Skip to content

Activation 1/3: keyless Vercel→Firebase server credentials and health check - #28

Merged
mekado11 merged 1 commit into
mainfrom
claude/relaxed-davinci-045nvi
Sep 23, 2026
Merged

mekado11 merged 1 commit into
mainfrom
claude/relaxed-davinci-045nvi

Conversation

@mekado11

Copy link
Copy Markdown
Owner

Why

Vercel has no Google Application Default Credentials, but server/security/firebase.js calls applicationDefault(). So in production every identity-verified API fails closed with a 503: /api/ai, the five utility APIs, and all /api/v2/*. The redesigned workspace can't load until this is fixed.

firebase-admin's Firestore only accepts a service-account certificate or ADC (firestore-internal.js). A custom credential object would fix Auth but break Firestore. So federation is delivered through ADC.

What

  • server/security/workload-identity.js: when GCP_WORKLOAD_IDENTITY_PROVIDER and GCP_SERVICE_ACCOUNT_EMAIL are set:

    • writes the request's Vercel OIDC token to /tmp/hubcys-wif (0600, atomic) and writes an external_account config that references it;
    • sets GOOGLE_APPLICATION_CREDENTIALS to that config;
    • Google STS then exchanges the token and impersonates a least-privilege runtime service account.

    No key is stored. Partial or malformed config fails closed. It won't override a different operator credential file. With neither variable set, local ADC keeps working unchanged.

  • server/security/identity.js: refreshes the credential only after a syntactically valid bearer token. If credential preparation fails, the result is a 503, never a 401 and never authenticated.

  • api/health.js: GET /api/health for operators.

    • Returns 404 unless HEALTH_CHECK_SECRET (32+ characters) is set, and requires it in the x-hubcys-health-secret header (timing-safe compare).
    • Probes a nonexistent Auth user and Firestore document, and returns only booleans and sanitized error codes.
    • This brings the function count to 11.
  • docs/v2/vercel-credentials.md: exact gcloud commands for the pool, provider (restricted to owner:mekado11s-projects:project:hubcys:environment:production), service account (datastore.user + firebaseauth.viewer) and binding; the Vercel OIDC and env settings; and how to verify.

Not changed

Rules, indexes, memberships, custom claims and the V2 flags are untouched. No production config is changed by merging this PR.

Verification

  • npm run test:security: 52/52 (18 new: config parsing, fail-closed cases, file modes, token refresh and precedence, no token in config or output, verifier ordering, health auth/method/sanitization).
  • npm run typecheck:v2, npm run test:v2 (68/68), eslint on changed files, npm run build: pass.
  • Real library check (not committed): GoogleAuth loaded the generated config as an IdentityPoolClient, read the token file and reached sts.googleapis.com. Google rejected it with invalid_target only because the placeholder pool doesn't exist. The code path is proven up to the IAM setup.
  • Local test:emulator: the rules tests before the browser test all passed. The browser test can't launch here because the Playwright version pinned by this repo needs a Chromium build that isn't installed in this environment. CI installs it and runs the full suite.

After merge (owner)

Follow docs/v2/vercel-credentials.md, redeploy, then confirm /api/health returns 200 with workload_identity, auth_admin.ok and firestore.ok.

🤖 Generated with Claude Code

https://claude.ai/code/session_017SrzLVR7J3b9nCU177esz8


Generated by Claude Code

Vercel has no Application Default Credentials, so every identity-verified
API (the six hardened utility/AI handlers and all /api/v2/*) fails closed
with 503 in production. firebase-admin's Firestore accepts only certificate
or ADC credentials, so federation is delivered through ADC: the per-request
Vercel OIDC token is written to a private temp file referenced by an
external_account config, and GOOGLE_APPLICATION_CREDENTIALS points at it.
Google STS exchanges it and impersonates a least-privilege runtime service
account. No key is stored; partial config fails closed.

Also adds GET /api/health, disabled unless HEALTH_CHECK_SECRET is set, which
probes Auth admin and Firestore and returns only booleans and sanitized codes.
No rules, memberships, claims or feature flags are changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017SrzLVR7J3b9nCU177esz8
@vercel

vercel Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hubcys Ready Ready Preview Sep 23, 2026 8:04pm UTC

@mekado11
mekado11 merged commit cdd942a into main Sep 23, 2026
5 checks passed

This branch was successfully deployed

1 active deployment
Preview — 32a978d7 Deployed Sep 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants