Author SHA1 Message Date
sneak 4e6a782edf An unguessable capability URL is the whole credential (closes #52)
check / check (push) Successful in 16s
The HTTP hardening section ends with "when in doubt, harden", which as
written authorises adding HMAC signing or a shared secret on top of an
endpoint already gated by an unguessable per-entrypoint UUID URL. That
has been ruled against twice, and inbound signature verification was
removed from webhooker on exactly that reasoning; until now the only
text contradicting the policy was webhooker's own README.

Adds one scoped carve-out immediately after that sentence: such a URL is
a complete credential and gets no second factor, not even as defence in
depth. The consequences that do follow — keep it out of logs and
tickets, rotate by minting a new entrypoint — are stated, as is what to
do with a sender that only supports signed payloads. Nothing in the
surrounding hardening guidance is removed or weakened.
2026-08-25 20:43:48 +00:00
5 changed files with 41 additions and 35 deletions
+3
View File
@@ -21,6 +21,9 @@ fmt-check, and commit.
# Completed Steps
- 2026-08-25: Carved capability-URL services out of "when in doubt, harden" in
REPO_POLICIES.md: an unguessable per-entrypoint UUID URL is a complete
credential and gets no second authentication factor.
- 2026-08-10: Moved every lint run into a container. `script/lint` now runs the
linter directly when `LINT_IN_CONTAINER=1` and otherwise builds
`Dockerfile.lint`, so the linter never runs on a developer host — closing the
+4 -9
View File
@@ -148,15 +148,10 @@ last_modified: 2026-08-10
1. Keep the `main()` function as small as possible.
1. Keep the `main` package as small as possible. Each `cmd/<name>/` directory
contains a single `main.go` whose body is one call into library code (for
example `os.Exit(cli.Main())` calling `internal/cli`). All CLI logic — flag
parsing, subcommand dispatch, argument handling, output formatting — lives
in `internal/` or `pkg/`, not in `cmd/`. `main` is just an entrypoint to
your code, not a place for implementations. Exception: single-file scripts.
1. No project logic outside `internal/` or `pkg/`. Anything in `cmd/` is a thin
entrypoint only.
1. Keep the `main` package as small as possible. Move as much code as is
feasible to a library package, even if it's an internal one. `main` is just
an entrypoint to your code, not a place for implementations. Exception:
single-file scripts.
1. HTTP HandleFuncs should be returned from methods or functions that need to
handle HTTP requests. Don't use methods or your top level functions as
+1 -3
View File
@@ -128,9 +128,7 @@ with your task.
exports, no `--allow-serial-runners`, and `.lint-cache/` removed from
`.gitignore` and `.dockerignore`.
- [ ] `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` has a 30-second timeout
- [ ] `make test` runs real tests, not a no-op (at minimum, import/compile
check)
- [ ] `make check` passes on current branch
+2 -2
View File
@@ -118,8 +118,8 @@ are thin shims calling them. Model scripts:
installs
- [ ] `script/setup` / `make setup` — readies a fresh clone: runs `bootstrap`,
then `install-precommit`, plus repo-specific init
- [ ] `script/test` / `make test` — runs real tests, not a no-op (90-second
timeout, 60-second hard cap on wall time)
- [ ] `script/test` / `make test` — runs real tests, not a no-op (30-second
timeout)
- [ ] `script/lint` / `make lint` — runs the linter directly when
`LINT_IN_CONTAINER=1`, otherwise `epoch="$(date +%s%N)$$"` on its own line
then `docker build --build-arg CHECK_EPOCH="$epoch" -f Dockerfile.lint .`.
+31 -21
View File
@@ -1,6 +1,6 @@
---
title: Repository Policies
last_modified: 2026-08-19
last_modified: 2026-08-25
---
This document covers repository structure, tooling, and workflow standards. Code
@@ -467,13 +467,8 @@ style conventions are in separate documents:
module under test to verify it compiles/parses. There is no excuse for
`make test` to be a no-op.
- `make test` must complete in under 60 seconds. That is the hard cap, and a
suite that exceeds it fails. Under 20 seconds is the target. A suite between
20 and 60 seconds is still green, but the overage must be filed as an
improvement bug against that repo. Add a 90-second timeout to the test
invocation in the Makefile (`go test -timeout 90s`). The backstop deliberately
sits above the hard cap so that it catches a genuinely hung test rather than a
merely slow one.
- `make test` must complete in under 20 seconds. Add a 30-second timeout in the
Makefile.
- **`make test` should use the conditional verbose rerun pattern.** Run tests
without `-v` (verbose) first. If tests fail, automatically rerun with `-v` to
@@ -492,9 +487,9 @@ style conventions are in separate documents:
```makefile
test:
@go test -timeout 90s -race -cover ./... || \
@go test -timeout 30s -race -cover ./... || \
{ echo "--- Rerunning with -v for details ---"; \
go test -timeout 90s -race -v ./...; exit 1; }
go test -timeout 30s -race -v ./...; exit 1; }
```
Python example:
@@ -671,14 +666,11 @@ style conventions are in separate documents:
- Make all changes on a feature branch. You can do whatever you want on a
feature branch.
- `.golangci.yml` is standardized. The vendored copy in a consuming repo must
_NEVER_ be modified by an agent: fetch it from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml` and keep it
byte-identical, so that no repo can quietly loosen its own linting. Linter
configuration changes are made to the canonical copy in the `prompts` repo and
reach consuming repos by re-vendoring; an agent may open a PR against
canonical, which only the user merges. The canonical golangci-lint version is
v2.12.2 (released 2026-05-06), pinned as the image digest in `Dockerfile.lint`
- `.golangci.yml` is standardized and must _NEVER_ be modified by an agent, only
manually by the user. Fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml`. The
canonical golangci-lint version is v2.12.2 (released 2026-05-06), pinned as
the image digest in `Dockerfile.lint`
(`golangci/golangci-lint@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240`,
which reports
`golangci-lint has version 2.12.2 built with go1.26.2 from c0d3ddc9`). That
@@ -855,6 +847,26 @@ style conventions are in separate documents:
hardening measure exists for HTTP services and is not listed here, it is
still expected. When in doubt, harden.
**One carve-out: capability URLs.** Where a service's credential is an
unguessable URL — a v4 UUID path segment minted per entrypoint — that URL is
the complete credential, not a partial one. Knowing it is authorization.
Such an endpoint does not get a second authentication factor added on top:
no HMAC request signing, no shared secrets, no bearer tokens, not as
defense-in-depth and not as a belt-and-braces extra. This has been
considered and rejected; "when in doubt, harden" is not license to propose
it again.
What does follow from a capability URL is that it is a secret, and is
handled as one:
- Keep it out of logs, error messages, tickets, screenshots, and support
transcripts. Log the entrypoint's internal ID, never its URL.
- Rotate by minting a new entrypoint and retiring the old one. There is no
key to change.
A sender that cannot accept a secret URL and supports only signed payloads
is a constraint on that integration. Raise it — that is not grounds to
reintroduce shared secrets.
- `README.md` is the primary documentation. Required sections:
- **Description**: First line must include the project name, purpose,
category (web server, SPA, CLI tool, etc.), license, and author. Example:
@@ -900,9 +912,7 @@ style conventions are in separate documents:
language-specific config). Everything else goes in a subdirectory. Canonical
subdirectory names:
- `bin/` — executable scripts and tools
- `cmd/` — Go command entrypoints; thin only: one `main.go` per binary whose
body is a single call into `internal/` or `pkg/`, no project logic in
`cmd/`
- `cmd/` — Go command entrypoints
- `configs/` — configuration templates and examples
- `deploy/` — deployment manifests (k8s, compose, terraform)
- `docs/` — documentation and markdown (README.md stays in root)