Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions internal/router/healthz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ func TestHealthzShape(t *testing.T) {
app.Get("/healthz", func(c *fiber.Ctx) error {
m := reader.Get(c.UserContext())
uptimeSeconds := int64(time.Since(fixedStart).Seconds())
// BUG-API-300: mirror the router.go stamp of
// Cache-Control: no-store so the wire-contract assertion
// below catches a future regression that drops the header.
c.Set(fiber.HeaderCacheControl, "no-store")
return c.JSON(fiber.Map{
"ok": true,
"service": "instanode-api",
Expand Down Expand Up @@ -145,6 +149,16 @@ func TestHealthzShape(t *testing.T) {
require.Equal(t, float64(int64(uptimeRaw)), uptimeRaw,
"BUG-P272: uptime_seconds must round to an integer; got %f", uptimeRaw)

// BUG-API-300 (QA 2026-05-29): /healthz is the rule-14 build-SHA
// gate surface. Without a Cache-Control directive every intermediary
// (CF edge, browser fetch cache, NR synthetic) may return a stale
// commit_id for seconds-to-minutes after a rollout, silently breaking
// the "did the new image actually land" verification. Pin
// `no-store` here so any future deletion of the header on the
// router.go path fails this assertion before merge.
require.Equal(t, "no-store", resp.Header.Get("Cache-Control"),
"BUG-API-300: /healthz must stamp Cache-Control: no-store so build-SHA reads never come from a cached layer")

require.NoError(t, mock.ExpectationsWereMet())
}

Expand Down
11 changes: 11 additions & 0 deletions internal/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,17 @@ func NewWithHooks(cfg *config.Config, db *sql.DB, rdb *redis.Client, geoDbs *mid
// jitter has no diagnostic value at this surface and would defeat
// HTTP-cache deduplication if anyone proxies the response.
uptimeSeconds := int64(time.Since(processStartFunc()).Seconds())
// BUG-API-300 (QA 2026-05-29): /healthz is the canonical surface
// the rule-14 build-SHA gate reads after every deploy. Without a
// Cache-Control hint, any intermediary (Cloudflare edge, browser
// fetch cache, kubectl-port-forward'd browser tab, NR synthetic
// monitor) may return a stale commit_id read for seconds-to-minutes
// after a rollout — silently breaking the "did the new image
// actually land" verification. Stamp `no-store` so probes always
// hit the live pod. Cost: a few hundred bytes of header per probe;
// upside: zero stale build-SHA reads, matching the contract canaries
// already assume. Pairs with the OPTIONS shim above.
c.Set(fiber.HeaderCacheControl, "no-store")
return c.JSON(fiber.Map{
"ok": true,
"service": "instanode-api",
Expand Down
Loading