Skip to content

Spec versions page lists deleted branches: GitHub filter fails open #249

Description

@jgeluk

Symptom

https://ekgf.org/dprod/spec-versions/ advertises 22 branches while only 6 pull requests are open. Eleven of the listed branches no longer exist in the repository at all:

add-dprod-contracts, agent/github-issues-source-of-truth, complete-dprod-migration, contracts/lifecycle-abstract-and-reject-5.8-5.9, dependabot/…/deploy-pages-5, dependabot/…/upload-pages-artifact-5, DPROD-64, issue/214-lifecycle-status-model, issue/215-reject-odrl-request, ns-dprod-segment, spec-latestversion-iri

Not a staleness problem

The page updates correctly: a branch pushed minutes ago appears while develop has not been redeployed, so ISR and the Vercel deployments API both work. ekgf-website is also not involved — its src/middleware.ts rewrites /dprod/* verbatim to the dprod zone and holds no version logic.

Cause

fetchActiveBranches() in site/src/lib/spec-versions.ts is failing, and the caller is written to fail open:

// Fail open: when the GitHub lookup failed, keep every branch.
if (activeBranches && !activeBranches.has(branch)) continue;

GITHUB_TOKEN appears in exactly one line of the repository (spec-versions.ts:121) with no .env.example, no documentation and no workflow that sets it, while the VERCEL_* variables are clearly provisioned since deployment discovery works. Authentication is optional in the code:

if (token) headers.Authorization = `Bearer ${token}`;

so without the token the request runs unauthenticated, where GitHub permits 60 requests/hour per IP shared across Vercel's serverless egress. That is exhausted continuously → non-2xx → null → every branch is kept.

(The Vercel project's environment variables could not be read directly to confirm the token is absent, so this last step is inferred. Every observable is consistent with it, and nothing else explains a persistent filter failure alongside working Vercel API calls.)

Three defects, not one

  1. The token is treated as optional when the unauthenticated path cannot work in production.
  2. The failure is silent — no log, no signal, no degraded-state indicator. It has been broken indefinitely with nothing to notice.
  3. The predicate is wrong. Open-PR status is not the question. issue/241-doc-metadata-drift exists upstream but has no open PR, so even a working token would hide it; conversely the eleven branches above are gone from the repository entirely. Branch existence is what the picker actually means.

Fix

  • Replace the open-PR lookup with GET /repos/EKGF/dprod/branches, paginated.
  • Require GITHUB_TOKEN and console.warn when it is missing or the lookup fails.
  • Split the two consumers, which need opposite failure behaviour:
    • getSpecVersions() stays permissive for middleware routing — a preview URL already handed out must keep resolving during a GitHub outage;
    • getListedSpecVersions() fails closed for the picker, showing only the archive and develop when existence cannot be determined.
  • Exclude dependabot/*: a dependency bump produces a valid preview deployment but is not a version of the specification.
  • Document the variables in site/.env.example and site/README.md.

Simulated against live data, the listing goes from 23 entries to 8 plus the archive, with every drop attributable to a deleted branch or a dependency bump.

GITHUB_TOKEN still has to be set on the Vercel project — a fine-grained token needs only Metadata: Read-only on EKGF/dprod. Until it is, the picker will correctly show just the archive and develop, and log why.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions