check / check (push) Successful in 1m0s
Every gpg invocation went through runGPG, which built its command with exec.CommandContext(context.Background(), ...). That is the right call with the wrong context: context.Background() never expires, so no deadline was ever enforced on any of the five gpg call sites. runGPG now takes a context and derives a gpgTimeout deadline from it, honouring an earlier caller deadline when there is one. The gpg-touching library entry points take a ctx as their first argument so cancellation propagates from above: Builder.Build, NewManifestFromReader, NewManifestFromFile, NewChecker, Checker.ExtractEmbeddedSigningKeyFP. Scanner.ToManifest already had a ctx and now passes it down, which withdraws the //nolint:contextcheck claiming signing was "not cancellable by design" -- it is, and now it is. A deadline alone is not enough, and the added test proves it. gpg delegates to helpers (gpg-agent, pinentry) that inherit the captured stdout and stderr pipes. Go's default cancellation kills only the direct child, so the helper keeps the pipes open and Cmd.Wait blocks on the output-copying goroutines forever -- a dead process and a call that still never returns. Two additions fix that: the child runs in its own process group and cancellation kills the group, and Cmd.WaitDelay caps how long Wait will hold on for the pipes if something escapes the group anyway. Measured with the stand-in gpg from the new test: neither mechanism, hangs until `go test` gives up; WaitDelay only, returns in 2.2s; both, returns in 0.20s. Timeout errors now name the operation and how long gpg ran instead of surfacing a bare "signal: killed" or "context deadline exceeded", and a cancellation from above is reported as a cancellation rather than a timeout, so an abort is distinguishable from a stall. The test helper's own keygen invocations had the same unbounded context.Background() and the same pipe-inheriting agent problem, which makes them the actual mechanism behind the intermittent suite timeout noted in the issue: keygen starts gpg-agent, and a stalled agent hung the suite rather than failing it. They now run under a deadline with the same hardening, so a broken gpg environment skips instead of hanging. Verified with a cold `docker buildx build --no-cache`: prettier, gofmt, `make lint` (0 issues) and `make test` all executed and passed. The golang:1.23 image ships gpg, so the real signing, export, fingerprint, import and verify tests run against real gpg there, not skipped. The process-group kill is unix-only and lives in a build-tagged file; on other platforms the deadline is still enforced via cancellation plus WaitDelay, only the group kill of helpers is unavailable.
114 lines
5.6 KiB
Markdown
114 lines
5.6 KiB
Markdown
# 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.md` changes in the same commit as the work)
|
|
- merge to `main` if the branch is not protected, otherwise open a PR
|
|
- push
|
|
|
|
# Status
|
|
|
|
pre-1.0. No git tags. README section "TODO: Remaining Work for 1.0" lists open
|
|
design questions and implementation tasks; policy compliance work is in flight
|
|
and unmerged.
|
|
|
|
# Next Step
|
|
|
|
Work through the remaining compliance items folded from the 2026-07-02 audit
|
|
(the first group under Future Steps): `.editorconfig`, `.gitignore` coverage,
|
|
gofumpt-based `fmt-check`, README "Getting Started", and the rest.
|
|
`.golangci.yml` and `TODO.md` are tracked and committed as of 2026-08-07, so the
|
|
only thing left of the `chore/align-repo-policies` branch is the list below.
|
|
|
|
# Completed Steps
|
|
|
|
- 2026-09-03: enforced real deadlines on every gpg subprocess call
|
|
(`gpgTimeout`, process-group kill, `Cmd.WaitDelay`) and threaded
|
|
`context.Context` through the library entry points that can reach gpg,
|
|
withdrawing the "signing exec is not cancellable" `//nolint` in
|
|
`mfer/scanner.go` (#62)
|
|
- 2026-08-09: added `.prettierrc`/`.prettierignore`, gave `script/fmt` and
|
|
`script/fmt-check` one shared prettier file set via `script/prettier`, dropped
|
|
the `|| true` that hid prettier failures, and added a node-based Dockerfile
|
|
stage so a markdown formatting violation fails `docker build .` (#69)
|
|
- 2026-08-07: updated golangci-lint to v2.12.2 everywhere it is pinned
|
|
(`Makefile`, `Dockerfile`), added the canonical `.golangci.yml`
|
|
(`default: all`), and fixed all resulting lint findings across the codebase
|
|
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile
|
|
shims, README Entrypoints section
|
|
- 2026-07-03: aligned repo tooling, docs, and config with standardized policies
|
|
(7d9a138, on chore/align-repo-policies, unmerged)
|
|
- 2026-06-28: moved to standardized repo policies (#56, on main)
|
|
- 2026-04-07: added 1.0 roadmap as README TODO section, removed old TODO.md
|
|
(#54)
|
|
- 2026-03-20: added Gitea Actions CI workflow (#53)
|
|
- 2026-03-17: added REPO_POLICIES.md, renamed CLAUDE.md to AGENTS.md (#51);
|
|
removed committed .index.mf (#52)
|
|
- 2026-03-15: split Dockerfile with pre-built golangci-lint stage for faster CI
|
|
(#45)
|
|
- 2026-03-01: 1.0 quality polish: code review, tests, bug fixes, docs (#32)
|
|
- 2026-02-20: deterministic file ordering in Builder.Build() (#28); removed
|
|
committed vendor/modcache archives (#35)
|
|
- 2026-02-08: added --seed flag for deterministic manifest UUID
|
|
|
|
# Future Steps
|
|
|
|
- Compliance (fold of TODO.md audit 2026-07-02; verify which items the in-flight
|
|
branch already closes, then check off):
|
|
- Add .editorconfig (canonical copy from sneak/prompts)
|
|
- Make .gitignore cover secrets (.env, _.key, _.pem), OS files (.DS_Store),
|
|
and editor files (_.swp, _~)
|
|
- Make fmt-check/lint verify with gofumpt, not gofmt -l, so `make check`
|
|
matches what `make fmt` writes
|
|
- Add README "Getting Started" section with copy-pasteable install/usage
|
|
block
|
|
- Move FORMAT.md from repo root to docs/ and update the AGENTS.md reference
|
|
- Pin Makefile-installed Go tools (`protoc-gen-go@v1.28.1`,
|
|
`golangci-lint@v2.12.2`) by module hash, not mutable tag
|
|
- Set `make test` timeout to 30s (currently 10s)
|
|
- Add explicit README "Rationale" heading (content exists under other
|
|
names); name the author in the README Description first line
|
|
- Reconcile root-level AGENTS.md with directory-hygiene policy (keep or
|
|
relocate)
|
|
- Add a `make build` target
|
|
- Rewrite `make hooks` to use printf or a heredoc instead of non-portable
|
|
`echo '...\n...'`
|
|
- Answer the 14 owner design questions in the README 1.0 roadmap:
|
|
- Format: simplify MFFileChecksum; store file mode; drop atime; specify path
|
|
normalization rules; version byte after magic; length-prefix after magic
|
|
- Signatures: hash covers compressed or uncompressed data; sign raw bytes vs
|
|
hex canonical string; detached .mf.sig support; GPG subprocess vs pure-Go
|
|
crypto
|
|
- Implementation: deterministic manifests by default; consolidate duplicate
|
|
scanner/checker implementations; export the manifest type; canonical Go
|
|
module path for 1.0
|
|
- Format and correctness:
|
|
- Resolve proto go_package vs go.mod module path inconsistency
|
|
- Specify and validate path invariants (UTF-8, forward-slash, relative, no
|
|
.., no leading /)
|
|
- Remove or deprecate atime; reserve mode field; add version byte (all
|
|
pending design answers)
|
|
- Write a standalone format specification document
|
|
- Library:
|
|
- Delete internal/scanner and internal/checker; consolidate on the mfer/
|
|
package versions (pending design answer)
|
|
- Add decompression size limit via io.LimitReader in deserializeInner()
|
|
- Fix errors.Is dead code in checker; make AddFile verify totalRead == size
|
|
- Export manifest type or define a public interface (pending)
|
|
- Replace GPG subprocess with pure-Go crypto (pending)
|
|
- CLI:
|
|
- Kebab-case primary flag names; fix fetch URL construction with
|
|
url.JoinPath; add http.Client timeout and retry with backoff to fetch;
|
|
rate-limit Checker progress output; add --deterministic flag or default;
|
|
wire top-level --version properly
|
|
- Testing:
|
|
- Fuzz NewManifestFromReader; end-to-end tests for freshen and fetch
|
|
- Documentation:
|
|
- Promote docs/FORMAT.md as primary spec reference; audit error messages;
|
|
document the signature scheme fully
|
|
- Release:
|
|
- Finalize module path, bump version constant, SemVer --version output, tag
|
|
v1.0.0
|