check / check (push) Failing after 2s
A submodule that keeps its own `.git` directory, instead of one under `.git/modules/`, still shipped `sub/.git/config` into the build context, credential included. Both git patterns in the canonical `.dockerignore` now start with `**/`: `**/.git/config` and `**/.git/modules/**/config`. A submodule whose name has a `config` segment (`config`, `deploy/config`, `config/lib`) still loses its whole git directory, because the pattern also matches that directory, and Go's version stamping then fails the build loudly. The file records this as a known gap with the way around it, `git submodule add --name`; closing it needs a wildcard re-include that makes every build walk excluded directories. `prompts/REPO_POLICIES.md` and both checklists say the same. Model: opus-5-5
199 lines
11 KiB
Markdown
199 lines
11 KiB
Markdown
---
|
|
title: Existing Repo Checklist
|
|
last_modified: 2026-10-04
|
|
---
|
|
|
|
Use this checklist when beginning work in a repo that may not yet conform to our
|
|
repository policies
|
|
(`https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md`).
|
|
|
|
Work on a feature branch. Check each item and fix any gaps before proceeding
|
|
with your task.
|
|
|
|
# Formatting (do this first)
|
|
|
|
- [ ] If the repo has never been formatted to our standards, run `make fmt` and
|
|
commit the result as a standalone branch/commit/PR before any other
|
|
changes. Formatting diffs can be large and should not be mixed with
|
|
functional changes.
|
|
|
|
# Required Files
|
|
|
|
- [ ] `README.md` exists with all required sections (Description, Getting
|
|
Started, Rationale, Design, TODO, License, Author)
|
|
- [ ] `LICENSE` file exists and matches the README
|
|
- [ ] `REPO_POLICIES.md` exists and version date is current — fetch from
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md`
|
|
- [ ] Guidance for coding agents, if the repo has any, is one `AGENTS.md` at the
|
|
root — never a file or directory named after one agent tool, such as
|
|
`CLAUDE.md` or `.claude/`, and never separate memory files. Move what any
|
|
such committed file says into `AGENTS.md` and delete it.
|
|
- [ ] `.gitignore` is comprehensive (OS, editor, agent scratch, language
|
|
artifacts, secrets) — fetch from
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore` if missing.
|
|
An existing repo usually has a hand-written one that is never re-fetched,
|
|
so check the entries rather than the file's presence.
|
|
- [ ] `.editorconfig` exists — fetch from
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig`
|
|
- [ ] `Dockerfile` and `.dockerignore` exist; the Dockerfile carries a `lint`
|
|
phase and a `test` phase, and the final stage carries a `COPY --from=` of
|
|
a harmless file from each — fetch `.dockerignore` from
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.dockerignore`
|
|
- [ ] Nothing has been appended after the final stage, and the gate phases are
|
|
reachable from it. A stage nothing depends on is built only when
|
|
`--target` names it, so a lost `COPY --from=` edge leaves `docker build .`
|
|
passing while the gate never runs. Confirm by planting a violation, not by
|
|
reading the file.
|
|
- [ ] The gate phases invoke their tools directly, never through `make lint` or
|
|
`script/test` — those are themselves a `docker build` and would recurse
|
|
inside a build step
|
|
- [ ] Every depth-independent pattern in `.dockerignore` carries a `**/` prefix,
|
|
only genuinely root-anchored entries such as `.claude` are unprefixed, and
|
|
`.gitignore`'s patterns have not been transplanted unmodified — the
|
|
transplanted form leaves `config/.env` and `certs/server.key` in the build
|
|
context while reading as solved
|
|
- [ ] `.dockerignore` excludes the repo's own host-built artifacts (compiled
|
|
binaries, test binaries, coverage output), written root-anchored —
|
|
`/myapp`, never `**/myapp`. An existing repo is where such a binary is
|
|
likeliest to already be sitting in the build context, invisible to git.
|
|
- [ ] `.claude/` is in `.gitignore` (unanchored) and `.claude` in
|
|
`.dockerignore` (anchored, no `**/` prefix). Agent worktrees are entire
|
|
checkouts of the repo, so they inflate the context by a multiple of it and
|
|
can copy another session's unreviewed work into an image layer. If agents
|
|
here run anywhere other than the repo root, the anchored entry misses
|
|
`services/api/.claude/`: add anchored entries for those directories.
|
|
- [ ] If the repo embeds a version in a binary: `.dockerignore` lets `.git` into
|
|
the build context. It keeps out every git `config` at any depth
|
|
(`**/.git/config`, `**/.git/modules/**/config`): the repository's own,
|
|
each submodule's under `.git/modules/`, and that of a submodule keeping
|
|
its own `.git` directory. `git describe` does not need them, and each can
|
|
hold a credential: a password in a remote URL, or the token the CI
|
|
checkout step stores there. A submodule whose name has a `config` segment
|
|
(`config`, `deploy/config`, `config/lib`) loses its whole git directory to
|
|
`**/.git/modules/**/config`, and Go's version stamping then fails the
|
|
build: give it a name without that segment (`git submodule add --name`).
|
|
The stage that compiles has `git` (the Debian Go image has it; an alpine
|
|
one needs `apk add --no-cache git`) and takes the version from the
|
|
`VERSION` build argument when one is given, otherwise from
|
|
`git describe --tags --always`. That gives the tag on a tagged commit; on
|
|
a later commit, the tag, the number of commits since it and the short
|
|
commit (`v1.2.3-4-gabc1234`); and the short commit when no tag is
|
|
reachable. The stage that compiles also marks its working directory safe
|
|
for git (`git config --system --add safe.directory /src`): a context sent
|
|
as a tar stream keeps the sender's file owners, and git refuses a checkout
|
|
owned by another user, so the version would come out empty. `ARG VERSION`
|
|
has no default, and the build fails if the context carries `.git` and the
|
|
version still comes out empty, `dev` or `unknown`. A plain
|
|
`docker build .` with no build arguments must succeed; a Dockerfile that
|
|
refuses an empty build argument drops that refusal and keeps the argument.
|
|
`script/docker` and `script/cibuild` pass the version they compute on the
|
|
host; it takes precedence. A tag-derived version additionally needs
|
|
`fetch-depth: 0` on the CI checkout step, which clones shallow and fetches
|
|
no tags by default.
|
|
- [ ] Gitea Actions workflow in `.gitea/workflows/` runs `script/cibuild` on
|
|
push — reference
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml`
|
|
- [ ] Language-specific config:
|
|
- [ ] Go: `go.mod`, `go.sum`, `.golangci.yml` (fetch from
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml` and,
|
|
in the same commit, set the lint phase digest to the one named in the
|
|
`.golangci.yml` paragraph of `REPO_POLICIES.md`)
|
|
- [ ] JS: `package.json`, `yarn.lock`, `.prettierrc`, `.prettierignore`
|
|
(fetch from
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrc` and
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierignore`)
|
|
- [ ] Python: `pyproject.toml`
|
|
- [ ] Docs/writing: `.prettierrc`, `.prettierignore` (same URLs as above)
|
|
|
|
# Makefile and script/ Entrypoints
|
|
|
|
- [ ] `Makefile` exists in root — reference
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile`
|
|
- [ ] Has targets: `test`, `lint`, `fmt`, `fmt-check`, `check`, `docker`,
|
|
`hooks`
|
|
- [ ] Target implementations live in `script/` (scripts-to-rule-them-all);
|
|
Makefile targets are thin shims calling them — model scripts at
|
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/script/<name>`
|
|
- [ ] `script/precommit` exists and the pre-commit hook (installed by
|
|
`script/install-precommit`, shimmed by `make hooks`) runs it
|
|
- [ ] README has an **Entrypoints** section documenting the `script/`
|
|
entrypoints and linking the standard
|
|
- [ ] `script/lint` and `script/test` build their phase by name
|
|
(`docker build --no-cache --target <phase> -t <name>-<phase> .`), and no
|
|
host invocation anywhere in the repo can produce a lint verdict — grep for
|
|
the linter's own name across `script/`, the `Makefile` and CI config, not
|
|
just `script/lint`. A second path is likeliest here: a `make lint-fast`,
|
|
an older host-versus-container branch, or a CI step calling the binary
|
|
directly. `script/fmt` and `script/fmt-check` are expected hits and stay
|
|
on the host.
|
|
- [ ] Every `docker build` in `script/` is tagged — an untagged one leaves a
|
|
dangling image behind on every run, on every host and CI runner
|
|
- [ ] `script/cibuild` runs `script/bootstrap` before `script/check`, and builds
|
|
the image with `--no-cache`. Without the bootstrap the CI run dies in
|
|
`script/fmt-check`, which runs the formatter on the host and finds nothing
|
|
installed.
|
|
- [ ] `script/fmt` and `script/fmt-check` source nvm for the pinned node version
|
|
before invoking `yarn`, as `script/bootstrap`'s own install step does.
|
|
`script/bootstrap` leaves the node and yarn it installs off the `PATH` of
|
|
the shell that called it, so a bare `yarn` exits 127 on a runner carrying
|
|
nothing but docker and git.
|
|
- [ ] `script/bootstrap` installs no linter of its own — delete the block, its
|
|
version variables and its call site. A JS repo's `yarn install` stays; it
|
|
brings a linter along with every other dependency, and no verdict is taken
|
|
from it.
|
|
- [ ] `make check` does not modify any files in the repo
|
|
- [ ] `make test` has a 90-second timeout and completes within the 60-second
|
|
hard cap (over 20 seconds is green but must be filed as an improvement
|
|
bug)
|
|
- [ ] `make test` runs real tests, not a no-op (at minimum, import/compile
|
|
check)
|
|
- [ ] `make check` passes on current branch
|
|
|
|
# Formatting
|
|
|
|
- [ ] Platform-standard formatter is configured (`black`, `prettier`, `go fmt`)
|
|
- [ ] Default formatter config, only exception: four-space indents (except Go)
|
|
- [ ] All files pass `make fmt-check`
|
|
|
|
# Git Hygiene
|
|
|
|
- [ ] Pre-commit hook is installed (`make hooks`)
|
|
- [ ] No secrets in the repo (`.env`, keys, credentials)
|
|
- [ ] No mutable references in Dockerfiles or scripts (tags, `@latest`) — all
|
|
pinned by cryptographic hash with version/date comment
|
|
- [ ] Using `yarn`, not `npm` (JS projects)
|
|
|
|
# Directory Structure
|
|
|
|
- [ ] No unnecessary files in repo root
|
|
- [ ] Files organized into canonical subdirectories (`bin/`, `cmd/`, `docs/`,
|
|
`internal/`, `static/`, etc.)
|
|
- [ ] Go migrations in `internal/db/migrations/` and embedded in binary
|
|
|
|
# HTTP Service Hardening (if targeting 1.0 and the repo is an HTTP/web service)
|
|
|
|
- [ ] Security headers set on all responses (HSTS, CSP, X-Frame-Options,
|
|
X-Content-Type-Options, Referrer-Policy, Permissions-Policy)
|
|
- [ ] Request body size limits enforced on all endpoints
|
|
- [ ] Read/write/idle timeouts configured on the HTTP server (slowloris defense)
|
|
- [ ] Per-handler execution time limits in place
|
|
- [ ] Password-based auth endpoints are rate-limited
|
|
- [ ] CSRF tokens on all state-mutating HTML forms
|
|
- [ ] Passwords hashed with bcrypt, scrypt, or argon2
|
|
- [ ] Session cookies use HttpOnly, Secure, and SameSite attributes
|
|
- [ ] True client IP correctly detected behind reverse proxy (trusted proxy
|
|
allowlist configured)
|
|
- [ ] CORS restricted to explicit origin allowlist for authenticated endpoints
|
|
- [ ] Error responses do not leak stack traces, SQL queries, or internal paths
|
|
|
|
# Final
|
|
|
|
- [ ] `make check` passes
|
|
- [ ] `script/cibuild` succeeds in a fresh clone on a host carrying nothing but
|
|
docker and git, with no node or yarn on `PATH`, which is what CI has, and
|
|
demonstrably executed the checks — a sub-second build, or `CACHED` on a
|
|
gate layer, means nothing ran
|
|
- [ ] A planted lint violation fails both `make lint` and a plain
|
|
`docker build .`; revert it afterwards
|
|
- [ ] Commit and merge fixes before starting your actual task
|