mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-21 20:30:47 +02:00
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
66 lines
2.4 KiB
TypeScript
66 lines
2.4 KiB
TypeScript
/**
|
|
* Regression tests for the 4 adversarial findings fixed during /ship:
|
|
*
|
|
* 1. Canary stream-chunk split bypass — rolling-buffer detection across
|
|
* consecutive text_delta / input_json_delta events.
|
|
* 2. Tool-output ensemble rule — single ML classifier >= BLOCK blocks
|
|
* directly when the content is tool output (not user input).
|
|
* 3. escapeHtml quote escaping (unit-level check on the shape we expect).
|
|
* 4. snapshot command added to PAGE_CONTENT_COMMANDS.
|
|
*
|
|
* These tests pin the fixes so future refactors don't silently re-open
|
|
* the bypasses both adversarial reviewers (Claude + Codex) flagged.
|
|
*/
|
|
import { describe, test, expect } from 'bun:test';
|
|
import { combineVerdict, THRESHOLDS } from '../src/security';
|
|
import { PAGE_CONTENT_COMMANDS } from '../src/commands';
|
|
|
|
describe('tool-output ensemble rule (single-layer BLOCK)', () => {
|
|
test('user-input context: single layer at BLOCK degrades to WARN', () => {
|
|
const result = combineVerdict([
|
|
{ layer: 'testsavant_content', confidence: 0.95 },
|
|
{ layer: 'transcript_classifier', confidence: 0 },
|
|
]);
|
|
expect(result.verdict).toBe('warn');
|
|
expect(result.reason).toBe('single_layer_high');
|
|
});
|
|
|
|
test('tool-output context: single layer at BLOCK blocks directly', () => {
|
|
const result = combineVerdict(
|
|
[
|
|
{ layer: 'testsavant_content', confidence: 0.95 },
|
|
{ layer: 'transcript_classifier', confidence: 0, meta: { degraded: true } },
|
|
],
|
|
{ toolOutput: true },
|
|
);
|
|
expect(result.verdict).toBe('block');
|
|
expect(result.reason).toBe('single_layer_tool_output');
|
|
});
|
|
|
|
test('tool-output context still respects ensemble path when 2 agree', () => {
|
|
const result = combineVerdict(
|
|
[
|
|
{ layer: 'testsavant_content', confidence: 0.80 },
|
|
{ layer: 'transcript_classifier', confidence: 0.75, meta: { verdict: 'block' } },
|
|
],
|
|
{ toolOutput: true },
|
|
);
|
|
expect(result.verdict).toBe('block');
|
|
expect(result.reason).toBe('ensemble_agreement');
|
|
});
|
|
|
|
test('tool-output context: below BLOCK threshold still WARN, not BLOCK', () => {
|
|
const result = combineVerdict(
|
|
[{ layer: 'testsavant_content', confidence: THRESHOLDS.WARN }],
|
|
{ toolOutput: true },
|
|
);
|
|
expect(result.verdict).toBe('warn');
|
|
});
|
|
});
|
|
|
|
describe('snapshot in PAGE_CONTENT_COMMANDS', () => {
|
|
test('snapshot is wrapped by untrusted-content envelope', () => {
|
|
expect(PAGE_CONTENT_COMMANDS.has('snapshot')).toBe(true);
|
|
});
|
|
});
|