fix: pre-landing review fixes

Review army findings (1 critical, auto-fixed with regression tests):

- CRITICAL (security specialist, verified live): redactFindingSpans spliced
  only the regex capture span, and pem.private_key / gcp.service_account
  capture just the BEGIN-header — the key body survived "redaction" and
  shipped via telemetry. Marker-only patterns now drop the whole payload
  (null, fail closed). Overlapping spans (Bearer+JWT on the same bytes) are
  coalesced before splicing so stale offsets can't leave partial secret
  bytes behind.
- gitStrict: drop the dead `|| r.status === null` disjunct (null !== 0
  already covers it); add the signal-kill/null-status regression test the
  docstring promised.
- security-dashboard human mode flags stale snapshots ("figures may be out
  of date") instead of presenting frozen counts as current.
- community-dashboard marker check uses jq when available — the grep-only
  variant misclassified whitespaced/reserialized bodies as legacy.
- telemetry fail-closed test now shadows bun with a failing stub
  (deterministic on any host layout); stale "five status cases" describe
  title renamed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-06-11 23:31:26 -07:00
co-authored by Claude Fable 5
parent 88ca684929
commit 8c8e3b9e52
9 changed files with 155 additions and 17 deletions
+1 -1
View File
@@ -174,7 +174,7 @@ function applyEnv(env: FakeEnv): () => void {
};
}
describe("lib/gbrain-local-status — five status cases", () => {
describe("lib/gbrain-local-status — status classification", () => {
let env: FakeEnv | null = null;
let restoreEnv: (() => void) | null = null;
+30
View File
@@ -409,6 +409,36 @@ describe("redactFindingSpans — machine-egress masking (#1947)", () => {
});
expect(out).toBe("line one\nline two has <REDACTED-github.pat>\nline three");
});
// Pre-landing review CRITICAL: pem.private_key and gcp.service_account
// capture only the HEADER, not the key material — a span splice would
// redact the marker and forward the key body. Marker-only patterns must
// drop the whole payload.
test("PEM private key → null (header-only span must not forward the key body)", () => {
const msg =
"deploy failed: -----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASC\n-----END PRIVATE KEY-----";
expect(redactFindingSpans(msg, { repoVisibility: "private" })).toBeNull();
});
test("GCP service-account JSON → null (key body follows the captured marker)", () => {
const msg =
'config dump: {"private_key_id": "abc123", "private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBg..."}';
expect(redactFindingSpans(msg, { repoVisibility: "private" })).toBeNull();
});
// Pre-landing review: overlapping spans (a Bearer token that is also a
// JWT) must coalesce — independent splices apply stale offsets and can
// leave trailing secret bytes or mangled markers.
test("overlapping spans (Bearer JWT fires auth.bearer + jwt) never leak and produce clean markers", () => {
const jwt = "eyJ" + "a".repeat(20) + ".eyJ" + "b".repeat(20) + "." + "c".repeat(20);
const out = redactFindingSpans(`Authorization: Bearer ${jwt}`, { repoVisibility: "private" });
expect(out).not.toBeNull();
expect(out!).not.toContain("eyJ");
expect(out!).not.toContain("aaaa");
expect(out!).not.toContain("cccc");
// One coalesced, well-formed marker — no truncated fragments.
expect(out!).toMatch(/^Authorization: Bearer <REDACTED-[a-z._+]+>$/);
});
});
describe("taxonomy integrity", () => {
+25
View File
@@ -127,6 +127,31 @@ describe("fail closed on unscannable diffs (#1946)", () => {
const { code } = runHook(`refs/heads/main ${head} refs/heads/main ${head}\n`);
expect(code).toBe(0);
});
test("a diff killed by a signal (null status — the maxBuffer/kill class) BLOCKS", () => {
// Stub git: probes delegate to the real git; the diff invocation kills
// itself, producing spawnSync status === null. This is the exact branch
// gitStrict's docstring names (oversized-diff overflow is delivered the
// same way) — pre-landing review flagged it as untested.
const realGit = Bun.which("git") || "/usr/bin/git";
const stubDir = fs.mkdtempSync(path.join(os.tmpdir(), "prepush-stubgit-"));
try {
const stub = `#!/bin/sh\nif [ "$1" = "diff" ]; then kill -KILL $$; fi\nexec "${realGit}" "$@"\n`;
fs.writeFileSync(path.join(stubDir, "git"), stub);
fs.chmodSync(path.join(stubDir, "git"), 0o755);
const base = git(["rev-parse", "HEAD"]);
const head = commit("clean.txt", "clean content\n", "clean commit");
const { code, stderr } = runHook(`refs/heads/main ${head} refs/heads/main ${base}\n`, {
PATH: `${stubDir}:${process.env.PATH}`,
});
expect(code).toBe(1);
expect(stderr).toContain("could not compute the pushed diff");
expect(stderr).toContain("GSTACK_REDACT_PREPUSH=skip");
} finally {
fs.rmSync(stubDir, { recursive: true, force: true });
}
});
});
describe("install UX surfaces (#1946 / eng review D3+D10)", () => {
+16
View File
@@ -182,6 +182,13 @@ describe("gstack-security-dashboard — never reports fake zeros (#1947)", () =>
expect(parsed.stale).toBe(true);
});
it("stale snapshot is flagged in human mode too — frozen figures never read as current", () => {
const staleBody = JSON.stringify({ ...JSON.parse(GOOD_BODY_MARKER), stale: true });
const r = run(SEC_BIN, { mode: "ok", body: staleBody });
expect(r.stdout).toContain("Attacks detected last 7 days: 3");
expect(r.stdout).toContain("stale snapshot");
});
it("200 without marker (legacy backend) → figures shown with unverified note", () => {
const r = run(SEC_BIN, { mode: "ok", body: GOOD_BODY_LEGACY });
expect(r.stdout).toContain("Attacks detected last 7 days: 3");
@@ -238,4 +245,13 @@ describe("gstack-community-dashboard — never reports fake zeros (#1947)", () =
expect(r.stdout).toContain("unknown — backend error (HTTP 200)");
expect(r.stdout).not.toContain("Weekly active installs:");
});
it("whitespaced marker ('\"status\": \"ok\"') still classified as verified when jq is present", () => {
// Pre-landing review: the grep-only marker check was whitespace-sensitive;
// a proxy-reserialized body must not be misclassified as legacy.
const spaced = GOOD_BODY_MARKER.replace('"status":"ok"', '"status": "ok"');
const r = run(COMM_BIN, { mode: "ok", body: spaced });
expect(r.stdout).toContain("Weekly active installs: 42");
expect(r.stdout).not.toContain("unverified");
});
});
+30 -6
View File
@@ -222,12 +222,21 @@ describe('gstack-telemetry-log', () => {
test('fails closed: error_message becomes null when the redactor is unavailable (#1947)', () => {
setConfig('telemetry', 'anonymous');
const token = 'ghp_' + 'A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8';
// PATH without bun: the redaction snippet cannot run, so the whole
// message must drop — never raw passthrough.
run(
`${BIN}/gstack-telemetry-log --skill qa --duration 10 --outcome error --error-message 'auth ${token} rejected' --session-id red-2`,
{ PATH: '/usr/bin:/bin' },
);
// Shadow bun with a failing stub on a prepended PATH (deterministic on
// any host layout — pre-landing review flagged the bare '/usr/bin:/bin'
// variant as environment-dependent): the redaction snippet cannot run,
// so the whole message must drop — never raw passthrough.
const stubBin = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-tel-nobun-'));
try {
fs.writeFileSync(path.join(stubBin, 'bun'), '#!/bin/sh\nexit 127\n');
fs.chmodSync(path.join(stubBin, 'bun'), 0o755);
run(
`${BIN}/gstack-telemetry-log --skill qa --duration 10 --outcome error --error-message 'auth ${token} rejected' --session-id red-2`,
{ PATH: `${stubBin}:${process.env.PATH}` },
);
} finally {
fs.rmSync(stubBin, { recursive: true, force: true });
}
const lines = readJsonl();
expect(lines).toHaveLength(1);
@@ -236,6 +245,21 @@ describe('gstack-telemetry-log', () => {
expect(lines[0]).not.toContain(token);
});
test('fails closed: PEM key in error_message drops the whole message (#1947 review fix)', () => {
setConfig('telemetry', 'anonymous');
// Header-only pattern: span replacement would forward the key body, so
// the engine returns null and the bin must store null.
run(
`${BIN}/gstack-telemetry-log --skill qa --duration 10 --outcome error --error-message 'deploy failed: -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASC' --session-id red-5`,
);
const lines = readJsonl();
expect(lines).toHaveLength(1);
const event = JSON.parse(lines[0]);
expect(event.error_message).toBeNull();
expect(lines[0]).not.toContain('MIIEvQIBADAN');
});
test('truncates error_message to 200 chars after redaction (#1947)', () => {
setConfig('telemetry', 'anonymous');
const long = 'x'.repeat(300);