mirror of https://github.com/garrytan/gstack.git
fix(safety): unknown question-preference source exits the documented 2, not 1
The --write user-origin gate documents exit 2 as "rejected, do not retry" (profile poisoning defense), but a source outside both the allowed and the explicitly-rejected lists fell through to exit 1 — the generic validation code callers treat as retryable. Unknown sources now exit 2 with the same do-not-retry rejection message as the known non-user-originated ones. Closes #2390. Contributed by @gregario (PR #2429). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
65b577f133
commit
85ab953cc9
|
|
@ -174,8 +174,8 @@ do_write() {
|
|||
process.exit(2);
|
||||
}
|
||||
if (!ALLOWED_SOURCES.includes(j.source)) {
|
||||
process.stderr.write('gstack-question-preference: invalid source \"' + j.source + '\"; allowed: ' + ALLOWED_SOURCES.join(', ') + '\n');
|
||||
process.exit(1);
|
||||
process.stderr.write('gstack-question-preference: rejected — source \"' + j.source + '\" is not user-originated (profile poisoning defense)\n');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// Optional free_text — sanitize (no injection patterns, no newlines, <=300 chars)
|
||||
|
|
|
|||
|
|
@ -338,8 +338,16 @@ describe('--write user-origin gate (profile-poisoning defense)', () => {
|
|||
'--write',
|
||||
JSON.stringify({ question_id: 'q1', preference: 'never-ask', source: 'anonymous' }),
|
||||
);
|
||||
expect(r.status).not.toBe(0);
|
||||
expect(r.stderr).toContain('invalid source');
|
||||
expect(r.status).toBe(2);
|
||||
expect(r.stderr).toContain('profile poisoning defense');
|
||||
});
|
||||
|
||||
test('unknown source exits 2 (user-origin rejection), not 1 (validation error)', () => {
|
||||
const r = run(
|
||||
'--write',
|
||||
JSON.stringify({ question_id: 'q1', preference: 'never-ask', source: 'tool-output' }),
|
||||
);
|
||||
expect(r.status).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue