fix(checks): read files through Gitea's contents endpoint, not raw
The three checks that read another repository -- checkFacts, checkQuickstart,
checkReference -- fetched source files from the API's `raw` route, which answers
`Cache-Control: public, max-age=21600`. The CDN in front of Gitea caches that,
so the checks can read a blob most of a working day old.
It bit on cutover day. checkFacts reported
FAIL moduleApi
platform.json says : 1.9.0
website main:server/src/modules/version.js says : 1.6.0
against a `main` that says 1.9.0 -- the served copy was two weeks old
(`cf-cache-status: HIT`, `Age: 15713`, `last-modified: 18 Aug`). No edit in this
repository could have made it pass, and the same run reported a bundle triple
that had already been republished as still current: a stale read fails BOTH
ways, and the false pass is the dangerous one.
The `contents` endpoint answers `private, must-revalidate`, which the CDN
bypasses, so it is always the ref's current blob. The cost is a JSON parse and a
base64 decode. checkReference's canonical-document existence loop already used
it, which is why that half was never affected.
PLAN.md 12 records the finding next to the check it constrains.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -60,8 +60,28 @@ async function api(pathname) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const raw = async (repo, filePath, ref) =>
|
||||
(await api(`${repo}/raw/${filePath}?ref=${encodeURIComponent(ref)}`)).text();
|
||||
/**
|
||||
* A file's bytes, read through the `contents` endpoint rather than `raw`.
|
||||
*
|
||||
* `raw` answers with `Cache-Control: public, max-age=21600`, so the CDN in front of Gitea
|
||||
* serves a copy for six hours and this check can read a blob most of a working day old.
|
||||
* That is not theoretical: on the day of the engagement cutover it reported website's
|
||||
* MODULE_API_VERSION as 1.6.0 -- the value from two weeks earlier -- and failed a site
|
||||
* whose number was right. A check that goes red on stale data is a check people learn to
|
||||
* ignore, which is the one failure mode this file exists to avoid.
|
||||
*
|
||||
* `contents` answers `private, must-revalidate`, which the CDN does not cache, so it is
|
||||
* always the ref's current blob. The cost is a JSON parse and a base64 decode.
|
||||
*/
|
||||
async function raw(repo, filePath, ref) {
|
||||
const meta = await json(`${repo}/contents/${filePath}?ref=${encodeURIComponent(ref)}`);
|
||||
if (meta.encoding !== 'base64' || typeof meta.content !== 'string') {
|
||||
throw new Error(
|
||||
`${repo}:${filePath}@${ref} did not come back as a base64 file (encoding ${meta.encoding}).`
|
||||
);
|
||||
}
|
||||
return Buffer.from(meta.content, 'base64').toString('utf8');
|
||||
}
|
||||
|
||||
const json = async (pathname) => (await api(pathname)).json();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user