Files
ci/src/agents/security-auditor.test.ts
T
Jon Chery 70f9f720e6 feat(P06): integration \u0026 hardening — version 0.8.0, agent tests, E2E, docs, fallbacks
---ci---
project: ci
phase: 6
milestone: v0.8
status: complete
decisions:
  - id: D-037
    decision: v0.8.0 release with 6 phases complete
    rationale: All verification layers now deliver what they claim
    confidence: 0.95
requirements:
  covered: [INT-01, INT-02, INT-03, INT-04, INT-05, INT-06, INT-07, INT-08]
---/ci---

INT-06: Version bumped to 0.8.0 in package.json and src/version.ts.

INT-07: New test suites for SecurityAuditorAgent (5 tests), DocWriterAgent
(5 tests), DebuggerAgent (5 tests), ChallengerAgent (4 tests).

INT-08: Zod validation test suite with 9 cases: valid input, missing
fields, path traversal, absolute paths, contradictory success+error,
invalid operation, negative tokens, fail+error, emptyBackendResult.

INT-04: ciagent review command now has mechanical fallback — runs
CodeReviewerAgent regex review without backend.

INT-05: ciagent debug command now has mechanical fallback — runs
DebuggerAgent stack trace parsing + git bisect without backend.

INT-01: E2E verification test — fixture with defects fails L3/L4; clean
project passes all 4 layers.

INT-02: AGENTS.md updated — removed 'not yet implemented' caveats for
L2/L3/L4; updated test count to 44 suites, 454 tests.

INT-03: PROJECT.md updated — removed Out of Scope for STRIDE,
multi-persona review, and behavioral test generation.
2026-05-29 20:46:44 +00:00

69 lines
2.4 KiB
TypeScript

import * as fs from "node:fs";
import * as path from "node:path";
import * as os from "node:os";
import { SecurityAuditorAgent } from "../agents/security-auditor.js";
describe("SecurityAuditorAgent", () => {
let tempDir: string;
beforeEach(() => {
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ciagent-sec-auditor-test-"));
});
afterEach(() => {
fs.rmSync(tempDir, { recursive: true, force: true });
});
it("finds hardcoded passwords via mechanical audit", () => {
const srcDir = path.join(tempDir, "src");
fs.mkdirSync(srcDir, { recursive: true });
fs.writeFileSync(path.join(srcDir, "config.ts"), 'const password = "secret123";');
const agent = new SecurityAuditorAgent();
const findings = agent.mechanicalAudit(tempDir);
expect(findings.length).toBeGreaterThan(0);
expect(findings[0].stride_category).toBe("information_disclosure");
expect(findings[0].cwe).toContain("CWE-");
expect(findings[0].severity).toBe("high");
});
it("finds empty catch blocks as repudiation", () => {
const srcDir = path.join(tempDir, "src");
fs.mkdirSync(srcDir, { recursive: true });
fs.writeFileSync(path.join(srcDir, "err.ts"), 'try { work(); } catch(e) {}');
const agent = new SecurityAuditorAgent();
const findings = agent.mechanicalAudit(tempDir);
const repudiation = findings.filter((f) => f.stride_category === "repudiation");
expect(repudiation.length).toBeGreaterThan(0);
});
it("returns empty findings for clean code", () => {
const srcDir = path.join(tempDir, "src");
fs.mkdirSync(srcDir, { recursive: true });
fs.writeFileSync(path.join(srcDir, "app.ts"), 'export function main() { return 1; }');
const agent = new SecurityAuditorAgent();
const findings = agent.mechanicalAudit(tempDir);
expect(findings).toHaveLength(0);
});
it("applies confidence-based disposition", () => {
const srcDir = path.join(tempDir, "src");
fs.mkdirSync(srcDir, { recursive: true });
fs.writeFileSync(path.join(srcDir, "api.ts"), 'const api_key = "abc123";');
const agent = new SecurityAuditorAgent(0.5);
const findings = agent.mechanicalAudit(tempDir);
expect(findings.some((f) => f.disposition === "flag")).toBe(true);
});
it("agent name is security-auditor", () => {
const agent = new SecurityAuditorAgent();
expect(agent.name).toBe("security-auditor");
});
});