Documentation
¶
Overview ¶
Package namematch decides one question, in one place: does this IDENTIFIER NAME denote a secret?
It is a leaf. It imports no codefit package and nothing outside the standard library, because three unrelated consumers depend on it and any one of them pulling the others in through it would break the core's layering:
SEC-001 (Go provider) -> MatchSet(name, Credential()) SEC-050 (Go provider) -> MatchSet(name, SecurityValue()) DB-053 / DB-020 (core) -> MatchSet(name, DB053Union())
The MATCHER is shared. The VOCABULARIES are not, and that separation is load-bearing rather than tidy:
- a personal identifier (ssn, cvv) is not a credential, so SEC-001 — which affirms "this looks like a hardcoded credential" at Confidence 1.0 — must not consume DB-053's PII names;
- crypto material (nonce, salt, iv) is not a credential either, so SEC-050 keeps its own set;
- DB-053's vocabulary is frozen against main 0fb211d, so SEC-001 can grow without moving a rule measured over 29 corpora that are no longer cloned.
The convention is: case-insensitive, by name COMPONENT with adjacent-pair joining, NEVER raw substring and never value length. Raw substring is what this package exists to remove — it made `tokenizer` match "token" and, worse, made a length-guarded bare "key" report enum constants such as CategoryDWDimensionNoSurrogateKey as hardcoded credentials. That guard was inverted in practice: descriptive kebab/snake values grow past 16 bytes BECAUSE they are descriptive, while a real credential has no length floor, so the gate admitted the false-positive class and rejected a true-positive one.
Component matching cannot split an all-lowercase concatenation. That gap is real, is declared in LimitLowercaseConcatenation, and is rendered to agents by codefit-coverage — see ADR 0075.
Index ¶
Constants ¶
const LimitLowercaseConcatenation = "SEC-001 (go) matches by NAME COMPONENT " +
"(camelCase/snake_case/kebab-case tokenized, with adjacent-pair joining and " +
"regular +s plurals, so `passwords`, `apiKeys` and `userPasswords` are " +
"reported), never by raw substring and never by value length. THE GAP: an " +
"ALL-LOWERCASE CONCATENATION carries no boundary to tokenize on, so " +
"`secretkey`, `dbpassword`, `mypassword` and `authtoken` are NOT reported, " +
"while `secretKey`, `secret_key`, `SECRET_KEY`, `db_password`, `myPassword` " +
"and `auth_token` are. Only the regular +s plural is folded: no other " +
"inflection is recognised. This is a known under-detection, declared rather " +
"than closed: the substring matcher it replaced reported enum constants as " +
"hardcoded credentials at Confidence 1.0, and a false affirmation is a worse " +
"failure than a declared gap."
LimitLowercaseConcatenation is the DECLARED gap component matching cannot close, and the reason it is declared rather than fixed. It lives here, beside the tokenizer that causes it, so the claim and its cause cannot drift apart: a consumer cites this const by reference and a compile-time dependency has no way to go stale. Copying the text into a provider, a manifest, or COVERAGE.md would create a second place to be wrong.
Variables ¶
This section is empty.
Functions ¶
func Components ¶
Components splits an identifier into lowercase alphabetic components, breaking on '_'/'-', on lower/digit -> upper transitions, and on letter <-> digit transitions. Digits are separators and are dropped from the word list.
A consecutive run of capitals is NOT split (DWDimension -> "dwdimension"), because without a dictionary there is no boundary to find inside it. That is not a wart: it is the property that makes CategoryDWDimensionNoSurrogateKey tokenize into names none of which is a credential.
func Credential ¶
Credential is the vocabulary SEC-001 consumes: credentialShared plus the SEC-001-only restorations, PLURAL-FOLDED, and never the PII names.
The fold is SEC-001's alone. DB053Union() and SecurityValue() are deliberately not folded: DB-053's vocabulary is frozen name for name against main 0fb211d across 29 measured corpora (ADR 0047), and folding it here would move it as a side effect of credential work — the exact coupling the three-set split exists to prevent.
func DB053Union ¶
DB053Union is the vocabulary DB-053 and DB-020 consume: credentialShared plus piiShared, and NOTHING else. This is the whole reason the split is three sets rather than two — with a two-set split (credential ⊂ union) every SEC-001 widening would silently become a DB-053 change across 29 measured corpora (ADR 0047) that are no longer available to re-measure against. Here, DB-053's vocabulary is provably byte-identical while SEC-001's moves.
func MatchSet ¶
MatchSet reports whether name carries a member of set as a name COMPONENT or as an adjacent component PAIR, returning the matched token.
The scan order is part of the contract, not an implementation detail: ALL components in order, THEN all adjacent pairs, over ONE set. The returned token is EVIDENCE — it reaches the user inside a finding's message — so a different order is a different answer even when the boolean is unchanged. ssnPassword returns "ssn" under this order and "password" under a credential-first two-pass; apiKeyCvv returns "cvv" here because a single component outranks the api+key pair. Both are locked by tests.
func SecurityValue ¶
SecurityValue is the vocabulary SEC-050 consumes.
Types ¶
This section is empty.