Redact existing placeholder keys without secrets
This commit is contained in:
@@ -2,12 +2,12 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [16.0.5] - 2026-06-17
|
||||
|
||||
### Added
|
||||
|
||||
- Added `friendlyName` support for hidden secrets so model-visible placeholders can carry sanitized semantic labels, content-derived hashes, and case hints while preserving exact deobfuscation ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)).
|
||||
|
||||
## [16.0.5] - 2026-06-17
|
||||
|
||||
### Added
|
||||
|
||||
- Added `tui.tight` setting (default `false`) to enable tight layout by removing the 1-character horizontal padding from terminal output.
|
||||
|
||||
@@ -1222,17 +1222,22 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
const fileEntries = await logger.time("loadSecrets", loadSecrets, cwd, agentDir);
|
||||
const envEntries = collectEnvSecrets();
|
||||
const allEntries = [...envEntries, ...fileEntries];
|
||||
const needsPlaceholderKey = allEntries.some(entry => (entry.mode ?? "obfuscate") === "obfuscate");
|
||||
const placeholderKey = needsPlaceholderKey
|
||||
? await getSecretPlaceholderKey()
|
||||
: await getExistingSecretPlaceholderKey();
|
||||
if (allEntries.length > 0) {
|
||||
// The persisted placeholder key — and creating its key file under the
|
||||
// config root — is only needed for reversible obfuscate-mode placeholders.
|
||||
// Replace-mode entries never build a keyed base, so a replace-only secrets
|
||||
// set must not require the key; otherwise a headless run with an unwritable
|
||||
// config root fails startup for a feature it does not use.
|
||||
const needsPlaceholderKey = allEntries.some(entry => (entry.mode ?? "obfuscate") === "obfuscate");
|
||||
const placeholderKey = needsPlaceholderKey
|
||||
? await getSecretPlaceholderKey()
|
||||
: await getExistingSecretPlaceholderKey();
|
||||
obfuscator = new SecretObfuscator(allEntries, placeholderKey);
|
||||
} else if (placeholderKey !== undefined) {
|
||||
obfuscator = new SecretObfuscator(
|
||||
[{ type: "plain", mode: "replace", content: placeholderKey }],
|
||||
placeholderKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
const secretsEnabled = obfuscator?.hasSecrets() === true;
|
||||
|
||||
@@ -170,11 +170,18 @@ describe("createAgentSession session storage isolation", () => {
|
||||
enableLsp: false,
|
||||
};
|
||||
|
||||
const withoutSecrets = await createAgentSession(commonOptions);
|
||||
const existingKeySpy = spyOn(secrets, "getExistingSecretPlaceholderKey").mockImplementation(
|
||||
async () => undefined,
|
||||
);
|
||||
try {
|
||||
expect(withoutSecrets.session.systemPrompt.join("\n")).not.toContain(redactionGuidance);
|
||||
const withoutSecrets = await createAgentSession(commonOptions);
|
||||
try {
|
||||
expect(withoutSecrets.session.systemPrompt.join("\n")).not.toContain(redactionGuidance);
|
||||
} finally {
|
||||
await withoutSecrets.session.dispose();
|
||||
}
|
||||
} finally {
|
||||
await withoutSecrets.session.dispose();
|
||||
existingKeySpy.mockRestore();
|
||||
}
|
||||
|
||||
fs.mkdirSync(path.join(cwd, ".omp"), { recursive: true });
|
||||
@@ -258,7 +265,7 @@ describe("createAgentSession session storage isolation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("requests the placeholder key only when an obfuscate-mode secret is configured", async () => {
|
||||
it("creates the placeholder key only when an obfuscate-mode secret is configured", async () => {
|
||||
await withClearedSecretEnv(async () => {
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `pi-sdk-secrets-key-${Snowflake.next()}-`));
|
||||
tempDirs.push(tempDir);
|
||||
@@ -287,6 +294,18 @@ describe("createAgentSession session storage isolation", () => {
|
||||
async () => "existing-placeholder-key",
|
||||
);
|
||||
try {
|
||||
const keyOnly = await createAgentSession(commonOptions);
|
||||
try {
|
||||
expect(keySpy).not.toHaveBeenCalled();
|
||||
expect(existingKeySpy).toHaveBeenCalled();
|
||||
expect(keyOnly.session.obfuscator?.obfuscate("existing-placeholder-key")).not.toContain(
|
||||
"existing-placeholder-key",
|
||||
);
|
||||
} finally {
|
||||
await keyOnly.session.dispose();
|
||||
}
|
||||
|
||||
existingKeySpy.mockClear();
|
||||
// Replace-mode secrets never build a reversible keyed placeholder, so
|
||||
// startup must not create the key file; an existing key is still redacted.
|
||||
fs.writeFileSync(
|
||||
|
||||
Reference in New Issue
Block a user