Skip to content

chore(#110): block-private-refs-in-public-repos.sh hook#119

Merged
atlas-apex merged 1 commit into
devfrom
chore/GH-110-block-private-refs-in-public-repos
Apr 24, 2026
Merged

chore(#110): block-private-refs-in-public-repos.sh hook#119
atlas-apex merged 1 commit into
devfrom
chore/GH-110-block-private-refs-in-public-repos

Conversation

@atlas-apex

Copy link
Copy Markdown
Collaborator

Summary

Adds a new PreToolUse hook block-private-refs-in-public-repos.sh that scrubs registered private-project identifiers from content destined for public framework repos (me2resh/apexyard + whatever the fork's upstream remote resolves to + any extras configured under .leak_protection.public_framework_repos).

Catches a common leak vector: an author diagnoses a framework bug while working in a private project, then files the upstream ticket or comment with a helpful "discovered during <private-project> rebase" reference. Once filed, the private project's name is permanently on a public issue tracker and searchable. This hook is the mechanical backstop for the discipline in the new .claude/rules/leak-protection.md rule.

  • New hook: .claude/hooks/block-private-refs-in-public-repos.sh (~230 LOC)
  • New rule doc: .claude/rules/leak-protection.md
  • Config integration: reads .leak_protection.public_framework_repos, .leak_protection.auto_detect_upstream, .leak_protection.skip_marker via the shared config lib introduced in [Chore] Make ticket-prefix whitelist + schema project-configurable (not hardcoded) #109
  • Defaults: extended .claude/project-config.defaults.json with a leak_protection subtree
  • Wired into .claude/settings.json — five PreToolUse matchers for gh issue create, gh pr create, gh issue comment, gh pr comment, gh api
  • Audit entry: new section 10 in docs/rule-audit.md, mechanized count bumped
  • 10 test cases in .claude/hooks/tests/test_block_private_refs.sh

How it works

  1. On every matched gh invocation, parse --repo (or the repos/owner/name/... path on gh api). If the target isn't public-class (not in the configured list + upstream), silent no-op.
  2. Locate apexyard.projects.yaml by walking up from CWD; extract each project's name, repo, and workspace fields. If the registry is missing, silent no-op — treated as "not an apexyard fork."
  3. Self-exempt the target's own slug and bare name: mentioning apexyard on an apexyard upstream ticket doesn't fire.
  4. Scan the title + body (from --title, --body, --body-file, -F <path>, and gh api-style -F body=@file / -f body=...) for whole-word matches against the extracted tokens, plus owner/repo#N patterns.
  5. Skip marker <!-- private-refs: allow --> in the body bypasses with a visible warning.
  6. On match: exit 2 naming each leaked token and suggesting abstract replacement phrasing.

Testing

Ran the committed test fixture — 10 cases, all pass:

$ bash .claude/hooks/tests/test_block_private_refs.sh
PASS: name leak on gh issue create to me2resh/apexyard
PASS: repo-slug leak with ticket ref
PASS: bare repo-slug leak
PASS: skip marker bypasses leak check
PASS: missing registry → no-op
PASS: non-public target → no-op
PASS: empty body → no-op
PASS: workspace path leak
PASS: non-gh command → no-op
PASS: gh api issues leak
Passed: 10  Failed: 0

Also smoke-tested the config integration after swapping the agent's inlined defaults for shared-lib reads:

  • Zero config present → hook falls back to shipped defaults (same behaviour as before)
  • Config with custom public_framework_repos → hook honours the override
  • Config with auto_detect_upstream: falseupstream remote ignored
  • Tests still green end-to-end

Scope — what this does NOT do

  • No CI workflow changes.
  • Does not touch the registry or any skill.
  • Does not alter commit-message or PR-title validation paths (handled in validate-commit-format.sh / validate-pr-create.sh).
  • Does not parse the rare --input - / stdin-driven gh api shape (noted in the hook's own header comment as an accepted gap).

Follow-ups

  • Short-name / generic-word collisions (a project literally named auth or core) could produce false positives. Mitigation is documented in the rule file; can harden with a project-config-level denylist of "skip these names" if pain emerges.
  • The .claude/hooks/tests/ convention was introduced by this hook. If future hook tests accumulate, consider a tiny runner pattern doc.

Glossary

Term Definition
Public framework repo A repo whose issues and PRs are publicly visible and indexed — me2resh/apexyard by default, plus each fork's configured list + upstream auto-detect.
Registered private project Any entry in the fork's apexyard.projects.yaml. The hook treats these as "do not mention upstream."
Skip marker Literal <!-- private-refs: allow --> in the body that lets one invocation through with a visible warning.
Self-exemption The hook does NOT scrub references to the target repo itself — a ticket on the apexyard upstream can legitimately say "apexyard" without firing.

Closes #110

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants