refactor: keep legacy secretref migration in doctor

This commit is contained in:
Peter Steinberger
2026-05-03 13:10:00 +01:00
parent e0a83c0046
commit 0031ef3120
4 changed files with 6 additions and 73 deletions

View File

@@ -271,7 +271,7 @@ describe("normalizeCompatibilityConfigValues", () => {
);
});
it("leaves invalid legacy secretref-env markers for validation to reject", () => {
it("leaves invalid legacy secretref-env markers unchanged", () => {
const res = normalizeCompatibilityConfigValues({
messages: {
groupChat: {

View File

@@ -98,7 +98,7 @@ describe("config validation SecretRef policy guards", () => {
expect(result.ok).toBe(true);
});
it("rejects legacy secretref-env markers on supported SecretRef credential paths", () => {
it("leaves legacy secretref-env marker migration to doctor", () => {
const result = validateConfigObjectRaw({
secrets: {
defaults: {
@@ -112,21 +112,10 @@ describe("config validation SecretRef policy guards", () => {
},
});
expect(result.ok).toBe(false);
if (!result.ok) {
const issue = result.issues.find((entry) => entry.path === "channels.discord.token");
expect(issue).toBeDefined();
expect(issue?.message).toContain(
'"secretref-env:DISCORD_BOT_TOKEN" is a legacy SecretRef marker',
);
expect(issue?.message).toContain(
'{"source":"env","provider":"gateway-env","id":"DISCORD_BOT_TOKEN"}',
);
expect(issue?.message).toContain('Run "openclaw doctor --fix"');
}
expect(result.ok).toBe(true);
});
it("rejects invalid legacy secretref-env markers that doctor cannot migrate", () => {
it("does not reject invalid legacy secretref-env markers during raw validation", () => {
const result = validateConfigObjectRaw({
channels: {
discord: {
@@ -135,12 +124,7 @@ describe("config validation SecretRef policy guards", () => {
},
});
expect(result.ok).toBe(false);
if (!result.ok) {
const issue = result.issues.find((entry) => entry.path === "channels.discord.token");
expect(issue?.message).toContain('"secretref-env:not-valid" is a legacy SecretRef marker');
expect(issue?.message).toContain('{"source":"env","provider":"default","id":"ENV_VAR"}');
}
expect(result.ok).toBe(true);
});
it("replaces derived unrecognized-key errors with policy guidance for discord thread binding webhookToken", () => {

View File

@@ -19,7 +19,6 @@ import {
import { validateJsonSchemaValue } from "../plugins/schema-validator.js";
import { hasKind } from "../plugins/slots.js";
import { resolveWebSearchInstallCatalogEntries } from "../plugins/web-search-install-catalog.js";
import { collectLegacySecretRefEnvMarkerCandidates } from "../secrets/legacy-secretref-env-marker.js";
import { collectUnsupportedSecretRefConfigCandidates } from "../secrets/unsupported-surface-policy.js";
import {
hasAvatarUriScheme,
@@ -492,35 +491,7 @@ function mergeUnsupportedMutableSecretRefIssues(
}
export function collectUnsupportedSecretRefPolicyIssues(raw: unknown): ConfigValidationIssue[] {
return [
...collectUnsupportedMutableSecretRefIssues(raw),
...collectLegacySecretRefEnvMarkerIssues(raw),
];
}
function formatLegacySecretRefEnvMarkerMessage(candidate: {
value: string;
ref: { id: string; provider: string } | null;
}): string {
const replacement = candidate.ref
? JSON.stringify({ source: "env", provider: candidate.ref.provider, id: candidate.ref.id })
: '{"source":"env","provider":"default","id":"ENV_VAR"}';
return [
`${JSON.stringify(candidate.value)} is a legacy SecretRef marker and is not valid openclaw.json config.`,
`Use a structured SecretRef object instead, for example ${replacement}.`,
'Run "openclaw doctor --fix" to migrate valid secretref-env:<ENV_VAR> markers.',
`See ${SECRETREF_POLICY_DOC_URL}.`,
].join(" ");
}
function collectLegacySecretRefEnvMarkerIssues(raw: unknown): ConfigValidationIssue[] {
if (!isRecord(raw)) {
return [];
}
return collectLegacySecretRefEnvMarkerCandidates(raw as OpenClawConfig).map((candidate) => ({
path: candidate.path,
message: formatLegacySecretRefEnvMarkerMessage(candidate),
}));
return collectUnsupportedMutableSecretRefIssues(raw);
}
function mapZodIssueToConfigIssue(issue: unknown): ConfigValidationIssue {

View File

@@ -21,25 +21,6 @@ function isLegacySecretRefEnvMarker(value: unknown): value is string {
return typeof value === "string" && value.trim().startsWith(LEGACY_SECRETREF_ENV_MARKER_PREFIX);
}
function containsLegacySecretRefEnvMarker(value: unknown, seen = new WeakSet<object>()): boolean {
if (isLegacySecretRefEnvMarker(value)) {
return true;
}
if (!value || typeof value !== "object") {
return false;
}
if (seen.has(value)) {
return false;
}
seen.add(value);
if (Array.isArray(value)) {
return value.some((entry) => containsLegacySecretRefEnvMarker(entry, seen));
}
return Object.values(value as Record<string, unknown>).some((entry) =>
containsLegacySecretRefEnvMarker(entry, seen),
);
}
function toCandidate(
target: DiscoveredConfigSecretTarget,
defaults: NonNullable<OpenClawConfig["secrets"]>["defaults"] | undefined,
@@ -58,9 +39,6 @@ function toCandidate(
export function collectLegacySecretRefEnvMarkerCandidates(
config: OpenClawConfig,
): LegacySecretRefEnvMarkerCandidate[] {
if (!containsLegacySecretRefEnvMarker(config)) {
return [];
}
const defaults = config.secrets?.defaults;
return discoverConfigSecretTargets(config)
.map((target) => toCandidate(target, defaults))