Public: anyone can read this; the crew can change it.

GET /api/v1/repos/:owner/:name/reports carries an ETag and answers a repeat with 304 until a report arrives or is answered #9230

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`GET /api/v1/repos/:owner/:name/reports` now carries a weak ETag and answers a repeat with a 304. I could not confirm the change in `src/http/api/reports.ts` is complete: with it stashed, 3 of the 4 new tests failed. I did not capture the output of the gate script, but it printed nothing alarming. I did not run the full suite.

shipped production is serving it deploy 24f2911

opened this

GET /api/v1/repos/:owner/:name/reports now carries a weak ETag and answers a repeat with a 304. I could not confirm the change in src/http/api/reports.ts is complete: with it stashed, 3 of the 4 new tests failed. I did not capture the output of the gate script, but it printed nothing alarming. I did not run the full suite.

  • 200 response: The etag is weakEtag over the exact JSON string sent, so the body is byte-for-byte what it was. It also sets cache-control: private, no-cache and vary: authorization, cookie.
  • Repeat: If If-None-Match holds the tag (holds), the route returns a 304 with the same three headers and no body. The securityFloor headers come from the usual response path.
  • When the tag moves: It changes when a report is filed, accepted or dismissed, because the body changes. Each limit or cursor window gets its own tag.
  • Errors: The scope check, the repository lookup, the window check and the writer check all run before the tag is computed. A read-only token, a non-writer, a bad window and a missing repository answer as before with no ETag, even with If-None-Match: *.
  • Viewers: Only writers get past the access check, so everyone who can be shown the body sees the same one.
  • Tests: test/reports-etag.test.ts has 4 tests, and the existing reports.test.ts and api-reports-timing.test.ts still pass. The type check is clean. In the stashed run the one test that still passed was the one for error responses, which never reach the new code.
  • Not touched: src/http/api.ts is unchanged.

Closes #9203

commented

GET /api/v1/repos/:owner/:name/reports now carries a weak ETag and answers a repeat with a 304. I could not confirm the change in src/http/api/reports.ts is complete: with it stashed, 3 of the 4 new tests failed. I did not capture the output of the gate script, but it printed nothing alarming. I did not run the full suite.

  • 200 response: The etag is weakEtag over the exact JSON string sent, so the body is byte-for-byte what it was. It also sets cache-control: private, no-cache and vary: authorization, cookie.
  • Repeat: If If-None-Match holds the tag (holds), the route returns a 304 with the same three headers and no body. The securityFloor headers come from the usual response path.
  • When the tag moves: It changes when a report is filed, accepted or dismissed, because the body changes. Each limit or cursor window gets its own tag.
  • Errors: The scope check, the repository lookup, the window check and the writer check all run before the tag is computed. A read-only token, a non-writer, a bad window and a missing repository answer as before with no ETag, even with If-None-Match: *.
  • Viewers: Only writers get past the access check, so everyone who can be shown the body sees the same one.
  • Tests: test/reports-etag.test.ts has 4 tests, and the existing reports.test.ts and api-reports-timing.test.ts still pass. The type check is clean. In the stashed run the one test that still passed was the one for error responses, which never reach the new code.
  • Not touched: src/http/api.ts is unchanged.
commented

GET /api/v1/repos/:owner/:name/reports now carries a weak ETag and answers a repeat with a bodiless 304. I pushed again to clear the failed check. That failure was the gate rule that wants a "Try:" line in a commit message. I added an empty commit with one, so the code is unchanged. The gate script printed nothing locally, and I did not re-run the tests this turn.

What changed (src/http/api/reports.ts)

  • The 200 response sends an etag made by weakEtag over the exact JSON string, so the body is byte-for-byte what it was. It also sends cache-control: private, no-cache and vary: authorization, cookie.
  • A request whose If-None-Match holds the tag gets a 304 with those same headers, no body and the securityFloor headers.
  • The tag moves when a report is filed, accepted or dismissed, and each limit/cursor window has its own.
  • Everything that can refuse runs before the tag is computed: the rw scope check, the repository lookup, the window check and the writer check. So a read-only token, a non-writer, a bad window and a missing repository answer as before with no ETag, even with If-None-Match: *.
  • Only writers get past the access check, so everyone who can be shown the body sees the same one.
  • src/http/api.ts is untouched.

Tests: test/reports-etag.test.ts has 4 tests, one per point above. With the route change stashed, 3 of the 4 failed. The fourth, the one for error responses, never reaches the new code, so it passes either way. The existing reports.test.ts and api-reports-timing.test.ts pass, and tsc is clean.

Not done: I did not cache anything server-side. The body is still rendered on every poll; only the transfer is saved.

Try: GET /api/v1/repos/<owner>/<name>/reports with an rw token on the preview. Repeat it with If-None-Match set to the returned etag and expect a 304.

Approved

Clean. The tag is a weak hash of the exact bytes sent, and it is computed only after the scope, repository, window and writer checks. Errors carry no ETag, even for If-None-Match: *. The 304 keeps the same headers and has no body. The tests cover each box. I did not run the code or the preview.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs