Files
gstack/test/redact-doc-resolver.test.ts
T
garrytan a5c5162d33 test(W7c): match redact scan-at-sink exact-bytes rule case-insensitively
W7c conversion (t02 #13). Credential-handling checks (mktemp, --from-file,
exit codes 3/2/0, visibility lookups, no HIGH skip flag) are unchanged.

Removed assertion group (invariant -> remaining protection):
- /EXACT bytes/ (caps): scan the exact bytes that will be sent -> kept free:
  /exact bytes/i in the same test, next to the mktemp and --from-file checks.

Mutation pass (scratch worktree, scripts/resolvers/redact-doc.ts): 3/3 as
expected; scanning a summary instead of the exact bytes or dropping the
Exit 3 (HIGH) branch goes red; lowering EXACT stays green. Log:
.context/mutation-redact-doc-resolver.md.
2026-10-03 01:17:49 +00:00

70 lines
2.6 KiB
TypeScript

/**
* redact-doc resolver tests (T3/T16). The taxonomy table is generated from
* lib/redact-patterns (single source of truth) and must contain every pattern
* id + the recognizable credential prefixes. The invocation block must encode
* the scan-at-sink contract (temp file → scan → same file), the exit-code
* branches, the which-bun probe, and the guardrail framing.
*/
import { describe, test, expect } from "bun:test";
import {
generateRedactInvocationBlock,
} from "../scripts/resolvers/redact-doc";
import { HOST_PATHS } from "../scripts/resolvers/types";
import { PATTERNS } from "../lib/redact-patterns";
const ctx = {
skillName: "spec",
tmplPath: "",
host: "claude" as const,
paths: HOST_PATHS["claude"],
};
describe("REDACT_INVOCATION_BLOCK", () => {
test("scan-at-sink: temp file → scan that file → exact bytes", () => {
const block = generateRedactInvocationBlock(ctx, ["pre-issue"]);
expect(block).toContain("mktemp");
expect(block).toContain("--from-file");
expect(block).toMatch(/exact bytes/i);
});
test("encodes exit-code branches 3/2/0", () => {
const block = generateRedactInvocationBlock(ctx, ["pre-codex"]);
expect(block).toContain("Exit 3 (HIGH)");
expect(block).toContain("Exit 2 (MEDIUM)");
expect(block).toContain("Exit 0 (clean)");
});
test("resolves visibility config → gh → glab → unknown", () => {
const block = generateRedactInvocationBlock(ctx, ["pre-issue"]);
expect(block).toContain("redact_repo_visibility");
expect(block).toContain("gh repo view --json visibility");
expect(block).toContain("glab repo view");
});
test("includes a which-bun probe", () => {
expect(generateRedactInvocationBlock(ctx, ["pre-issue"])).toContain("command -v bun");
});
test("HIGH has no skip flag; framed as guardrail not enforcement", () => {
const block = generateRedactInvocationBlock(ctx, ["pre-issue"]);
expect(block).toMatch(/no skip flag for HIGH/i);
expect(block).toMatch(/guardrail, not airtight enforcement/i);
});
test("PII subset offers auto-redact; non-PII MEDIUM does not", () => {
const block = generateRedactInvocationBlock(ctx, ["pre-pr-body"]);
expect(block).toContain("--auto-redact");
expect(block).toContain("Proceed (acknowledged)");
});
test("sink label drives the prose noun/verb", () => {
expect(generateRedactInvocationBlock(ctx, ["pre-commit"])).toContain("commit");
expect(generateRedactInvocationBlock(ctx, ["pre-pr-title"])).toContain("PR title");
});
test("unknown sink label falls back without throwing", () => {
expect(() => generateRedactInvocationBlock(ctx, ["bogus-sink"])).not.toThrow();
});
});