Finding
websiteUrl() in src/lib/profile-links.mjs resolves the free-text blog
field of a third-party GitHub profile — copied verbatim into
data/community-people.json by scripts/fetch-community-people.mjs and
committed unedited by the scheduled refresh workflow. It is the one place on
the site that turns untrusted third-party text into an href.
Three of its arms are exercised by unit tests but never by a browser, because
no record in the checked-in data has the shape that reaches them:
51 if (typeof value !== 'string') return null; // blog absent / not a string
55 const candidate = /^[a-z][a-z0-9+.-]*:/i.test(trimmed)
56 ? trimmed
57 : `https://${trimmed}`; // bare host, resolved not concatenated
62 } catch { // parses as a scheme, not as a URL
63 return null;
Every real blog value is either "" or an absolute http(s):// URL, so the
no-scheme arm, the parser rejection and the non-string guard are not merely
untested end to end — against the shipped data they are unreachable. The
no-scheme arm is the one that matters most: it is why
trusted.example@attacker.example resolves to a URL whose authority is the
real host instead of being concatenated into a link whose visible prefix and
real authority disagree.
Evidence and provenance
- Unit:
TZ=UTC node tests/tools/coverage-report.mjs at main 900592b
(node v26.10.0, run locally 2026-10-04) reports src/lib/profile-links.mjs
at 100.00% lines / 100.00% regions; tests/profile-links.test.mjs
covers all three arms directly. This is a unit-covered path.
- End-to-end: job
End-to-end coverage, workflow Validate repository,
run 37164361552
attempt 1, revision 900592b; artifact e2e-coverage (id 11289266192),
report.json; manifest runId 37164361552-1, status: passed,
sealedAt 2026-10-04T00:19:14Z. It puts the file at 100.00% lines /
57.14% regions, uncovered region lines 11 31 33 51 55 62.
- Reproduced locally at the same revision:
npm run build:e2e:coverage,
then the full Playwright suite under E2E_COVERAGE=1 (298 passed), rendered
with tests/tools/e2e-coverage-report.mjs. src files comes out at
379/469 regions (80.81%) against CI's 379/468 (80.98%), and
profile-links.mjs is identical in both at 57.14% with the same uncovered
region lines.
Priority 2 under the coverage-evidence rules: covered by unit tests, not by
end-to-end tests.
Caveat on the meter
The percentage in that report is under active correction — #1035 and #1051
show the region union carrying zero-count spans over lines that demonstrably
ran. The reliable signal for this finding is the covered-region count,
which rises when a branch is genuinely reached, not the ratio.
Recommendation
Give the coverage build the three missing shapes through the existing overlay
mechanism (tests/e2e/fixtures/data/community-people.json, applied by
tests/tools/e2e-data-fixtures.cjs under E2E_COVERAGE=1 only, never by
npm run build:production), and assert each rendered outcome in
tests/e2e/data-fixtures.spec.js:
- a profile with no
blog at all → no Website anchor;
- a profile whose
blog is a bare host → a Website anchor whose href is
https://<host>/, i.e. resolved rather than concatenated;
- a profile whose
blog opens with a scheme but does not parse → no anchor
rather than a dead one.
Completion criteria
Priority
- Impact: medium (the one place untrusted third-party text becomes an href, with its anti-spoofing arm unexercised in a browser)
- Effort: low
🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5n31 | SHA: 900592b
— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88
Finding
websiteUrl()insrc/lib/profile-links.mjsresolves the free-textblogfield of a third-party GitHub profile — copied verbatim into
data/community-people.jsonbyscripts/fetch-community-people.mjsandcommitted unedited by the scheduled refresh workflow. It is the one place on
the site that turns untrusted third-party text into an
href.Three of its arms are exercised by unit tests but never by a browser, because
no record in the checked-in data has the shape that reaches them:
Every real
blogvalue is either""or an absolutehttp(s)://URL, so theno-scheme arm, the parser rejection and the non-string guard are not merely
untested end to end — against the shipped data they are unreachable. The
no-scheme arm is the one that matters most: it is why
trusted.example@attacker.exampleresolves to a URL whose authority is thereal host instead of being concatenated into a link whose visible prefix and
real authority disagree.
Evidence and provenance
TZ=UTC node tests/tools/coverage-report.mjsatmain900592b(node v26.10.0, run locally 2026-10-04) reports
src/lib/profile-links.mjsat 100.00% lines / 100.00% regions;
tests/profile-links.test.mjscovers all three arms directly. This is a unit-covered path.
End-to-end coverage, workflowValidate repository,run 37164361552
attempt 1, revision 900592b; artifact
e2e-coverage(id 11289266192),report.json; manifestrunId 37164361552-1,status: passed,sealedAt 2026-10-04T00:19:14Z. It puts the file at 100.00% lines /57.14% regions, uncovered region lines
11 31 33 51 55 62.npm run build:e2e:coverage,then the full Playwright suite under
E2E_COVERAGE=1(298 passed), renderedwith
tests/tools/e2e-coverage-report.mjs.src filescomes out at379/469 regions (80.81%) against CI's 379/468 (80.98%), and
profile-links.mjsis identical in both at 57.14% with the same uncoveredregion lines.
Priority 2 under the coverage-evidence rules: covered by unit tests, not by
end-to-end tests.
Caveat on the meter
The percentage in that report is under active correction — #1035 and #1051
show the region union carrying zero-count spans over lines that demonstrably
ran. The reliable signal for this finding is the covered-region count,
which rises when a branch is genuinely reached, not the ratio.
Recommendation
Give the coverage build the three missing shapes through the existing overlay
mechanism (
tests/e2e/fixtures/data/community-people.json, applied bytests/tools/e2e-data-fixtures.cjsunderE2E_COVERAGE=1only, never bynpm run build:production), and assert each rendered outcome intests/e2e/data-fixtures.spec.js:blogat all → no Website anchor;blogis a bare host → a Website anchor whosehrefishttps://<host>/, i.e. resolved rather than concatenated;blogopens with a scheme but does not parse → no anchorrather than a dead one.
Completion criteria
blog, one with a bare-hostblog, and one with an unparseableblogtests/e2e/data-fixtures.spec.jsasserts the rendered outcome of each in a browsersrc/lib/profile-links.mjsrisesnpm run build:productionis unchanged — the overlay stays out of what the site shipsPriority
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5n31| SHA:900592b— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88