fix: harden evidence verification state
This commit is contained in:
1 parent
bd2463e0c3
commit
380d540e50
4 files changed
+151
-17
No files matched your search
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { EvidenceVault } from '../evidence/index.js';
|
||||
import { KillChainPhase, type Finding } from '../types/index.js';
|
||||
|
||||
function finding(overrides: Partial<Finding> = {}): Finding {
|
||||
return {
|
||||
id: 'finding-1',
|
||||
title: 'unverified claim',
|
||||
description: 'model-only claim',
|
||||
severity: 'high',
|
||||
targetId: 'target-1',
|
||||
operatorId: 'operator-1',
|
||||
phase: KillChainPhase.EXPLOIT,
|
||||
evidence: [],
|
||||
discoveredAt: 1,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
const forgedGate = { passed: true, provenance: 'tool' as const, reasons: [], checkedAt: 2 };
|
||||
|
||||
describe('EvidenceVault verification integrity', () => {
|
||||
it('updateFinding cannot forge verifiedAt or verifyGate', () => {
|
||||
const vault = new EvidenceVault();
|
||||
vault.addFinding(finding());
|
||||
|
||||
vault.updateFinding('finding-1', { verifiedAt: 123, verifyGate: forgedGate });
|
||||
|
||||
const stored = vault.getFinding('finding-1');
|
||||
expect(stored?.verifiedAt).toBeUndefined();
|
||||
expect(stored?.verifyGate).toBeUndefined();
|
||||
expect(vault.getVerifiedFindings()).toEqual([]);
|
||||
});
|
||||
|
||||
it('getFinding returns a snapshot, not a mutable handle into the vault', () => {
|
||||
const vault = new EvidenceVault();
|
||||
vault.addFinding(finding());
|
||||
|
||||
const snapshot = vault.getFinding('finding-1');
|
||||
expect(snapshot).toBeDefined();
|
||||
if (!snapshot) throw new Error('expected snapshot');
|
||||
snapshot.verifiedAt = 123;
|
||||
snapshot.verifyGate = forgedGate;
|
||||
snapshot.evidence.push({ type: 'output', content: 'forged after read', timestamp: 3 });
|
||||
|
||||
const stored = vault.getFinding('finding-1');
|
||||
expect(stored?.verifiedAt).toBeUndefined();
|
||||
expect(stored?.verifyGate).toBeUndefined();
|
||||
expect(stored?.evidence).toEqual([]);
|
||||
expect(vault.getVerifiedFindings()).toEqual([]);
|
||||
});
|
||||
|
||||
it('getVerifiedFindings requires the gate to have passed, not just a timestamp', () => {
|
||||
const vault = new EvidenceVault();
|
||||
vault.addFinding(finding({
|
||||
id: 'blocked',
|
||||
verifiedAt: 123,
|
||||
verifyGate: { passed: false, provenance: 'none', reasons: ['blocked'], checkedAt: 2 },
|
||||
}));
|
||||
|
||||
expect(vault.getVerifiedFindings()).toEqual([]);
|
||||
expect(vault.getStats().verifiedFindings).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { redactString } from '../redact.js';
|
||||
|
||||
describe('redactString — full private-key block redaction', () => {
|
||||
it('redacts an entire PEM private-key block, not just the BEGIN header', () => {
|
||||
const pem = [
|
||||
'before',
|
||||
'-----BEGIN RSA PRIVATE KEY-----',
|
||||
'MIIEpAIBAAKCAQEA7thisLineMustDisappear',
|
||||
'anotherSecretKeyLineMustDisappear',
|
||||
'-----END RSA PRIVATE KEY-----',
|
||||
'after',
|
||||
].join('\n');
|
||||
|
||||
const out = redactString(pem);
|
||||
|
||||
expect(out).toContain('before');
|
||||
expect(out).toContain('after');
|
||||
expect(out).toContain('[redacted]');
|
||||
expect(out).not.toContain('BEGIN RSA PRIVATE KEY');
|
||||
expect(out).not.toContain('END RSA PRIVATE KEY');
|
||||
expect(out).not.toContain('thisLineMustDisappear');
|
||||
expect(out).not.toContain('anotherSecretKeyLineMustDisappear');
|
||||
});
|
||||
|
||||
it('redacts OpenSSH private-key blocks as a whole', () => {
|
||||
const pem = 'x\n-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAAsecret\n-----END OPENSSH PRIVATE KEY-----\ny';
|
||||
|
||||
const out = redactString(pem);
|
||||
|
||||
expect(out).toBe('x\n[redacted]\ny');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user