Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/runtime/protect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,10 @@ function isAgentGuardStatusResult(action: RuntimeAction): boolean {

function isSafelyMaskedAgentGuardStatusOutput(output: unknown): boolean {
const serialized = typeof output === 'string' ? output : JSON.stringify(output);
return redactText(serialized) === serialized;
// The status help intentionally prints this literal placeholder. Normalize only
// that documented value so real keys and unrelated sensitive output stay strict.
const normalized = serialized.replaceAll('TYPESAFE_API_KEY=<key>', 'TYPESAFE_API_KEY=[REDACTED]');
return redactText(normalized) === normalized;
}

function isAgentGuardApprovalCommand(action: RuntimeAction): boolean {
Expand Down
37 changes: 37 additions & 0 deletions src/tests/codex-hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,29 @@ describe('installed Codex native hooks', () => {
assert.equal(existsSync(join(fixture.home, 'audit.jsonl')), false);
});

it('does not block the real status output when it contains documented key placeholders', () => {
const fixture = installFixture();
const status = fixture.runCli('status');
assert.equal(status.status, 0);
assert.match(status.stdout, /TYPESAFE_API_KEY=<key>/);

const run = fixture.run('agentguard-post-tool.sh', {
hook_event_name: 'PostToolUse',
session_id: 'sess_real_status',
turn_id: 'turn_real_status',
cwd: fixture.project,
tool_name: 'functions.exec_command',
tool_use_id: 'tool_real_status',
tool_input: { cmd: 'agentguard status' },
tool_response: { output: status.stdout, exit_code: status.status },
});

assert.equal(run.status, 0);
assert.equal(run.stdout.trim(), '');
assert.equal(run.stderr.trim(), '');
assert.equal(existsSync(join(fixture.home, 'audit.jsonl')), false);
});

it('still blocks an unexpectedly unmasked secret in agentguard status output', () => {
const fixture = installFixture();
const run = fixture.run('agentguard-post-tool.sh', {
Expand Down Expand Up @@ -466,6 +489,7 @@ function installFixture(): {
home: string;
run: (script: string, event: unknown) => HookRun;
runRaw: (script: string, input: string) => HookRun;
runCli: (...args: string[]) => HookRun;
} {
const project = mkdtempSync(join(tmpdir(), 'agentguard-codex-hooks-'));
const home = mkdtempSync(join(tmpdir(), 'agentguard-codex-home-'));
Expand Down Expand Up @@ -494,6 +518,19 @@ function installFixture(): {
home,
run: (script, event) => runRaw(script, JSON.stringify(event)),
runRaw,
runCli: (...args) => {
const result = spawnSync(shim, args, {
cwd: project,
encoding: 'utf8',
env: {
...process.env,
PATH: `${bin}:${process.env.PATH || ''}`,
AGENTGUARD_HOME: home,
TYPESAFE_API_KEY: '',
},
});
return { status: result.status, stdout: result.stdout, stderr: result.stderr };
},
};
}

Expand Down
Loading