docs(spec): a security baseline for reference deployments, enforced in CI - #34
Draft
antstanley wants to merge 1 commit into
Draft
Conversation
This was referenced Aug 5, 2026
…n CI Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
antstanley
force-pushed
the
spec/baseline-reference-deployments
branch
from
August 5, 2026 12:01
fa819d6 to
2ae5cde
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Stacked PR 15 of 16 — part of stack #35, which targets
main.Base: #30 (
spec/harden-release-supply-chain) · Followed by: #28This PR's diff shows only its own change. Merge the stack bottom-up; do not merge this before its base.
Why it sits at position 15: Reference deployments and templates. Follows #30 because both modify
bindings/specs/05-distribution.md, and follows #25, which owns the KMS algorithm strings in the example configs.Scope of this PR
This PR currently carries the change spec. It will also carry the implementation plan and the build work for that spec — plan and code land as later commits on this same branch, so the spec, its plan, and its implementation review and merge as one unit.
Review order within the PR: spec first, then plan, then implementation.
Change spec adopting the
reference-deployment-baselinehardening proposal — the one proposal of eight that no spec had taken, leaving 7 findings with no home including both remaining uncovered mediums.Proposed delta. Option 2 on the proposal's recommended path: a named, versioned baseline plus a CI conformance gate, with Option 1's per-template fixes as a mandatory first phase and the Option 3 carve-out of one manual end-to-end run of the two KMS examples. Seven findings become work packages A1–A7; the
reference-baselineCI job asserts seven baseline properties (B1–B7) over every shipped template, plus three cross-layer assertions that live incargo nextestbecause a Terraform scan cannot see a client silently downgrading its own connection.Findings closed:
g4-aws-web-demo-app-unverified-jwt(medium),g4-fargate-alb-plaintext-http-listener(medium),g4-fargate-valkey-unencrypted-unauthenticated,g4-cdk-client-secret-plaintext-lambda-env,g4-k8s-example-no-security-context,g4-postgres-example-schema-drift,g3-local-store-default-file-permissions— plus the orphaneddeferred_sqlite_index_recreate_window, which folds into the samecreate_poolthe0600fix already opens.Three things reading the real files corrected:
Dockerfilehas noUSERdirective, so the Kubernetes finding'srunAsNonRoot: truealone would produceCreateContainerConfigError. The fix has to land in the image, not just the manifest.terraform apply. It recommends making the plaintext listener conditional, butmain.tf:677-679pins the ECS service toaws_lb_listener.httpviadepends_on—count-conditioning it indexes into an empty list. The finding does not mention this.g4-postgres-example-schema-driftnames the wrong half. The missingversioncolumn is repaired at startup (ALTER TABLE … ADD COLUMN IF NOT EXISTSsucceeds because compose makes the app role the DB owner). The unrepairable half is the index:init.sql:14createsidx_users_external_idwhile the migration only dropsidx_users_external_id_provider.Confirmed traps:
crates/adapters/Cargo.toml:31isfeatures = ["serde-json"]with no TLS feature andvalkey/mod.rs:31callsConfig::from_url, sorediss://is silently downgraded — the fix needs a Cargo feature (enable-rustls-ring, for consistency with the workspace'ssqlx tls-rustls). Andresolve_placeholders_in_strreadsstd::env::varonly, so a Secrets Manager ARN in a Lambda environment variable resolves to nothing; the CDK fix needs theAWS_LAMBDA_EXEC_WRAPPERthatstack.ts:89already uses for the sibling function.On the demo relying party the spec commits to verifying against the service JWKS rather than shipping a decode-only variant, on three grounds: the loader has the literal shape of an auth gate (
redirect(302,'/')on both absence and parse failure), so a "display only" comment is the first thing lost to copy-paste;GET /keysotherwise has zero demonstrated consumers anywhere in the repo; and thehttpOnlycookie is no substitute, since anything that can write a cookie for the origin supplies a token this loader accepts indefinitely with noexpcheck.Canonical pages:
bindings/specs/05-distribution.md,service/specs/08-persistence.md,service/specs/06-configuration.md,architecture-principles.md.Two incidental divergences flagged, not fixed (outside this spec's scope):
05-distribution.mdsays the builder image isrust:1.85-slimwhile the realDockerfileisrust:1.96-slim, anddocs/deployment/linux-postgres.md:57tells operators the service runs its own migrations, contradicting the compose-mountedinit.sql.Drafted with the
spec-creatorplugin from a deep security scan of the repository at53cbdec9. Spec only — no source or template changes.