README missing four required sections; TODO.md is stale and describes completed work as pending #46
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
From the repo-standards audit. Docs-only, so per repo workflow this one skips adversarial review and goes straight to
merge-readyoncemake checkis green.Divergences
README structure. Policy requires Description, Getting Started, Entrypoints, Rationale, Design, TODO, License, Author. Present today: Description, Entrypoints (this one is genuinely good — it opens by naming the Scripts to Rule Them All standard with the link and documents all twelve scripts), and Author. Missing as named sections: Getting Started, Rationale, Design, TODO, License.
The content mostly exists under different headings — "Installation" and "Quick Start" cover Getting Started, "Core Architecture" covers Design — so this is largely renaming plus two genuinely new sections.
Description line is non-compliant. Policy requires the first line to include name, purpose, category, license, and author, with this model: "µPaaS is an MIT-licensed Go web application by @sneak that receives git-frontend webhooks and deploys applications via Docker in realtime." The current opening states name, purpose and category but omits license and author. License appears only as prose at line 533 under
# Author, never as its own section.TODO.md is actively misleading. Its
# Next Stepsection reads:All four are already done.
fmt-checkandhooksare atMakefile:57-61;REPO_POLICIES.mdand.editorconfigare both present and byte-identical to canonical;.gitea/workflows/check.ymlexists; all three Dockerfile stages are digest-pinned. An agent or contributor reading this would redo completed work. The third bullet is also wrong on its own terms — the workflow correctly runsscript/cibuild, notmake checkdirectly.Policy also wants the TODO in the README: "When planning, put the todo list in the README so a new agent can pick up where the last one left off."
Definition of done
# Next Stepblock is cleared and its four completed items moved into# Completed Stepswith the date they actually landed.1.0.0milestone with a link is the right shape.proseWrap: always(hard wrap at 80). The audit measured 19 lines over 80 columns in README.md and 5 in AGENTS.md.make checkgreen.Implementation requirements
Next Stepmust reflect reality. The authoritative queue is the Gitea1.0.0milestone, and the README should say so.Manager note, for whoever picks this up: three entries in the old
TODO.md1.0 blocker list were verified against the current code and are already fixed. They should be deleted fromTODO.mdas part of this issue rather than carried forward or filed as work. Evidence below so the deletion is not taken on faith.Command injection — fixed, both halves.
No shell is spawned anywhere in the repo; there is no
sh -c. Every GPG invocation usesexec.CommandContextwith an argv slice, and key IDs are validated first by an anchored allowlist (pgpunlocker.go:50-55,validateGPGKeyIDat:371-381, applied at:384-394and:434-442). Option injection via a leading-does not work: the value is passed as the operand after-r, which gpg consumes as a recipient, not as a new flag. The on-disk metadata key ID is never passed to an exec —GetGPGKeyID()feeds display inGetID()only.The macOS half is fixed because the code no longer exists:
keychainunlocker.gouses thego-keychainAPI directly (:490-578) and has noexecimport at all. Item names are separately validated at:477-487.Timing attacks — fixed, and the remaining comparisons are not vulnerabilities.
bytes.Equalis gone from non-test code; it survives only in test files. The two comparisons that remain are both non-constant-time and both fine.internal/cli/init.go:216compares a passphrase the user typed twice at the same terminal — there is no oracle, and an attacker positioned to measure it can already read the buffer.internal/vault/vault.go:206-215compares a double-SHA256 of a public key against a stored hash of that same public key; both operands are public values.crypto/subtleis not imported anywhere, and does not need to be. If you want constant-time compares at those two sites as defense in depth it is a four-line change, but it closes nothing.Secure temporary file handling — moot as written.
There are no temp files. Zero hits for
os.CreateTemp,MkdirTemp,ioutil.TempFile, or hand-built.tmppaths in non-test code; every write goes directly to its final path. Permissions are correct throughout —DirPerms = 0o700,FilePerms = 0o600ininternal/secret/constants.go, used by everyMkdirAllandWriteFile.Worth stating plainly: the reason there are no temp files is that writes are not atomic, which is #34. Fixing #34 introduces temp files holding key material, at which point this item becomes live again as a requirement of that work — and #34's definition of done already carries it (0600 at creation, in the destination directory, cleaned up on every error path). So delete it here, but do not conclude the concern is permanently retired.
Two further corrections to fold into the cleanup: the old list named
internal/cli/version.goamong the unprotectedidentity.String()sites — it contains no such call, and the accurate site list is now in #38. Andinternal/cli/crypto.gois described as holding the age key in a plain string; it is held in aLockedBufferthroughout, with one genuine residual atcrypto.go:95, also captured in #38.Everything else from that list is now filed individually under the
1.0.0milestone.