Skip to content

test(web): hold every HTTP route to a declared auth expectation - #759

Merged
CybotTM merged 1 commit into
mainfrom
test/route-auth-boundary
Jul 28, 2026
Merged

test(web): hold every HTTP route to a declared auth expectation#759
CybotTM merged 1 commit into
mainfrom
test/route-auth-boundary

Conversation

@CybotTM

@CybotTM CybotTM commented Jul 28, 2026

Copy link
Copy Markdown
Member

The authorization boundary was one prefix rule plus an allowlist inside
authMiddleware: anything under /api/ needs a token, everything else does
not. A route registered outside /api/ therefore shipped reachable without a
token and nothing failed. The two registration sites — NewServerWithAuth and
RegisterHealthEndpoints — each built their own mux, so neither a reviewer nor
a test saw the whole surface at once.

This extracts the routes into one table both sites consume, with an explicit
public flag per entry, and tests it four ways:

Test Closes
TestRouteAuthExpectations replays every route through the real middleware chain; 401 without a token unless declared public
TestPublicRoutesAreExactlyDeclared pins the public set to a literal list, so widening the token-free surface is a deliberate edit
TestRouteRegistrationIsCentralized a route registered outside the table — including inside newMux — would escape the replay
TestAuthMiddlewarePathDecisionsMatchAllowlist a handler served from the middleware itself, never registered on a mux

No route changed its reachability. The table records what the code already
did; the flags were read off the existing behaviour.

Verification

Each gate was verified by breaking it, not by assuming it works:

  • marking /api/jobs/delete public → TestRouteAuthExpectations//api/jobs/delete and TestPublicRoutesAreExactlyDeclared both fail
  • registering /sneaky inside newMux"newMux registers a route outside the route table", with the file and line
  • adding a /backdoor path check to authMiddleware → the allowlist diff names /backdoor

go test ./web/ passes and golangci-lint reports 0 issues on the package.

Copilot AI review requested due to automatic review settings July 28, 2026 16:43
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions github-actions Bot added the tests label Jul 28, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown

✅ Mutation Testing Results

Mutation Score: 80.00% (threshold: 60%)

✨ Good job! Mutation score meets the threshold.

What is mutation testing?

Mutation testing measures test quality by introducing small changes (mutations) to the code and checking if tests detect them. A higher score means better test effectiveness.

  • Killed mutants: Tests caught the mutation (good!)
  • Survived mutants: Tests missed the mutation (needs improvement)

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.83673% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.72%. Comparing base (0173f1d) to head (6390d30).

Files with missing lines Patch % Lines
web/server.go 91.83% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #759      +/-   ##
==========================================
+ Coverage   87.64%   87.72%   +0.07%     
==========================================
  Files          90       90              
  Lines       12054    12057       +3     
==========================================
+ Hits        10565    10577      +12     
+ Misses       1198     1191       -7     
+ Partials      291      289       -2     
Flag Coverage Δ
integration 87.72% <91.83%> (+0.07%) ⬆️
unittests 85.25% <91.83%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@CybotTM

CybotTM commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Blocked on #756, not by anything in this branch.

go-check / gosec became blocking in the shared workflow (netresearch/.github#312), and main currently carries three findings — two auth cookies whose Secure is derived from the request scheme, and a password marshal the Docker API requires. #756 annotates all three and passes gosec.

Verified this branch adds none of its own: gosec on main and on this branch report the same findings in the same files, shifted only by the added lines. Merging #756 first turns this green on rebase.

The authorization boundary was one prefix rule plus an allowlist inside
authMiddleware: anything under /api/ needs a token, everything else does not.
A route registered outside /api/ therefore shipped reachable without a token
and nothing failed. The two registration sites — NewServerWithAuth and
RegisterHealthEndpoints — each built their own mux, so neither the reviewer nor
a test saw the whole surface at once.

Extract the routes into one table that both sites consume, with an explicit
public flag per entry, and test the table four ways:

  - every route is replayed through the real middleware chain and must answer
    401 without a token unless it declares itself public
  - the set of public routes is pinned to a literal list, so widening the
    token-free surface means editing the test on purpose
  - registering a route anywhere other than through the table fails, including
    inside newMux, which would otherwise escape the replay
  - authMiddleware may not dispatch on a path beyond its declared exemptions,
    closing the variant where a handler is served from the middleware itself
    and never registered on a mux at all

No route changed its reachability; the table records what the code already did.

Each of the four was verified by breaking it: marking /api/jobs/delete public,
registering /sneaky inside newMux, and adding a /backdoor path check to
authMiddleware each produce exactly the finding they should, naming the route.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
@CybotTM
CybotTM force-pushed the test/route-auth-boundary branch from 888dfda to 6390d30 Compare July 28, 2026 17:41
@sonarqubecloud

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

@CybotTM
CybotTM added this pull request to the merge queue Jul 28, 2026
Merged via the queue into main with commit 39c7130 Jul 28, 2026
27 checks passed
@CybotTM
CybotTM deleted the test/route-auth-boundary branch July 28, 2026 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants