Problem
GOWDK enforces security in scattered places — default-deny guards, generated
CSRF, body caps, panic boundaries, secret redaction, and the diagnostic registry — but
there is no single, declarative, auditable view of an app's whole security
posture, no way to declare the intended posture and have it checked, and no
integration-test framework that proves the runtime behaves as declared. The
production-readiness gates in docs/engineering/security.md exist only as prose.
Teams (and LLMs reviewing a change) cannot answer "is this app's security
posture acceptable?" from one artifact.
Goals
- A declarative, machine- and human-readable security posture derived from the
IR (
gowdk-security.json), covering routes, backend endpoints, contracts, and the frontend surface. - A
gowdk auditcommand that evaluates a built-in baseline (the documented production-readiness gates, made executable) against that posture and reports registry-coded findings withfile:lineand remediation. - Composable, declared policies in a new
*.audit.gwdkfile kind that extend or override the baseline (named policies,extends, selector-applied to many targets). - Frontend coverage: secret/data-leak scan of embedded output, client route-guard coverage, required response headers/CSP, and raw-HTML (XSS) sink allowlisting.
- An integration-test framework (
test {}blocks → generatedhttptesttests) that verifies the runtime matches the declared posture.
Non-Goals
- Owning authentication, sessions, RBAC storage, or backend resource authorization — those stay in app Go. Guards and audits are defense-in-depth.
- Running generated-app audit tests as part of
gowdk build. The build command runs the static baseline gate, but runtime audit tests stay explicit throughgowdk audit --run. - Browser/E2E testing or testing user domain logic.
- Full data-flow/taint analysis of raw-HTML sinks (M8 flags sinks; it does not trace tainted inputs).
Users And Permissions
- Primary users: app authors and reviewers (human or LLM) who need a trustworthy, one-glance security posture and a CI gate.
- The audit reads guard/CSRF/body-limit/contract-role metadata already in the IR; it grants no access and changes no runtime behavior.
Trust Model
Three-way consistency: declared policy ⟷ static posture (from IR) ⟷ runtime
behavior (integration tests) must agree. gowdk audit checks policy-vs-static;
gowdk audit --run adds runtime-vs-declared. Severity for every finding comes
only from the diagnostic registry, so the baseline never hardcodes severity.
Anti-Magic Guarantees
- The posture manifest is a pure projection (like
gowdk-routes.json); it describes, never acts. gowdk buildruns only the static baseline gate. The full report surface and generated runtime audit tests stay explicit throughgowdk audit.- Every finding cites a named rule, a diagnostic code, and a source
file:line;gowdk explain <code>gives the reasoning. - The baseline is the gates already written in
security.md, made executable — not new hidden policy. - Integration tests are emitted as readable
_test.gofiles the user owns; the generated app audit test is the runtime truth. The--runconvenience builds a temporary generated app and runs that app's generated audit test.
Acceptance Criteria
gowdk-security.jsonis emitted to a non-served build report path and bygowdk audit --json.gowdk auditapplies the baseline, cites findings by code +file:line, and exits non-zero on error findings.- New
audit_*/policy_*codes are registered andgowdk explain-able. - Frontend audits (secret leak, route-guard coverage, headers/CSP, raw-HTML).
*.audit.gwdkparser → IR → composable policy engine (extends, selectors).test {}blocks → generatedhttptesttests;gowdk audit --emit-testsand--run;runtime/appsecurity-header capability.
Delivery Phases
- Phase 0–1 (shipped in this slice): diagnostic codes;
internal/auditspec(composable policy model, selector matcher,extends, baseline, engine);internal/securitymanifest(IR → posture);gowdk auditwith the baseline;gowdk-security.jsonat build time outside the served output directory. Unit- CLI tests.
- Phase 2 (shipped): the four frontend audits as baseline rules.
- Phase 3 (shipped): the
*.audit.gwdkfile kind and declared composable policies. - Phase 4 (shipped):
runtime/testkit, generated_test.go, standalone--emit-tests, generated-app--run, and theruntime/appsecurity-header capability.
Issue Alignment
Advances/closes #179 (IR-driven test harness; Phase 4 testkit). Relates to #120 (CSRF tests), #119 (fail-closed secret), #67 (testing umbrella), #182 (features from IR metadata), and diagnostics issues #328/#255/#107/#109.
Verification
go build ./cmd/gowdk
go test ./internal/securitymanifest ./internal/auditspec ./internal/parser ./internal/lang ./internal/appgen ./runtime/app ./runtime/testkit ./cmd/gowdk ./internal/diagnostics
go run ./cmd/gowdk audit --json --config gowdk.config.go
go run ./cmd/gowdk audit --emit-tests --run --config gowdk.config.go
go run ./cmd/gowdk explain audit_api_public_by_omission
go run ./cmd/gowdk build --out /tmp/gowdk-build examples/pages/home.page.gwdk \
examples/pages/hero.cmp.gwdk && test -f /tmp/.gowdk/reports/gowdk-build/gowdk-security.json