Take the image signing key from PIXA_SIGNING_KEY and refuse the example placeholder (closes #110) #120

Merged
clawbot merged 6 commits from issue-110-docker-config-signing-key into next 2026-09-21 21:59:25 +02:00
Collaborator

What changed

  • The Docker runtime stage now copies config.docker.yml, which sets
    only signing_key (from PIXA_SIGNING_KEY), state_dir, and port.
    The public placeholder key and the baked-in five-host allowlist are
    gone from the image; operators mount a file over
    /etc/pixa/config.yml for anything else.
  • Startup now refuses the exact config.example.yml placeholder with an
    error naming signing_key (failing test committed first, then the
    fix). The 45-character placeholder previously passed the 32-character
    length check, letting a deployment sign URLs with a key that is public
    in this repository.
  • README.md Getting Started documents the two container-config paths,
    and the local-run example now copies the example file and sets a real
    signing_key, since the placeholder is refused.

Why

upaas configures apps with environment variables and mounts, injecting
no config file, so the key must come from the environment.

What a reader would trip over

  • validateSigningKey is extracted from validate(): the new
    placeholder branch pushed validate() to cyclomatic complexity 16
    (limit 15), so the signing-key checks moved into a helper.
  • The unset-variable abort message ("environment variable
    PIXA_SIGNING_KEY not found") comes from smartconfig interpolation, not
    from validate().

Disclosures

  • Judgement call: did not touch TODO.md; this issue is not the tracked
    Next Step and the definition of done does not list it.
  • Deviation: five commits (failing test first per the repo TDD rule,
    plus the rework commit) rather than one.
  • Pre-existing gomodguard deprecation warning in lint output; out of
    scope, not acted on.

Model: opus-4-8

## What changed - The Docker runtime stage now copies `config.docker.yml`, which sets only `signing_key` (from `PIXA_SIGNING_KEY`), `state_dir`, and `port`. The public placeholder key and the baked-in five-host allowlist are gone from the image; operators mount a file over `/etc/pixa/config.yml` for anything else. - Startup now refuses the exact `config.example.yml` placeholder with an error naming `signing_key` (failing test committed first, then the fix). The 45-character placeholder previously passed the 32-character length check, letting a deployment sign URLs with a key that is public in this repository. - `README.md` Getting Started documents the two container-config paths, and the local-run example now copies the example file and sets a real `signing_key`, since the placeholder is refused. ## Why upaas configures apps with environment variables and mounts, injecting no config file, so the key must come from the environment. ## What a reader would trip over - `validateSigningKey` is extracted from `validate()`: the new placeholder branch pushed `validate()` to cyclomatic complexity 16 (limit 15), so the signing-key checks moved into a helper. - The unset-variable abort message ("environment variable PIXA_SIGNING_KEY not found") comes from smartconfig interpolation, not from `validate()`. ## Disclosures - Judgement call: did not touch `TODO.md`; this issue is not the tracked Next Step and the definition of done does not list it. - Deviation: five commits (failing test first per the repo TDD rule, plus the rework commit) rather than one. - Pre-existing `gomodguard` deprecation warning in lint output; out of scope, not acted on. Model: opus-4-8
clawbot added the needs-review label 2026-09-21 20:13:49 +02:00
clawbot self-assigned this 2026-09-21 20:13:49 +02:00
Author
Collaborator

Findings (needs-rework):

  1. README.md, Getting Started — the local-run example ./bin/pixad --config config.example.yml. This change makes startup reject the placeholder signing_key in config.example.yml, so that exact documented command now aborts at startup instead of running (it previously ran). The Getting Started section was edited in this PR to add the container paragraph, but the line directly above it still tells a reader to run the example file unchanged, which the new code refuses. The README no longer describes what the binary does, and a newcomer following Getting Started hits an unexplained abort on the first run command. Acceptable: update the local-run example so it does not depend on the now-rejected placeholder — copy config.example.yml, set a real signing_key (or pass PIXA_SIGNING_KEY), then run — so the documented command matches the code.

  2. PR body length — the description is about 264 words, over the roughly 250-word limit. Acceptable: trim to 250 words or fewer.

Model: opus-4-8

Findings (needs-rework): 1. `README.md`, Getting Started — the local-run example `./bin/pixad --config config.example.yml`. This change makes startup reject the placeholder `signing_key` in `config.example.yml`, so that exact documented command now aborts at startup instead of running (it previously ran). The Getting Started section was edited in this PR to add the container paragraph, but the line directly above it still tells a reader to run the example file unchanged, which the new code refuses. The README no longer describes what the binary does, and a newcomer following Getting Started hits an unexplained abort on the first run command. Acceptable: update the local-run example so it does not depend on the now-rejected placeholder — copy `config.example.yml`, set a real `signing_key` (or pass `PIXA_SIGNING_KEY`), then run — so the documented command matches the code. 2. PR body length — the description is about 264 words, over the roughly 250-word limit. Acceptable: trim to 250 words or fewer. Model: opus-4-8
clawbot added needs-rework and removed needs-review labels 2026-09-21 20:41:09 +02:00
clawbot force-pushed issue-110-docker-config-signing-key from e1044e9037 to 11c8a96766 2026-09-21 20:52:12 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-09-21 20:52:34 +02:00
Author
Collaborator

Both findings addressed.

  1. README.md Getting Started no longer runs config.example.yml unchanged: the local-run example copies it to config.yml and sets a real signing_key first, matching the new startup rejection. The two other mentions of the file only cite it as a key reference and remain accurate; the devserver target uses config.dev.yml, so no other stale run of the example existed.
  2. PR body trimmed to 245 words.

Rebased onto current next and re-ran the local Docker builder gate before pushing.

Model: opus-4-8

Both findings addressed. 1. `README.md` Getting Started no longer runs `config.example.yml` unchanged: the local-run example copies it to `config.yml` and sets a real `signing_key` first, matching the new startup rejection. The two other mentions of the file only cite it as a key reference and remain accurate; the `devserver` target uses `config.dev.yml`, so no other stale run of the example existed. 2. PR body trimmed to 245 words. Rebased onto current `next` and re-ran the local Docker builder gate before pushing. Model: opus-4-8
Author
Collaborator

Findings (needs-rework):

  1. README.md, Getting Started, the "build and run via Docker" block: the documented steps are make docker followed by docker run -p 8080:8080 -e PIXA_SIGNING_KEY="..." pixad:latest. make docker runs script/docker, which tags the image from script/projectname — that name is pixa, so the image built is pixa:latest. No Getting Started step creates pixad:latest (only make docker-versioned does), so a reader who follows these steps gets "no such image" from the docker run line. This PR edited that exact line to add the PIXA_SIGNING_KEY variable but left the image name that does not match what make docker builds. A newcomer following Getting Started hits a failure on the Docker run — the same class of broken Getting Started command the previous round was reworked to fix, in the same block. Acceptable: reference the image make docker actually builds (pixa:latest) in the run command, or change the build step to make docker-versioned (which tags pixad:latest), so the two lines agree and the documented command runs.

Model: opus-4-8

Findings (needs-rework): 1. `README.md`, Getting Started, the "build and run via Docker" block: the documented steps are `make docker` followed by `docker run -p 8080:8080 -e PIXA_SIGNING_KEY="..." pixad:latest`. `make docker` runs `script/docker`, which tags the image from `script/projectname` — that name is `pixa`, so the image built is `pixa:latest`. No Getting Started step creates `pixad:latest` (only `make docker-versioned` does), so a reader who follows these steps gets "no such image" from the `docker run` line. This PR edited that exact line to add the `PIXA_SIGNING_KEY` variable but left the image name that does not match what `make docker` builds. A newcomer following Getting Started hits a failure on the Docker run — the same class of broken Getting Started command the previous round was reworked to fix, in the same block. Acceptable: reference the image `make docker` actually builds (`pixa:latest`) in the run command, or change the build step to `make docker-versioned` (which tags `pixad:latest`), so the two lines agree and the documented command runs. Model: opus-4-8
clawbot added needs-rework and removed needs-review labels 2026-09-21 21:12:17 +02:00
clawbot added 6 commits 2026-09-21 21:37:39 +02:00
The placeholder is 45 characters, so it passes the length check and a
deployment could unknowingly sign URLs with a key that is public in
this repository. Add a failing validation case (and the placeholder
constant it references); the rejection follows.

Model: opus-4-8
Reject the exact config.example.yml placeholder in validate() with an
error naming signing_key, so a container or file-based deployment that
never changed it fails fast instead of signing URLs with a public key.
The signing-key checks move into a validateSigningKey helper, keeping
validate() within the cyclomatic-complexity limit.

Model: opus-4-8
The runtime stage now copies config.docker.yml, which sets only
signing_key (from PIXA_SIGNING_KEY), state_dir, and port. This drops
the public placeholder key and the baked-in allowlist from the image,
matching how upaas configures apps: environment variables and mounts,
no injected config file.

Model: opus-4-8
Getting Started now shows the docker run with PIXA_SIGNING_KEY and a
short paragraph: the key comes from that environment variable, and any
other setting is changed by mounting a file over /etc/pixa/config.yml.

Model: opus-4-8
The startup now rejects the config.example.yml placeholder signing_key,
so the documented `pixad --config config.example.yml` command aborts on
first run. Show copying the example to config.yml and setting a real
signing_key before running, matching the code.

Model: opus-4-8
make docker tags the image pixa:latest via script/projectname, so the
Getting Started run line must reference pixa:latest, not pixad:latest.

Model: opus-4-8
clawbot force-pushed issue-110-docker-config-signing-key from 11c8a96766 to c9aa48227d 2026-09-21 21:37:39 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-09-21 21:37:50 +02:00
Author
Collaborator

Fixed. The Getting Started Docker run line now names pixa:latest, the image make docker builds through script/projectname, so the build and run steps refer to the same image.

Checked the rest of the README's runnable commands (clone, build, the local run, and the Docker build and run) against the Makefile, the script/ entrypoints and the code; the others already match what they call. Ran the documented Docker build and run with a real signing key and confirmed the healthcheck responded, then removed the container and image.

Model: opus-4-8

Fixed. The Getting Started Docker run line now names `pixa:latest`, the image `make docker` builds through `script/projectname`, so the build and run steps refer to the same image. Checked the rest of the README's runnable commands (clone, build, the local run, and the Docker build and run) against the Makefile, the `script/` entrypoints and the code; the others already match what they call. Ran the documented Docker build and run with a real signing key and confirmed the healthcheck responded, then removed the container and image. Model: opus-4-8
Author
Collaborator

Verified against #110: the definition of done is met — the image ships config.docker.yml reading signing_key from PIXA_SIGNING_KEY with no allowlist and no placeholder secret, a container without PIXA_SIGNING_KEY exits non-zero naming it while a real key serves /.well-known/healthcheck.json, the unchanged config.example.yml mounted over the config path is refused naming signing_key (failing test committed before the fix), README.md Getting Started's build, local-run and Docker commands run as written, only the runtime stage of the Dockerfile changed, and the local Docker gate is green.

Model: opus-4-8

Verified against https://git.eeqj.de/sneak/pixa/issues/110: the definition of done is met — the image ships `config.docker.yml` reading `signing_key` from `PIXA_SIGNING_KEY` with no allowlist and no placeholder secret, a container without `PIXA_SIGNING_KEY` exits non-zero naming it while a real key serves `/.well-known/healthcheck.json`, the unchanged `config.example.yml` mounted over the config path is refused naming `signing_key` (failing test committed before the fix), `README.md` Getting Started's build, local-run and Docker commands run as written, only the runtime stage of the `Dockerfile` changed, and the local Docker gate is green. Model: opus-4-8
clawbot merged commit 1798cba96c into next 2026-09-21 21:59:25 +02:00
clawbot deleted branch issue-110-docker-config-signing-key 2026-09-21 21:59:25 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#120