Public: anyone can read this; the crew can change it.
Sentinel: release was degraded 30 minutes today: Release 0.7.475 is unproven: the public URL never answered as 0.7.475. It is proven again at 11:44 UTC. #10187
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/10184-sentinel-release-was-degraded-30-minutes → main 1 commit fork 1 thread · 1 unresolved
2 files
changed +16
−1
src/release/prove.ts +2 −1
| @@ -172,7 +172,8 @@ export async function proveRelease(o: ProveOptions): Promise<Proof | undefined> | ||
| 172 | 172 | let seen = ""; |
| 173 | 173 | for (;;) { |
| 174 | 174 | try { |
| 175 | const res = await doFetch(health, { redirect: "manual", headers: ownProbeHeaders(o.dataDir), signal: AbortSignal.timeout(5_000) }); | |
| 175 | // Each ask is a fresh URL and says no-cache, so a proxy or edge holding an older /healthz answer cannot stand for the public URL (#10184). | |
| 176 | const res = await doFetch(`${health}?proof=${now()}`, { redirect: "manual", cache: "no-store", headers: { ...ownProbeHeaders(o.dataDir), "cache-control": "no-cache" }, signal: AbortSignal.timeout(5_000) }); | |
| 176 | 177 | await res.body?.cancel(); |
| 177 | 178 | seen = res.headers.get("x-forge-version") ?? ""; |
| 178 | 179 | if (seen === o.version) break; |
test/release-prove.test.ts +14
| @@ -103,6 +103,20 @@ describe("proving a release", () => { | ||
| 103 | 103 | expect(proofNeed(dir)).toBeUndefined(); |
| 104 | 104 | }); |
| 105 | 105 | |
| 106 | test("each ask of the public URL is uncacheable (#10184)", async () => { | |
| 107 | const seen: { url: string; cc: string | null }[] = []; | |
| 108 | const { fake } = site("1.0.0"); | |
| 109 | const spy = (async (input: string | URL, init?: RequestInit) => { | |
| 110 | if (new URL(String(input)).pathname === "/healthz") seen.push({ url: String(input), cc: new Headers(init?.headers).get("cache-control") }); | |
| 111 | return fake(input, init); | |
| 112 | }) as unknown as typeof fetch; | |
| 113 | await run("1.0.0", spy); | |
| 114 | expect(seen.length).toBeGreaterThan(0); | |
| 115 | const polls = seen.filter((h) => h.url.includes("?proof=")); | |
| 116 | expect(polls.length).toBeGreaterThan(0); | |
| 117 | expect(polls.every((h) => h.cc === "no-cache")).toBe(true); | |
| 118 | }); | |
| 119 | ||
| 106 | 120 | test("it gives up after 10 minutes as unproven", async () => { |
| 107 | 121 | let t = 0; |
| 108 | 122 | const old = site("0.9.0"); // the old version keeps answering |
new above
offline
Fine as written. Optionally, keep
seenand the responseage/viaheaders for the give-up message so a repeat degradation shows its cause.