Skip to content

fix(server): serve /version on Lambda (excluded from static-path fallback) - #916

Merged
cristim merged 1 commit into
feat/multicloud-web-frontendfrom
fix/version-endpoint-lambda-static-shadow
Jun 2, 2026
Merged

cristim merged 1 commit into
feat/multicloud-web-frontendfrom
fix/version-endpoint-lambda-static-shadow

Conversation

@cristim

@cristim cristim commented Jun 2, 2026 •

Copy link
Copy Markdown
Member

Root cause

isStaticPath() in internal/server/static.go only excluded /api/* and
/health from the SPA file-server fallback. /version was not in the
allowlist, so on the Lambda Function URL path (handleLambdaHTTPEvent) the
check isStaticPath("/version") == true caused the request to be routed to
serveLambdaStatic, which served index.html instead of JSON.

The HTTP / Cloud Run / Fargate path (CreateHTTPServer in
internal/server/http.go) was unaffected because mux.HandleFunc("/version", app.handleVersion) is registered explicitly before the SPA catch-all handler,
so the Go ServeMux routes it correctly regardless of isStaticPath.

The /version route has been in the API router table since PR #901
(ExactPath: "/version", Auth: AuthPublic). Once isStaticPath("/version")
returns false, app.API.HandleRequest handles it correctly on the Lambda path
too.

Verified live before the fix:

curl https://33pz7pombdqwu3bdlxp4lqxyra0bsriy.lambda-url.us-east-1.on.aws/version
# returned text/html (index.html)

Fix

Add clean == "/version" to the isStaticPath allowlist using the same
pattern as /health. Updated the function doc comment to mention /version as
a public root-path endpoint and explain why it must bypass the SPA fallback.

Tests

Added two cases to TestIsStaticPath in internal/server/static_test.go:

  • {"/version", false} - direct path
  • {"//version", false} - double-slash input normalised by path.Clean

All 334 tests in ./internal/server/... pass. gofmt and go vet clean.

Notes

No issue to close - discovered during deploy debugging of the #901 build-version
diagnostic endpoint on a Lambda Function URL deployment. Behaviour is now
consistent across all deployment targets (Lambda, Cloud Run, Fargate).

Summary by CodeRabbit

  • Bug Fixes
    • Corrected routing logic to ensure the /version endpoint is properly directed to the API handler instead of incorrectly falling through to static content serving.

…h fallback

isStaticPath() only excluded /api/* and /health, so /version was falling through
to the SPA file server on the Lambda Function URL path, returning index.html
instead of the JSON build-metadata response added by PR #901. The HTTP/Cloud Run
path was unaffected because mux.HandleFunc("/version", ...) is registered before
the SPA catch-all in CreateHTTPServer.

Add /version to the isStaticPath allowlist (same pattern as /health) so
handleLambdaHTTPEvent routes it to app.API.HandleRequest, which already handles
it correctly via the ExactPath:/version AuthPublic router entry.

Also add test cases for /version and //version (double-slash normalised) to
TestIsStaticPath.
@cristim cristim added triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/this-sprint Within the current sprint impact/internal Team-internal only effort/xs Trivial / one-liner type/bug Defect labels Jun 2, 2026
@cristim

cristim commented Jun 2, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates static-path routing logic to explicitly treat /version as an API endpoint that must not fall through to the SPA static/Lambda fallback. Documentation is clarified, the isStaticPath function adds an explicit check for /version, and tests are updated to verify the endpoint is non-static.

Changes

Version Endpoint Routing

Layer / File(s) Summary
Exclude /version from static path handling
internal/server/static.go, internal/server/static_test.go
Documentation in isStaticPath clarifies that /version is a public root-path endpoint handled by the API router and must not fall through to SPA/Lambda fallback. Logic adds an explicit clean == "/version" check to exclude it from static handling. Tests assert /version and //version are non-static paths.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related PRs

  • LeanerCloud/CUDly#901: Complements this routing exclusion by adding the actual /version handler and public auth allowlisting for it.

Suggested labels

priority/p2

Poem

🐰 A /version that wandered too far,
Down static paths beneath the stars,
Now rooted firm in API's keep,
No SPA fallback, promises to keep!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing the /version endpoint routing to exclude it from the static-path fallback on Lambda, which matches the core fix in the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/version-endpoint-lambda-static-shadow

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/server/static_test.go (1)

97-98: 💤 Low value

Consider adding a trailing-slash test case for completeness.

The test cases correctly verify that /version and //version are non-static. For more comprehensive coverage, consider adding {"/version/", false} to confirm that path.Clean("/version/") → "/version" also bypasses the SPA fallback.

📋 Optional test case addition
 		{"/version", false},  // public build-metadata endpoint must reach API, not SPA
 		{"//version", false}, // double-slash normalised to /version
+		{"/version/", false}, // trailing slash normalised to /version
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/server/static_test.go` around lines 97 - 98, Add a trailing-slash
case to the static handler tests: update the test cases slice in
internal/server/static_test.go (the table that currently contains {"/version",
false} and {"//version", false}) to include {"/version/", false} so the test
verifies path.Clean("/version/") → "/version" still bypasses the SPA fallback;
ensure the new entry uses the same expected boolean and test logic as the other
non-static cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/server/static_test.go`:
- Around line 97-98: Add a trailing-slash case to the static handler tests:
update the test cases slice in internal/server/static_test.go (the table that
currently contains {"/version", false} and {"//version", false}) to include
{"/version/", false} so the test verifies path.Clean("/version/") → "/version"
still bypasses the SPA fallback; ensure the new entry uses the same expected
boolean and test logic as the other non-static cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e1763440-febb-478d-b1e1-bc2254ddd7e2

📥 Commits

Reviewing files that changed from the base of the PR and between 80c20d2 and 647b111.

📒 Files selected for processing (2)
  • internal/server/static.go
  • internal/server/static_test.go

@cristim
cristim merged commit 787f95d into feat/multicloud-web-frontend Jun 2, 2026
4 checks passed
@cristim
cristim deleted the fix/version-endpoint-lambda-static-shadow branch June 3, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/xs Trivial / one-liner impact/internal Team-internal only priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant