Problem
A filename-word denylist silently excludes files from the graph. It matches on the name only —
the content is never inspected — so design-system files called tokens.css / tokens.contract.json
are treated as credentials and dropped.
Discovered on a monorepo whose design tokens are generated artifacts with fixed names: the generated
tokens.css and the committed tokens.contract.json were both absent from the graph, announced by a
single line:
[graphify extract] 1 file(s) skipped as potentially sensitive (rename or move if wrongly flagged): tokens.css
Repro (deterministic on 0.9.34)
mkdir case && cd case
for n in tokens token mytokens design-tokens palette secrets credentials; do
echo ':root{ --a: #fff; }' > "$n.css"
done
echo 'def f(): return 1' > tokens.py
echo '{"a":1}' > tokens.json
echo '{"a":1}' > plain.json
graphify extract . --code-only --no-cluster --out /tmp/out --force
[graphify extract] found 2 code, 0 docs, 0 papers, 0 images
[graphify extract] 2 file(s) not classified (no supported extension or shebang), skipped: mytokens.css, palette.css
[graphify extract] 6 file(s) skipped as potentially sensitive (rename or move if wrongly flagged):
credentials.css, design-tokens.css, secrets.css, token.css, tokens.css, tokens.json
The rule, as observed
| file |
outcome |
tokens.css, token.css, design-tokens.css, secrets.css, credentials.css, tokens.json |
skipped as sensitive |
mytokens.css, palette.css |
not matched |
tokens.py |
not matched |
plain.json |
indexed |
Three properties, all of which look unintended:
- Content is never read. An empty file named
token.css is skipped; a file named palette.css
containing a real API key is not. The check cannot do what its message claims.
- The match is word-boundary aware, which makes it worse, not better.
design-tokens matches
(separator-delimited word tokens), mytokens does not. So the more conventionally named a
design-token file is, the more likely it is to be dropped.
- It is extension-dependent.
tokens.py survives; tokens.css and tokens.json do not. Same
word, same content-blindness, different outcome. (Also note .css is not a supported code
extension at all — palette.css came back "not classified" — yet tokens.css still went down the
sensitive path, so the check runs ahead of classification.)
Why the suggested remedy does not work
The warning says "rename or move if wrongly flagged". For a generated artifact that is not
available: the name is fixed by the generator and asserted by a drift guard in CI. Renaming it to
please a scanner would break the build that produces it. In a design-system repo, tokens.* is close
to the single most likely filename to exist.
Suggested fix
Any of these would resolve it; roughly in order of preference:
- Inspect content. Gate the skip on an actual secret-shaped match (high-entropy string, known key
prefixes, PRIVATE KEY armor). A :root{} block of hex colours is not that.
- Drop
token from the name denylist, or require it to co-occur with a content signal.
secret/credential/password are far less ambiguous than token, which is ordinary vocabulary
in design systems, tokenizers, parsers and lexers.
- Make it overridable — honour a
.graphifyignore-style allowlist, or add
--no-sensitive-filter. Today there is no flag to opt out; I checked --help.
- Raise the reporting. One line in the middle of extraction output is easy to miss for a file
that then simply does not exist in the graph. If a file is excluded, it is worth being loud.
Happy to send a PR for (1) or (3) if you have a preference on shape.
Environment
graphifyy 0.9.34, macOS (darwin 25.5.0), Python 3.12, --code-only (no LLM backend involved).
Problem
A filename-word denylist silently excludes files from the graph. It matches on the name only —
the content is never inspected — so design-system files called
tokens.css/tokens.contract.jsonare treated as credentials and dropped.
Discovered on a monorepo whose design tokens are generated artifacts with fixed names: the generated
tokens.cssand the committedtokens.contract.jsonwere both absent from the graph, announced by asingle line:
Repro (deterministic on 0.9.34)
The rule, as observed
tokens.css,token.css,design-tokens.css,secrets.css,credentials.css,tokens.jsonmytokens.css,palette.csstokens.pyplain.jsonThree properties, all of which look unintended:
token.cssis skipped; a file namedpalette.csscontaining a real API key is not. The check cannot do what its message claims.
design-tokensmatches(separator-delimited word
tokens),mytokensdoes not. So the more conventionally named adesign-token file is, the more likely it is to be dropped.
tokens.pysurvives;tokens.cssandtokens.jsondo not. Sameword, same content-blindness, different outcome. (Also note
.cssis not a supported codeextension at all —
palette.csscame back "not classified" — yettokens.cssstill went down thesensitive path, so the check runs ahead of classification.)
Why the suggested remedy does not work
The warning says "rename or move if wrongly flagged". For a generated artifact that is not
available: the name is fixed by the generator and asserted by a drift guard in CI. Renaming it to
please a scanner would break the build that produces it. In a design-system repo,
tokens.*is closeto the single most likely filename to exist.
Suggested fix
Any of these would resolve it; roughly in order of preference:
prefixes,
PRIVATE KEYarmor). A:root{}block of hex colours is not that.tokenfrom the name denylist, or require it to co-occur with a content signal.secret/credential/passwordare far less ambiguous thantoken, which is ordinary vocabularyin design systems, tokenizers, parsers and lexers.
.graphifyignore-style allowlist, or add--no-sensitive-filter. Today there is no flag to opt out; I checked--help.that then simply does not exist in the graph. If a file is excluded, it is worth being loud.
Happy to send a PR for (1) or (3) if you have a preference on shape.
Environment
graphifyy0.9.34, macOS (darwin 25.5.0), Python 3.12,--code-only(no LLM backend involved).