All checks were successful
check / check (push) Successful in 8s
The canonical .dockerignore was three lines -- .git, node_modules, .DS_Store -- while the canonical Dockerfile does `COPY . .`, so a developer's local .env, *.pem or *.key was shipped into the build context and could land in an image layer. Nothing surfaced it because .gitignore covers those patterns, so the files are invisible to every git-based check. The obvious repair, copying .gitignore's secret patterns across, is worse than the gap it closes. .dockerignore does not use .gitignore semantics: Docker matches with Go filepath.Match, `*` does not cross `/`, and a pattern without a leading `**/` is anchored at the build-context root. A file listing .env, *.pem and *.key therefore reads as solved, reviews as solved, and protects only the repository root, while config/.env and certs/server.key still ship. The three-line file at least invited scrutiny; the transplanted form manufactures confidence and stops anyone looking. So every depth-independent pattern here carries the `**/` prefix and only genuinely root-anchored entries stay unprefixed. `**/node_modules` fixes a defect the three-line file had today for any nested node_modules, independently of the secret exposure. The OS and editor patterns are included on their own merits rather than by mirroring .gitignore. None of them is ever a build input, and editor state in particular churns under a developer's hands, so each one is a source of `COPY . .` invalidation carrying no information about the source tree. Now that the checks are keyed on CHECK_EPOCH rather than on accidental context churn, there is no reason left to keep churn in the context. Language build artifacts are deliberately absent: they are per-repo, and the file's header comment tells consuming repos to add their own host-built binaries, which is the case that actually bites -- a host `make build` drops a multi-megabyte artifact into the context where .gitignore hides it from every git-based check. .gitignore is untouched. Its semantics are the inverse: an unanchored pattern already matches at any depth, so `**/`-prefixing it produces a file that is wrong in a way that looks careful. That asymmetry is why "derive one from the other" was the wrong instruction, and it is now written down in REPO_POLICIES.md in both directions, together with the requirement to verify by enumerating the image rather than by reading the patterns. Every consuming repo inherits .dockerignore by copy, so the trap has to live where the next person looks, not only be fixed once here. Both repo checklists gain the same requirement, since they are what an agent reads while extending the file. Verified by planting .env, server.key and ca.pem at the root plus config/.env, config/.env.production, certs/ca.pem, certs/server.key, deploy/secrets/id_rsa.key, web/node_modules/nested/index.js and a nested .swp below it, then building a standalone probe image doing `COPY . .` and listing what actually landed inside it. Before: all eleven planted files in the image. Against the naive unprefixed form: the three root-level files excluded and every nested one still present, which is what shows the enumeration can detect the failure mode at all. After: every planted file excluded at every depth, with web/src/app.js still present to prove the probe was copying nested files rather than copying nothing. Transferred-context size is recorded but load-bearing on nothing, and the runs show why: the naive build reported 2.18kB transferred while 43 files, five of them secrets, were in the image. BuildKit transfers only the delta from the previous build, so the number describes the transfer and not the contents. Planted files were removed and their absence confirmed against the filesystem rather than against `git status`, which could not have seen them. `make docker` re-run after the change: the check layer executed rather than being served from cache, so the CHECK_EPOCH verification still holds under the altered build context.
4.1 KiB
4.1 KiB
Workflow
- branch (from
main) - do the work in Next Step
- move Next Step to the top of Completed Steps
- move the top item of Future Steps into Next Step
- commit (
TODO.mdchanges in the same commit as the work) - merge to
mainif the branch is not protected, otherwise open a PR - push
Status
pre-1.0
Next Step
Finish the two draft prompt documents in the working tree and commit them:
prompts/FIXUP_CLEAN.md (currently a near-empty stub) and prompts/FIXUP_REPORT.md
(a rough draft). Write the missing content, run make fmt so they pass
fmt-check, and commit.
Completed Steps
- 2026-08-09: Closed the secret exposure in the canonical
.dockerignore: a developer's local.env,*.pemor*.keywas reaching the Docker build context underCOPY . ., invisible to every git-based check because.gitignorecovers it. The patterns are written to.dockerignore's ownfilepath.Matchsemantics —**/-prefixed so they hold at every depth, which also fixes nestednode_modules— rather than transplanted from.gitignore, whose unprefixed form protects only the repository root while reading as solved.REPO_POLICIES.mdand both repo checklists now state that asymmetry and require verification by enumerating the image rather than by reading the patterns. Verified with a probe image before, against the naive unprefixed form, and after. - 2026-08-09: Made the pinned golangci-lint actually propagate: REPO_POLICIES.md
now carries the canonical
script/bootstrapsnippet for Go repos, which installs when the installed version does not match the pin (the oldif missingguard tested PATH presence only, so pins were inert on any provisioned machine and CI silently disagreed with local) and then re-resolves the binary throughPATHand fails loudly, naming the shadowing path, when the install did not take effect — the failure mode the naive compare-then-install fix leaves behind while reporting success. - 2026-08-09: Fixed the false green in the canonical CI gate:
script/cibuildandscript/dockernow pass a per-invocationCHECK_EPOCHnonce, and theDockerfile(plus the Go multistage template in REPO_POLICIES.md, in both its lint and builder stages) declaresARG CHECK_EPOCHwith a guard that makes a baredocker build .fail closed. Corrected the org-canonical text that asserted a successful build implies all checks pass, across every document carrying it:REPO_POLICIES.md, both repo checklists (which still told agents to write the pre-fixscript/cibuildand ended on an acceptance item the guard makes unsatisfiable), and the Go styleguide. - 2026-08-07: Set the canonical
.golangci.ymlto the org-standard v2-schema config already deployed byte-identical across the org's Go repos (settings underlinters.settingsso thresholds like lll/funlen/cyclop/dupl actually apply under golangci-lint v2). Recorded the canonical golangci-lint version (v2.12.2, commit-pinned) in REPO_POLICIES.md. - 2026-03-20: Strengthened constructor naming and Params struct rules in the Go styleguide.
- 2026-03-18: Documented fail-fast Dockerfile lint stage and conditional -v test rerun patterns in REPO_POLICIES.md.
- 2026-03-11: Added HTTP service hardening policy for 1.0 releases.
- 2026-03-10: Added policy: no build artifacts in repos.
- 2026-03-04: Added LLM prose tells reference and copyediting checklist, then several self-applied revision passes.
- 2026-02-28: Expanded the pre-1.0 schema migration rule; added clawpub reference.
- 2026-02-23: Added Go style rules (no type-only packages, Stringer for string-based types); template repos section in README.
- 2026-02-22: Initial policy corpus: REPO_POLICIES.md, code styleguides (general, Go, JS, Python), repo checklists, CI policy, hash pinning, Go HTTP server conventions, repo scaffolding.
Future Steps
- Finish, format, and commit FIXUP_CLEAN.md and FIXUP_REPORT.md (the Next Step).
- Commit this TODO.md at the repo root; it is the last missing policy file.
- Decide the fate of untracked resume.sh: commit it or delete it.
- Add more prompt templates for common development tasks (from README TODO).