Skip to content

feat(frontend): serve RFC 9116 security.txt at /.well-known/security.txt - #7

Open
JRojowski wants to merge 9 commits into
mainfrom
work/001-security-txt
Open

feat(frontend): serve RFC 9116 security.txt at /.well-known/security.txt#7
JRojowski wants to merge 9 commits into
mainfrom
work/001-security-txt

Conversation

@JRojowski

Copy link
Copy Markdown
Collaborator

Summary

Adds a new public HTTP endpoint to the frontend service: GET /.well-known/security.txt, returning an RFC 9116-compliant response.

RFC 9116 requires exactly two fields; this endpoint emits only those:

  • Contact (required, §2.5.3) — mailto:security@example.com (demo placeholder).
  • Expires (required, §2.5.5) — computed at request time as now + 1 year (RFC 3339), so it never goes stale and always satisfies the <1-year recommendation.

All optional/recommended fields (Encryption, Acknowledgments, Preferred-Languages, Canonical, Policy, Hiring) are intentionally omitted. Response is served with an explicit Content-Type: text/plain; charset=utf-8.

Implementation

  • Extracted a testable seam: package-level securityTxtHandler + registerSecurityTxtRoute(r, baseUrl), called by both main() and tests (so httptest runs without dialing gRPC backends).
  • 7 Given-When-Then httptest scenarios (T-001…T-007) pin status, Content-Type, both fields, RFC 3339 freshness, only-required-fields, line shape, and routing exactness.
  • Registered with an exact HandleFunc path (not PathPrefix), mirroring the existing robots.txt/_healthz handlers.

Verification

  • cd src/frontend && go build ./... && go test ./... — green (107 tests).
  • Live e2e smoke PASS on a kind cluster via skaffold runcurl -i returned 200, correct Content-Type, Contact, and a future RFC 3339 Expires. Evidence in docs/test/001-security-txt/.

Pipeline artifacts

Spec-driven pipeline (research → tests → plan → execute → docs): docs/work/001-security-txt/.

Docs reconcile: no drift — no doc enumerates frontend routes (consistent with the undocumented robots.txt/_healthz), so no doc changes were needed.

Squash-merge to main; team reviews and merges manually.

JRojowski and others added 9 commits July 16, 2026 12:22
* fix(checkoutservice): use %s verb in status.Errorf for error message

go 1.26's go vet rejects passing a non-constant string (err.Error()) as the
format argument to status.Errorf. Pass it via %s so the error can never be
misinterpreted as a format string. Surfaced while wiring the dev-kit quality
gate (go test ./... runs vet).

* chore(dev-kit): bootstrap spec-driven pipeline (vendor runtime + configure quality gate, workflow anchor, e2e runbook)

Vendor the dev-kit runtime (v0.5.5) into the repo so every teammate gets the
pipeline on git pull with no per-user setup:
- .claude/skills/{dev-kit,work-*}, .claude/agents/{coder,e2e-tester},
  .claude/hooks/quality-gate.sh, dev-kit.manifest
- Routed quality gate (.claude/quality-gate.routes): per-service Go + C# build/test
  (shipping, productcatalog, frontend, checkout, cartservice) + protos composite;
  Node/Python/Java left to each task's acceptance check (not CI-tested).
- CLAUDE.md workflow anchor + per-service Commands + Structure.
- docs/test/README.md e2e runbook: full-stack skaffold bring-up + per-service smokes.
- Branch-per-unit + squash-PR policy.
Extract package-level securityTxtHandler + registerSecurityTxtRoute so
the route can be exercised via httptest without running main() or dialing
gRPC backends. Placeholder body only; compliant response follows.

Refs docs/work/001-security-txt (P3-01, P3-02).
Given-When-Then httptest coverage for T-001..T-007 against a router built
via registerSecurityTxtRoute (no main(), no gRPC). Expected-red: T-003..T-006
fail against the placeholder body until the handler is implemented; T-001/T-002/
T-007 already pass (routing + content sniffing).

Refs docs/work/001-security-txt (P3-03).
Emit the two required fields — Contact (mailto:security@example.com) and a
computed Expires (now + 1 year, RFC 3339) so it never goes stale — with an
explicit Content-Type: text/plain; charset=utf-8. Turns T-002..T-006 green.

Refs docs/work/001-security-txt (P3-04).
No code changes needed; frontend build + full test suite green (107 tests),
gofmt clean on main.go and security_txt_test.go.

Refs docs/work/001-security-txt (P3-05).
Brought up the full stack via skaffold on a kind cluster and curled
GET /.well-known/security.txt through the frontend: 200, Content-Type
text/plain; charset=utf-8, Contact + future RFC 3339 Expires present.

Refs docs/work/001-security-txt (P3-06).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant