mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:10:45 +00:00
fix(secrets): preserve auth profile key refs during provider scrub (#77489)
* fix(secrets): preserve auth profile key refs during provider scrub * Add changelog for secrets apply fix * Seed auth profile ref for scrub regression * fix(secrets): guard auth profile ref scrub --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -110,7 +110,8 @@ async function seedDefaultApplyFixture(fixture: ApplyFixture): Promise<void> {
|
||||
"openai:default": {
|
||||
type: "api_key",
|
||||
provider: "openai",
|
||||
key: "sk-openai-plaintext", // pragma: allowlist secret
|
||||
key: "sk-ope...text", // pragma: allowlist secret
|
||||
keyRef: OPENAI_API_KEY_ENV_REF,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -290,7 +291,11 @@ describe("secrets apply", () => {
|
||||
profiles: { "openai:default": { key?: string; keyRef?: unknown } };
|
||||
};
|
||||
expect(nextAuthStore.profiles["openai:default"].key).toBeUndefined();
|
||||
expect(nextAuthStore.profiles["openai:default"].keyRef).toBeUndefined();
|
||||
expect(nextAuthStore.profiles["openai:default"].keyRef).toEqual({
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "OPENAI_API_KEY",
|
||||
});
|
||||
|
||||
const nextAuthJson = JSON.parse(await fs.readFile(fixture.authJsonPath, "utf8")) as Record<
|
||||
string,
|
||||
@@ -303,6 +308,58 @@ describe("secrets apply", () => {
|
||||
expect(nextEnv).toContain("UNRELATED=value");
|
||||
});
|
||||
|
||||
it("preserves auth-profile tokenRef during provider scrub", async () => {
|
||||
await writeJsonFile(fixture.authStorePath, {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"openai:bot": {
|
||||
type: "token",
|
||||
provider: "openai",
|
||||
token: "sk-token-plaintext", // pragma: allowlist secret
|
||||
tokenRef: OPENAI_API_KEY_ENV_REF,
|
||||
},
|
||||
},
|
||||
});
|
||||
const plan = createPlan({
|
||||
targets: [createOpenAiProviderTarget()],
|
||||
options: createOneWayScrubOptions(),
|
||||
});
|
||||
|
||||
await runSecretsApply({ plan, env: fixture.env, write: true });
|
||||
|
||||
const nextAuthStore = JSON.parse(await fs.readFile(fixture.authStorePath, "utf8")) as {
|
||||
profiles: { "openai:bot": { token?: string; tokenRef?: unknown } };
|
||||
};
|
||||
expect(nextAuthStore.profiles["openai:bot"].token).toBeUndefined();
|
||||
expect(nextAuthStore.profiles["openai:bot"].tokenRef).toEqual(OPENAI_API_KEY_ENV_REF);
|
||||
});
|
||||
|
||||
it("scrubs malformed auth-profile ref residue during provider scrub", async () => {
|
||||
await writeJsonFile(fixture.authStorePath, {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"openai:default": {
|
||||
type: "api_key",
|
||||
provider: "openai",
|
||||
key: "sk-openai-plaintext", // pragma: allowlist secret
|
||||
keyRef: "secretref-managed", // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
});
|
||||
const plan = createPlan({
|
||||
targets: [createOpenAiProviderTarget()],
|
||||
options: createOneWayScrubOptions(),
|
||||
});
|
||||
|
||||
await runSecretsApply({ plan, env: fixture.env, write: true });
|
||||
|
||||
const nextAuthStore = JSON.parse(await fs.readFile(fixture.authStorePath, "utf8")) as {
|
||||
profiles: { "openai:default": { key?: string; keyRef?: unknown } };
|
||||
};
|
||||
expect(nextAuthStore.profiles["openai:default"].key).toBeUndefined();
|
||||
expect(nextAuthStore.profiles["openai:default"].keyRef).toBeUndefined();
|
||||
});
|
||||
|
||||
it("skips exec SecretRef checks during dry-run unless explicitly allowed", async () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
type OpenClawConfig,
|
||||
} from "../config/config.js";
|
||||
import type { ConfigWriteOptions } from "../config/io.js";
|
||||
import type { SecretProviderConfig } from "../config/types.secrets.js";
|
||||
import { coerceSecretRef, type SecretProviderConfig } from "../config/types.secrets.js";
|
||||
import { normalizeAgentId } from "../routing/session-key.js";
|
||||
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
||||
import { iterateAuthProfileCredentials } from "./auth-profiles-scan.js";
|
||||
@@ -411,7 +411,10 @@ function scrubAuthStoresForProviderTargets(params: {
|
||||
delete profile.profile[profile.valueField];
|
||||
mutated = true;
|
||||
}
|
||||
if (profile.refField in profile.profile) {
|
||||
if (
|
||||
profile.refField in profile.profile &&
|
||||
coerceSecretRef(profile.refValue, params.nextConfig.secrets?.defaults) === null
|
||||
) {
|
||||
delete profile.profile[profile.refField];
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user