feat(redact-prepush): per-address allowlist for pii.email (gstack.redact.allowEmail)

`git config --add gstack.redact.allowEmail <address>` allows that address for
MEDIUM pii.email findings only, so a team alias or support address that has
to be in the repo stops warning without reaching for --no-verify. It never
affects HIGH findings or any other rule, and the pii.email fix line names it.

Controls: a different address still reports, and a HIGH secret next to an
allowed address still blocks.

Plan item: DX-17.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-07 19:48:03 +00:00
1 parent e7a481a28d
commit d192d696e7
2 files changed
+35 -6

No files matched your search

+23
View File
@@ -163,6 +163,7 @@ describe("own and already-public addresses are not reported (#3060)", () => {
expect(lines).toHaveLength(1);
expect(lines[0]).toContain("pii.email");
expect(lines[0]).toContain("notes.md:3");
expect(lines[0]).toContain("git config --add gstack.redact.allowEmail <address>");
expect(stderr).not.toContain("stranger@corp.io");
});
@@ -302,6 +303,28 @@ describe("each input fails on its own (CEO-23, DX-9)", () => {
}
});
describe("per-address allowlist (DX-17)", () => {
test("an allowed address is not reported; a different address still is", () => {
const fx = fixture();
git(fx, fx.repo, ["config", "--add", "gstack.redact.allowEmail", "Team@corp.io"]);
commitFile(fx, fx.repo, "CONTACT.md", "team@corp.io\nother@corp.io\n");
const { code, stderr } = push(fx, ["origin", "main"]);
expect(code).toBe(0);
const found = mediumLines(stderr);
expect(found).toHaveLength(1);
expect(found[0]).toContain("CONTACT.md:2");
});
test("a HIGH secret next to an allowed address still blocks", () => {
const fx = fixture();
git(fx, fx.repo, ["config", "--add", "gstack.redact.allowEmail", "team@corp.io"]);
commitFile(fx, fx.repo, "deploy.env", `OWNER=team@corp.io\nkey ${AWS_KEY}\n`);
const { code, stderr } = push(fx, ["origin", "main"]);
expect(code).toBe(1);
expect(stderr).toContain("aws.access_key");
});
});
describe("MEDIUM lines point at the real file line (ENG-8)", () => {
test("separated hunks in one file report each hunk's own line", () => {
const fx = fixture();