mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
fix(redact): pii.email reports a file named after an address
looksLikeAtFilename exempted any span whose domain ended in a non-TLD extension, so an address inside a filename (an export named after the address plus .json) went unreported. Strip the trailing extension run and exempt only when what precedes it cannot be a domain (one dotless label or a dotted version). The dotted-version branch now requires an extension that doubles as a TLD, so an address at an all-digit subdomain still reports. Regression rows pin both. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
0ff98dba1f
commit
566641d44f
2 files changed
+24
-13
No files matched your search
+16
-10
@@ -475,23 +475,29 @@ export function isDotenvFilename(match: RegExpExecArray): boolean {
|
||||
return spanStart > 0 && input[spanStart - 1] === ".";
|
||||
}
|
||||
|
||||
/** File extensions that are not top-level domains (checked against the IANA
|
||||
* root zone list, 2026-10-28). Extensions that are also TLDs (`.md`, `.py`,
|
||||
* `.sh`, `.rs`, `.so`, `.zip`, `.mov`, `.map`) are left out on purpose. */
|
||||
const NON_TLD_EXTENSION = /\.(?:json|jsonc|jsonl|ndjson|ya?ml|toml|lock|txt|csv|tsv|log|ini|cfg|conf|xml|html?|[mc]?js|jsx|tsx?|tgz|gz|tar|bz2|xz|zst|whl|jar|gem|nupkg|deb|rpm|wasm|svg|png|jpe?g|pdf|patch|diff)$/i;
|
||||
/** A trailing run of file extensions that are not top-level domains (checked
|
||||
* against the IANA root zone list, 2026-10-28). Extensions that are also TLDs
|
||||
* (`.md`, `.py`, `.sh`, `.rs`, `.so`, `.zip`, `.mov`, `.map`) are left out on
|
||||
* purpose. */
|
||||
const NON_TLD_EXTENSIONS = /(?:\.(?:json|jsonc|jsonl|ndjson|ya?ml|toml|lock|txt|csv|tsv|log|ini|cfg|conf|xml|html?|[mc]?js|jsx|tsx?|tgz|gz|tar|bz2|xz|zst|whl|jar|gem|nupkg|deb|rpm|wasm|svg|png|jpe?g|pdf|patch|diff))+$/i;
|
||||
|
||||
/**
|
||||
* True when a pii.email span is a filename with an `@` in it rather than an
|
||||
* address: `terminal-bench@2.0.json`, `lodash@4.17.21.tgz`,
|
||||
* `eslint-config@next.yaml`. The package@version convention puts a version
|
||||
* after the `@`, so either sign decides: the "domain" ends in a file extension
|
||||
* no TLD uses, or it is a dotted version (two or more all-digit labels) with
|
||||
* one label after it. `user@163.com` (one numeric label) and an address at a
|
||||
* TLD that doubles as an extension (`dev@acme.sh`, `ops@acme.md`) still report.
|
||||
* `eslint-config@next.yaml`. The package@version convention puts a version or
|
||||
* tag after the `@`, so either sign decides: the "domain" ends in file
|
||||
* extensions no TLD uses and what precedes them cannot be a domain (one dotless
|
||||
* label or a dotted version), or it is a dotted version (two or more all-digit
|
||||
* labels) followed by an extension that doubles as a TLD (`a@1.2.md`). A file
|
||||
* named after an address (`jane@acme.com.json`), `user@163.com`,
|
||||
* `alice@1.2.com` and an address at a TLD that doubles as an extension
|
||||
* (`dev@acme.sh`, `ops@acme.md`) still report.
|
||||
*/
|
||||
export function looksLikeAtFilename(span: string): boolean {
|
||||
const domain = span.slice(span.lastIndexOf("@") + 1);
|
||||
return NON_TLD_EXTENSION.test(domain) || /^\d+(?:\.\d+)+\.[A-Za-z]{2,}$/.test(domain);
|
||||
const stem = domain.replace(NON_TLD_EXTENSIONS, "");
|
||||
if (stem !== domain) return !/\.[A-Za-z]{2,}$/.test(stem);
|
||||
return /^\d+(?:\.\d+)+\.(?:md|py|sh|rs|so|zip|mov|map)$/i.test(domain);
|
||||
}
|
||||
|
||||
/** Extensions that mark a `<name>.local.<ext>` span as a file. Closed on
|
||||
|
||||
@@ -73,9 +73,9 @@ describe("pii.email and package@version filenames", () => {
|
||||
expect(looksLikeAtFilename("terminal-bench@2.0.json")).toBe(true);
|
||||
});
|
||||
|
||||
// Value: protects=real addresses still report, including a numeric domain label (163.com) and TLDs that double as file extensions (.sh, .md, .py,
|
||||
// .zip); fails_when=the guard treats any digit label or any extension-like TLD as a filename; why_new=pins the narrowness of the new guard;
|
||||
// seam=none (scan); no_claim=every IANA TLD
|
||||
// Value: protects=real addresses still report, including numeric domain labels (163.com, 1.2.com), TLDs that double as file extensions (.sh, .md,
|
||||
// .py, .zip) and a file named after an address; fails_when=the guard treats any digit label, any extension-like TLD or any trailing extension as a
|
||||
// filename; why_new=pins the narrowness of the new guard; seam=none (scan); no_claim=every IANA TLD
|
||||
test("real addresses still report, numeric domains and extension-shaped TLDs included", () => {
|
||||
for (const s of [
|
||||
"mail alex@acme-corp.com",
|
||||
@@ -85,6 +85,11 @@ describe("pii.email and package@version filenames", () => {
|
||||
"py team@acme.py",
|
||||
"files sales@acme.zip",
|
||||
"contact jo@mail.acme.io",
|
||||
"reach alice@1.2.com",
|
||||
"export jane.doe@acme-corp.com.json",
|
||||
"log at ops-team@acme.io.log",
|
||||
"uploaded jdoe@acme-corp.com.PDF",
|
||||
"archive li.wei@163.com.tar.gz",
|
||||
]) {
|
||||
expect([s, flags("pii.email", s)]).toEqual([s, true]);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user