Skip to content

test: verify local /img static asset references resolve under static/ (tests/static-assets.test.mjs) - #289

Open
kubestellar-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-static-assets
Open

kubestellar-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-static-assets

Conversation

@kubestellar-hive

Copy link
Copy Markdown
Contributor

Test Improvement

Adds one new test-only file, tests/static-assets.test.mjs (6 tests). No
production code, no workflow, no package.json, no lockfile, no dependency —
it uses only node:test, node:assert/strict, node:fs and node:path.

Files claimed by this PR: tests/static-assets.test.mjs (new). Nothing else.

The gap

The site references 83 distinct files under static/ from docs/,
blog/, src/ and the top-level data/*.json files. Nothing verified that
any of them resolve.

The largest group is the logo="/img/cncf-projects/*.svg" props on
<CNCFProjectCard>, hand-authored in docs/architectures/*.md; the component
renders the value straight into an <img src>.

Why the existing gates do not cover it:

  • docusaurus.config.js sets onBrokenLinks: 'throw', but that enforces
    page routes, not static assets. A typo in an absolute /img/... path
    builds clean and ships a broken image.
  • scripts/validate-architecture-assets.mjs checks data/architectures
    assets only; scripts/validate-awards.mjs checks data/awards.json logos
    only. Neither touches docs/, blog/, src/ or the other data files.

A case-only mismatch is the worst variant: /img/Social-card.png resolves
on a case-insensitive developer filesystem and 404s on GitHub Pages, which
serves from a case-sensitive one. existsSync() alone does not catch it, so
the test walks each path segment and compares against the real readdir entry.

What the 6 tests assert

  1. The scan finds references at all — guards against an extraction regression
    silently making the other five tests vacuous.
  2. Every referenced asset exists and is a file.
  3. Referenced assets are non-empty (a zero-byte logo renders as a broken image).
  4. Each reference matches the on-disk name case-exactly.
  5. No reference escapes static/ via ...
  6. Every local CNCFProjectCard logo= prop under docs/ resolves.

Implementation note

The one non-obvious part: absolute and protocol-relative URLs are stripped
before scanning. Without that,
https://raw.githubusercontent.com/cncf/people/main/images/nate-waddington.jpg
yields the token /images/nate-waddington.jpg and is reported as a missing
local asset. Five such false positives exist in the current tree
(blog/authors.yml, data/community-people.json, data/community-roster.json,
and two docs/architectures/*.md files); all are correctly ignored.

References are then filtered to those whose first path segment is a real
top-level entry of static/, so page routes like /awards/ and /metrics
are left to onBrokenLinks.

Verification

Local clone of cncf/endusers at parent revision 00b44df, node v26.8.2,
after npm ci.

  • node --test: 61 pass, 0 fail (55 before; the 6 new tests are additive).
    No existing test, helper or fixture is modified.
  • Mutation-checked. Five independent breakages were each introduced and
    reverted, and each turned the suite red:
    a reference to a nonexistent /img/definitely-missing.png; a case-only
    mismatch /img/Social-card.png; a traversal /img/../../package.json; a
    typo'd CNCFProjectCard logo prop; and truncating a referenced asset to zero
    bytes. git status was clean after each revert.
  • npx prettier --check tests/static-assets.test.mjs clean.

Coverage evidence

  • Unit: node --test --experimental-test-coverage at 00b44df, 2026-09-18.
    Baseline 55 tests; no test file read static/ or scanned docs//blog//src/
    for asset references.
  • End-to-end: unavailable — this repository has no end-to-end or browser
    suite and publishes no coverage artifact from any suite (tracked in [quality] CI publishes no coverage evidence, so coverage findings cannot be verified #186).
    No claim is made that this path lacks end-to-end coverage.

Disjointness

Checked against every open hold-gated PR. This PR claims the static asset
path existence
surface in a new file no other PR touches:

Related Issue

Closes #288


Filed by quality agent (hold-gated mode). Human review required.

— hive: agent=quality backend=copilot model=claude-opus-5

Adds tests/static-assets.test.mjs. The site references 83 distinct files
under static/ from docs/, blog/, src/ and data/*.json, and nothing verified
that any of them resolve.

onBrokenLinks: 'throw' enforces page routes, not static assets, so a typo in
an absolute /img path builds clean and ships a broken image. A case-only
mismatch is worse: it resolves on a case-insensitive developer filesystem and
404s on GitHub Pages.

The scan strips absolute and protocol-relative URLs first, so a remote
https://.../images/foo.jpg is never mistaken for a local /images/foo.jpg.

Closes #288

Signed-off-by: kubestellar-hive[bot] <kubestellar-hive@hive.kubestellar.io>
@kubestellar-hive

Copy link
Copy Markdown
Contributor Author

Important

Held for human review by the hive's ACMM level gate.

This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Non-outreach agents are held at ACMM L3–L5; the outreach agent is always held because it publishes project-facing communication.

Hive will automatically remove the hold label once current policy no longer requires a level hold for "quality". If this is an outreach PR, a human must review it and remove the label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent/quality Approved by a Hive merger/owner for auto-merge on green CI hive/hosted-available-lke648397-260827-5n31 Approved by a Hive merger/owner for auto-merge on green CI hold quality Approved by a Hive merger/owner for auto-merge on green CI testing Approved by a Hive merger/owner for auto-merge on green CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[quality] Nothing verifies that local /img static asset references in docs/, blog/, src/ and data/ resolve under static/

0 participants