You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
pkgdown publishes CLAUDE.md: add the pre-build removal and allowlist gate #50
CLAUDE.md stops being published on the pkgdown site, and a declared allowlist
means a future root-level markdown file cannot leak silently.
What happens if we never do
CLAUDE.html stays live, and anything added to CLAUDE.md publishes
automatically the next time the site builds. drift is a public repo, so
there is no incremental exposure today — the same content is already readable in
the repo. The cost is that the gate the convention prescribes does not exist, so
the protection depends on drift staying public and its CLAUDE.md staying
innocuous.
pkgdown:::package_mds() renders every root-level .md except a hardcoded
allowlist (README, LICENSE, NEWS, two GitHub templates). There is no config
option to exclude a file, and .Rbuildignore does not apply — pkgdown reads the
source tree, not the tarball.
Fix, per soul/conventions/pkgdown-publishing.md
Two steps, both in .github/workflows/pkgdown.yaml:
Remove before the build, not after. There are three published copies — CLAUDE.html, a verbatim CLAUDE.md, and the text inside search.json — so
deleting the rendered page afterwards fixes one of three.
- name: Keep internal notes out of the published siterun: rm -f CLAUDE.md
Gate on a declared allowlist, so a new root markdown file fails the build
rather than publishing. Test it against both known answers before trusting it:
it must exit non-zero on a site that contains the file and zero on one that
does not.
Also worth checking while there: whether the deploy action uses clean: true.
With clean: false nothing is ever deleted from gh-pages, so removing the file
from source does not unpublish it — the stale copy needs an explicit purge.
Not urgent
Filed from /compact-prep rather than fixed inline: it is a workflow change
unrelated to the branch that surfaced it (#47), and it wants the two-answer test
on the guard rather than a drive-by edit.
Done in #53 (merged as aa09831). I did not see this issue before doing the work — the PR implements exactly what this body prescribes, plus clean: true, and should have referenced it.
Verified live after the deploy:
CLAUDE.html -> 404
CLAUDE.md -> 404
search.json (grep -ic sred) -> 0
site index / reference / news -> 200
The one addition beyond this body: clean: true on the deploy. With clean: false the action never deletes, so removing CLAUDE.md from source would not have unpublished the existing CLAUDE.html and CLAUDE.md — they would have stayed up indefinitely. Checked first that gh-pages carries no CNAME and no dev/ tree, so nothing hand-added was at risk; confirmed afterwards that the rest of the site is intact.
The allowlist gate was tested against four known answers before shipping: clean site → 0, site with CLAUDE.html → 1, a name spanning two allowed entries (authors index) → 1, and empty docs/ → 1. The third is why membership is an explicit loop rather than case " $allowed " in *" $b "*), which matches a substring. The fourth caught a first draft where a loop over an empty docs/ exited 0, making "the build produced nothing" indistinguishable from "all clear".
Activity
NewGraphEnvironment commentedon Sep 2, 2026
Done in #53 (merged as
aa09831). I did not see this issue before doing the work — the PR implements exactly what this body prescribes, plusclean: true, and should have referenced it.Verified live after the deploy:
The one addition beyond this body:
clean: trueon the deploy. Withclean: falsethe action never deletes, so removingCLAUDE.mdfrom source would not have unpublished the existingCLAUDE.htmlandCLAUDE.md— they would have stayed up indefinitely. Checked first that gh-pages carries noCNAMEand nodev/tree, so nothing hand-added was at risk; confirmed afterwards that the rest of the site is intact.The allowlist gate was tested against four known answers before shipping: clean site → 0, site with
CLAUDE.html→ 1, a name spanning two allowed entries (authors index) → 1, and emptydocs/→ 1. The third is why membership is an explicit loop rather thancase " $allowed " in *" $b "*), which matches a substring. The fourth caught a first draft where a loop over an emptydocs/exited 0, making "the build produced nothing" indistinguishable from "all clear".