chore: de-link parent organization from public tree and add an identity gate - #68
Closed
verlyn13 wants to merge 3 commits into
Closed
chore: de-link parent organization from public tree and add an identity gate#68verlyn13 wants to merge 3 commits into
verlyn13 wants to merge 3 commits into
Conversation
system-config is public and now has outside readers. The parent org carries linkPolicy "no-link" / publicAlias "parent organization" in the identity registry, but its real name appeared 142 times across 40 tracked files. This sweep removes the 100 incidental occurrences -- doc prose, filesystem paths, the org domain, and a Google Workspace super-admin mailbox published beside the gcloud invocation that uses it. Highest-value single change: docs/google-admin-tooling.md went from 15 occurrences to 0. Substitutions: Organizations/the-nash-group -> Organizations/<parent-org> the-nash-group -> <parent-org> Nash-Group -> parent-organization The Nash Group / Nash Group -> the parent organization <admin>@thenash.group -> <parent-org-admin>@<parent-org-domain> thenash.group -> <parent-org-domain> Deliberately NOT changed, and why: - Structural identifiers other things resolve against: the SSH host alias github.com-nash-group, the key filename id_ed25519_nash-group, and the 1Password item path ssh/workstation/nash-group/github. Renaming the prose while the identifier stays would make the docs wrong. - iterm2/profiles/*.json and the four docs describing them. The profile filenames and Bound Hosts globs are matched at runtime; the docs must keep naming them accurately. - policies/host-capability-substrate/tiers.yaml, byte-pinned by a sibling repo -- coordinated re-vendor only. 42 occurrences remain, all structural. This reduces exposure; it does not de-link the organization, because two tracked FILENAMES still carry the name. Completing that requires renaming live artifacts and a vault item, which is a separate operator-gated change. Validation: scripts/validate-repo.sh PASS. No structural file appears in the diff (asserted explicitly).
This 14-line template was the highest-value single artifact in the public repo. It published, together: the parent organization's real name, a publicly routable IPv4 (verified non-RFC1918), User root, and the operator key filename -- i.e. a no-link entity's secrets manager, by reachable address, with root login, in a repo carrying the operator's real identity on every commit. Host identity now comes from ~/.config/chezmoi/chezmoi.toml under [data.ssh.parent_org_openbao] (alias, host, user, identity_file). Machine data already lives outside the repo, so no value is committed. The block is guarded with `hasKey .ssh "parent_org_openbao"` rather than a bare lookup, because chezmoi runs with missingkey=error and a bare key would break rendering on any machine that has not been configured. With the key absent the file renders as comments explaining how to restore it, so `chezmoi apply --dry-run --force` stays clean. OPERATOR ACTION REQUIRED: add the [data.ssh.parent_org_openbao] table before the next `chezmoi apply`, or the live ~/.ssh/conf.d/tng-openbao.conf loses its Host entry and the alias stops resolving. The example values in the template are RFC 5737 documentation addresses, not the real ones. The source filename still carries the "tng" abbreviation. Renaming it is safe (the SSH config Include is a *.conf glob, and the alias now comes from machine data) but renames outside scripts/ and docs/ are ask-first per AGENTS.md, and chezmoi would orphan the old deployed file. Left for a separate decision.
docs/git-identity.md presents identity_no_registry_values_committed as the control for "never commit registry.json or any value from it". Only the file half was ever implemented: that ng-doctor check greps git ls-files for a file NAMED registry.json and runs check-ignore. It performs no content inspection, and it reported green while 142 parent-org occurrences and 32 third-party personal email addresses sat in the tree. ng-doctor is also never executed by CI -- validate-repo.sh only shellchecks its template. Add two content scans to the gate CI actually runs. 1. Parent-org real name. Deliberately does not match a bare "nash-group", which only occurs inside identifiers that other things resolve against (github.com-nash-group, id_ed25519_nash-group, ssh/workstation/nash-group). 2. Email addresses outside an allowlist. The allowlist is what makes this runnable rather than permanently red: it passes vendor, RFC-reserved and operator-owned domains and fails personal and third-party addresses. Failure output for the email scan is MASKED to localpart-initial. CI logs on a public repo are themselves public, so echoing a matched address would publish, durably and indexably, the exact value the step exists to keep out. The org-name scan prints matching lines unmasked, which is correct -- that name is already public via the structural files below. Exclusions are structural, each a value something resolves against at runtime: iterm2/** profile filenames and Bound Hosts globs, docs/iterm2-*.md which document them, zz-iterm2.zsh's $PWD test, the byte-pinned tiers.yaml, tests/policies/** negative fixtures whose values ARE the test input, and home/.chezmoidata.yaml allowed_signers principals which must byte-match the signing identity or verification stops. Also fixes three name occurrences the doc sweep missed on case and hyphen variants -- two description fields in the SSH import manifests and one line in secret-records.md. The structural identifiers on those same lines are unchanged. NOTE: this gate FAILS on main until the PII redaction lands, which is the intended ordering, not a regression. shellcheck clean at the pinned 0.11.0.
verlyn13
added a commit
that referenced
this pull request
Aug 23, 2026
Closes the ownership half of the oldest open finding in docs/ai-tool-config-ownership.md. That file is loaded into every Claude Code session in every repo on this host and had no source of truth, so it was invisible to chezmoi status, chezmoi diff, validate-repo.sh and ng-doctor. The doc records fish surviving in it through every migration pass for exactly that reason, and this is the fourth time its content has been corrected without the ownership being assigned. The source is home/dot_claude/CLAUDE.md and the adoption is a no-op deployment: the source is byte-identical to the live file, chezmoi status reports no diff, and chezmoi apply --dry-run --force exits 0. Nothing on the machine changed; the file simply became visible. dot_claude, deliberately NOT exact_dot_claude. The exact_ prefix would make chezmoi delete everything under ~/.claude/ it does not manage, which is the app's own settings.json, settings.local.json, agents/, commands/ and skills/. .chezmoiignore's Claude guard block is rewritten to say so at the point someone would be tempted to add the prefix. Safe for a public repo, checked rather than assumed: the file has zero non-allowlisted email addresses, zero parent-org name hits, zero identity values and zero absolute /Users paths, so it passes the content gate arriving in PR #68. Scope note: visibility is not binding force. README.md's configuration-layers table still lists this file as non-binding, because it is -- being managed means drift is now detectable, not that the instructions are enforced.
Member
Author
|
Superseded by the accepted successor series: #76 established value-blind public-source privacy enforcement, #77 removed whole-file historical privacy exemptions while preserving public-safe provenance, and #78 moved the remaining machine-specific SSH identity behind validated private machine data with fail-closed destination semantics. The successor changes were independently reviewed, validated, and merged; this older combined branch is no longer a merge candidate. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #66 — merge #66 first, see Ordering below.
Why
system-configis public and now has outside readers. The identity registry gives the parent organizationlinkPolicy: no-link/publicAlias: "parent organization", anddocs/git-identity.mdforbids committing "registry.json or any value from it".registry.jsonitself is clean — never tracked, never added in any commit, gitignored twice. The values rule was the one being violated, and nothing enforced it.1. OpenBao host identity → machine data
home/private_dot_ssh/private_conf.d/tng-openbao.conf.tmplwas the highest-value single artifact in the repo. Fourteen lines that published, together: the parent org's real name, a publicly routable IPv4 (verified non-RFC1918),User root, and the operator key filename. A no-link entity's secrets manager, by reachable address, with root login, in a repo carrying the operator's real identity on every commit.Host identity now comes from
[data.ssh.parent_org_openbao]in~/.config/chezmoi/chezmoi.toml. Guarded withhasKeyrather than a bare lookup, because chezmoi runsmissingkey=errorand a bare key breaks rendering on an unconfigured machine.2. Name sweep — 142 → 42 occurrences
100 incidental occurrences removed across 28 files. Biggest single win:
docs/google-admin-tooling.md15 → 0, which was publishing a Google Workspace super-admin mailbox beside the exactgcloud auth logininvocation that uses it.Deliberately not changed, because changing the prose while the identifier stays would make the docs wrong:
github.com-nash-group, key filenameid_ed25519_nash-group, 1P item pathssh/workstation/nash-group/githubiterm2/profiles/*.jsonand the four docs describing them — the filenames and "Bound Hosts" globs are matched at runtimepolicies/host-capability-substrate/tiers.yaml— byte-pinned by a sibling repoThis reduces exposure; it does not de-link the organization. Two tracked filenames still carry the name (
10-nash-guardian-l0.json,11-nash-repos.json). Completing that means renaming live artifacts and a vault item — a separate operator-gated change.3. The enforcement gap
identity_no_registry_values_committedgrepsgit ls-filesfor a file namedregistry.jsonand runscheck-ignore. Zero content inspection. It reported green throughout.ng-doctoris also never executed by CI —validate-repo.shonly shellchecks its template.Two content scans added to the gate CI actually runs:
nash-group, which only occurs inside the structural identifiers above.Email failure output is masked to localpart-initial. CI logs on a public repo are public; echoing a matched address would publish, durably and indexably, the exact value the step exists to keep out. The org-name scan prints unmasked, which is correct — that name is already public via the structural files.
Exclusions are structural, not cosmetic:
iterm2/**,docs/iterm2-*.md,zz-iterm2.zsh, the byte-pinnedtiers.yaml,tests/policies/**(negative fixtures whose values are the test input), andhome/.chezmoidata.yaml(allowed_signersprincipals must byte-match the signing identity or verification stops).Ordering
This gate fails on
mainuntil #66 lands. That is intended, not a regression. Verified: the six files the email scan flags are exactly the six #66 fixes — so the merged state passes.Validation
shellcheckclean at the pinned 0.11.0chezmoi execute-templaterenders the OpenBao template safely with the key absentNot in scope
History. The name reaches the root commit, so a full rewrite is 335/335 commits and destroys 250 verifiable signatures, and cleans none of the GitHub-side residue. Recommendation is accept-and-document; that decision is yours.