Always-public API path check has no refusal test, so a prefix-match regression opens gated routes
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 86/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- express, javascript
- Domain
- authentication, security, testing
Research direction
Start with server/lib/apiAccessPolicy.js and its tests in server/lib/apiAccessPolicy.test.js, then read the auth gate tests in server/services/authGate.test.js. Add the listed exact-path and child-path cases, including a protected-install request without credentials. Run the relevant test files and confirm a prefix-match mutation fails in both; no production code should change.
Written by the indexing model from the issue text.
Description
Slice audited: external auth boundary tests (test-quality audit, 2026-10-18).
Problem
isAlwaysPublicApiPath in server/lib/apiAccessPolicy.js:16 is an exact Set lookup over ALWAYS_PUBLIC_API_PATHS, consumed by isPublicPath in server/services/authGate.js. Its tests only ever use it as a positive disjunct:
server/lib/apiAccessPolicy.test.js:33-38folds it into thereachable()helper; no case asserts it returnsfalsefor anything.server/services/authGate.test.js:87("passes /api/auth/login through") and:95(travel guest) assert the public siblings pass; no case asserts a child or extension of a public path is still gated.
Mutation probe (scratch worktree): replaced the Set lookup with ALWAYS_PUBLIC_API_PATHS.some((p) => path.startsWith(p)) and ran every server suite importing apiAccessPolicy, authGate or systemHealth (69 files).
Test Files 69 passed (69) Tests 1165 passed | 1 skipped (1166)
Impact
On a password-protected install, the mutation makes GET /api/system/health/details (system metrics, app and CoS status, server/routes/systemHealth.js:98) and POST/DELETE /api/system/health/warnings/:type/dismiss (a settings write, :111 and :131) reachable with no credential, because /api/system/health is public and they share its prefix. That is exactly the unauthorized LAN/tailnet caller the instance password exists to refuse, and the suite cannot see the regression. server/lib/sidecarAuthGate.js:92 keeps its own Set, so there is no second production site to change.
Fix (decided)
- In
server/lib/apiAccessPolicy.test.js, add a table case: everyALWAYS_PUBLIC_API_PATHSentry istrue;/api/auth/status-extra,/api/auth/status/,/api/system/health/details,/api/system/health/warnings/x/dismiss, and/api/eidoverse/travel/guest/xarefalse. - In
server/services/authGate.test.js, add one gate-level case: with a password set and no credential,GET /api/system/health/detailsanswers401 AUTH_REQUIREDwhileGET /api/system/healthstill passes. - No production code change.
Scope: small
Acceptance criteria
- Replacing the
Setlookup with astartsWithprefix match fails at least one case in each of the two files. - The gate-level case proves a public path's child is refused on a password-protected install.
- No production code change.
- Dominant language
- JavaScript
- Stars
- 38
- Forks
- 32
- Avg merge
- 34m
- Merged PRs (30d)
- 993
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from atomantic/PortOS
-
effort:medium enhancement model:medium plan
Difficulty 4/5 1-2 days Newbie friendliness 62/100
Maintainers usually reply within 1 day
-
bug effort:high model:heavy plan
Difficulty 4/5 3-5 days Newbie friendliness 43/100
atomantic/PortOS#12748 · 1 comment ·
Maintainers usually reply within 1 day
-
Reconcile dead-owner settlement reservations left by crashed publicationsPossibly taken @atomantic claimed this today. Openbug effort:high in-progress model:medium plan
atomantic/PortOS#12740 · 1 assignee ·
Maintainers usually reply within 1 day
-
CI planner runs the full suite for requirements-only Python pin changesPossibly taken @atomantic claimed this today. Opencode-quality effort:low in-progress model:medium plan
atomantic/PortOS#12739 · 1 assignee ·
Maintainers usually reply within 1 day
-
Worktrees made outside the claim prompt never get dependency links, and a cache-only node_modules blocks a later linkPossibly taken @atomantic claimed this today. Openbug effort:medium in-progress model:medium plan
atomantic/PortOS#12734 · 1 assignee ·
Maintainers usually reply within 1 day
All issues in atomantic/PortOS
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
MagicMirrorOrg/MagicMirror#4310 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
bluerobotics/Cockpit-docs#48 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
tc39/proposal-temporal#3332 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
opennextjs/opennextjs-cloudflare#1461 ·
Maintainers usually reply within 1 day