/home/john/bin/describe-secrets (on PATH). Reports the structure of a YAML secrets file — what variables exist, how long each value is, what character classes it uses, whether any two share a value — while never printing, logging or returning a single secret. Written 2026-09-17 for ~/ansible/secrets.yml, but it works on any YAML mapping of names to values.
A secrets file is the one file you want to audit but must not open casually. Opening it puts the values into a terminal, a scrollback buffer, and — when an agent does the opening — a conversation transcript. That is exactly how three credentials came to be leaked on 2026-09-09 (see john/actions item 9). This tool lets the useful questions be answered without that risk: is anything still a placeholder, is any secret implausibly short, has the same password been pasted into two variables, does a value have trailing whitespace that will break an auth header.
describe-secrets ~/ansible/secrets.yml
describe-secrets --hide-names ~/ansible/secrets.yml # shape only
describe-secrets --min-len 16 secrets.yml # stricter length flag
Output is one line per leaf value: name, type, length, a duplicate-detection tag, and a character-class shape such as lower+upper+digit+punct [base64-ish]. Then a findings list.
Do not "simplify" this to a plain hash. A bare SHA-256 of a short or low-entropy secret is trivially brute-forced from a wordlist, so publishing one in a report would leak the value. The tag is HMAC-SHA256(random 32-byte salt, value) truncated to 8 hex characters, with a fresh salt generated on every run. Identical values therefore produce identical tags within one report — which is all that duplicate detection needs — while nothing in the output can be attacked, and two runs cannot be correlated against each other.
--hide-names is given. These are not secret — they appear in the playbooks that consume them.CHANGEME, FIXME, password and similar). This is the point: it tells you the secret was never set. It does reveal that particular value, which is acceptable because such a value is not a secret.Not by inspection. A synthetic file was written with known values covering each case — a placeholder, a short password, a hex token, a duplicated pair, a value with trailing whitespace, an empty string, a nested key — then the tool was run and its output was grepped for every one of those values. All absent. Repeat that test if the output format is ever changed; a formatting change is exactly how a leak would be introduced.
~/ansible/secrets.yml, no duplicates — no password reused across variables.gdata_api_pass is still CHANGEME. Because setup_server.yml guards its htpasswd task with when: gdata_api_pass != 'CHANGEME', that task is silently skipped on every run and the file is never created — while the play reports success. Logged in ansible/todo.aws_access_key_id against the known-leaked and known-live key IDs, so no value was printed; the file holds the computer IAM user's key.Follows main-pattern (importable main(), no sys.exit inside it) and cli-options (argparse, so --help and unknown-option errors come free). Per documentation-in-notes the documentation is here rather than beside the code, and --help prints a pointer back to this note.