Skip to content

fix(security): fail closed on missing production registry token - #40

Merged
reprewindai-dev merged 4 commits into
mainfrom
fix/registry-auth-production-guard
Aug 11, 2026
Merged

fix(security): fail closed on missing production registry token#40
reprewindai-dev merged 4 commits into
mainfrom
fix/registry-auth-production-guard

Conversation

@reprewindai-dev

@reprewindai-devreprewindai-dev commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Closes#39.

POST /api/v1/registry/register previously allowed unauthenticated registration whenever CAPI_REGISTRY_TOKEN was absent outside the literal NODE_ENV=production case. That left unset, staging, and unknown environments fail-open, and configured tokens could also be presented without the Bearer scheme.

This PR now:

  • permits unauthenticated registration only for the explicit local, development, and test environment allowlist;
  • fails closed with 503 when registry authentication is absent under unset, production, staging, or any unknown environment;
  • requires Authorization: Bearer <token> when CAPI_REGISTRY_TOKEN is configured; raw-token Authorization headers are rejected;
  • preserves 401 for invalid/missing credentials when authentication is configured;
  • adds negative regression coverage for unset/staging/unknown environments and non-Bearer token presentation;
  • does not log or return token material.

Current exact head: 623baa8d0d338060f8c4aa039d426be2fa358284.

Review findings for environment allowlisting and strict Bearer parsing are fixed on this head and their threads are resolved.

Verification boundary

This is a source/authentication correction only. reported_runtime_state remains cAPI 3003; verified_runtime_state remains empty until deployed SHA + HTTP/protocol identity + container listener + Traefik routing agree.

Exact-head merge gate

Do not merge solely from source inspection. GitHub Actions run 31464619305 has now failed on two attempts before executable steps were exposed. The latest verify job is 93694991424, completed failure with steps: null, and its job-log download returns 404 BlobNotFound. The checked-in .github/workflows/ci.yml is a conventional Ubuntu/Node workflow (checkout, setup-node, npm ci, npm test, npm run build), so there is no source evidence that the application tests themselves ran or failed. Treat this as an unresolved Actions/pre-step execution gate, not a test result.

Required before merge: an exact-head workflow must actually execute and expose successful install/test/build steps, with no blocking review. Runtime verification remains separate and still requires deployed SHA + listener 3003 + protocol identity + Traefik agreement.

Summary by CodeRabbit

  • New Features

    • Registry authentication now fails safely with a 503 configuration error when credentials are missing outside local, development, or test environments.
    • Unauthenticated registration remains available in approved non-production environments.
    • Authorization now requires a properly formatted Bearer token.
  • Bug Fixes

    • Prevented raw, non-Bearer authorization values from being accepted.
    • Improved environment-specific handling of registry registration.

@vercel

vercelBot commented Aug 10, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
c-apiErrorErrorAug 11, 2026 6:20am
veklom-id-59uwErrorErrorAug 11, 2026 6:20am

@reprewindai-devChatGPT Codex Connector

Copy link
Copy Markdown
OwnerAuthor

@coderabbitai review

Please review exact head d90dd9c57629a93364519b5f8ee5c8a58dd8006e. Confirm production fails closed before registry mutation when CAPI_REGISTRY_TOKEN is missing, configured-token behavior remains 401/201 as expected, non-production dev/test behavior is preserved, and no token material can leak.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 470c91af-b8db-40ab-8fb3-6015bd69eaa6

📥 Commits

Reviewing files that changed from the base of the PR and between d90dd9c and 623baa8.

📒 Files selected for processing (2)
  • src/app/api/v1/registry/register/route.test.ts
  • src/app/api/v1/registry/register/route.ts

📝 Walkthrough

Walkthrough

The registry registration route now fails with HTTP 503 when authentication configuration is missing outside local, development, and test environments. Configured tokens require Bearer authentication. Tests cover environment handling, authentication, and registry mutation.

Changes

Registry authentication guard

Layer / File(s)Summary
Production authentication handling
src/app/api/v1/registry/register/route.ts
The route allows unauthenticated registration only in local, development, and test environments. It returns HTTP 503 when CAPI_REGISTRY_TOKEN is missing elsewhere. Configured tokens require Bearer authentication.
Authentication behavior coverage
src/app/api/v1/registry/register/route.test.ts
Tests restore NODE_ENV, verify environment-specific registration responses and registry mutation, require Bearer tokens, and reject raw tokens.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedThe changes satisfy Issue #39 by adding the production 503 guard, preserving 401 behavior, preventing mutation, and adding regression coverage.
Out of Scope Changes check✅ PassedThe changes are limited to production registry authentication behavior and its tests, with no unrelated code changes.
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and concisely describes the main security change: production registration fails closed when the registry token is missing.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/registry-auth-production-guard

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/app/api/v1/registry/register/route.test.ts

Oops! Something went wrong! :(

ESLint: 10.8.1

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///.eslintrc.json?mtime=1786454203074" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoadSync (node:internal/modules/esm/load:164:3)
at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:776:12)
at #loadSync (node:internal/modules/esm/loader:796:49)
at ModuleLoader.load (node:internal/modules/esm/loader:762:26)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:504:31)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:555:36)
at afterResolve (node:internal/modules/esm/loader:603:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:609:12)
at node:internal/modules/esm/loader:628:32

src/app/api/v1/registry/register/route.ts

Oops! Something went wrong! :(

ESLint: 10.8.1

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///.eslintrc.json?mtime=1786454203074" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoadSync (node:internal/modules/esm/load:164:3)
at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:776:12)
at #loadSync (node:internal/modules/esm/loader:796:49)
at ModuleLoader.load (node:internal/modules/esm/loader:762:26)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:504:31)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:555:36)
at afterResolve (node:internal/modules/esm/loader:603:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:609:12)
at node:internal/modules/esm/loader:628:32


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
target='d90dd9c57629a93364519b5f8ee5c8a58dd8006e'echo'== Repository revision =='
git rev-parse HEAD
git cat-file -t "$target"
git status --short
echo'== Target commit metadata and changed files =='
git show --no-ext-diff --format=fuller --stat "$target"
git diff-tree --no-commit-id --name-status -r "$target"echo'== Target commit patch =='
git show --no-ext-diff --format= --find-renames "$target"echo'== Candidate route/auth/registry/test files =='
fd -t f .| rg -i '(registry|register|route|router|auth|token|test|spec)'| head -n 250
echo'== Source references with context =='
rg -n -i -C 5 \
'(POST|/api/v1/registry/register|CAPI_REGISTRY_TOKEN|NODE_ENV|register(?:Service)?\s*\(|registry\.(?:set|register|add)|console\.(?:log|error|warn)|logger\.)' \
-g '!node_modules' -g '!dist' -g '!build'.echo'== Test references with context =='
rg -n -i -C 8 \
'(CAPI_REGISTRY_TOKEN|NODE_ENV|/api/v1/registry/register|registry/register|registered service|authorization|bearer)' \
-g '*test*' -g '*spec*' -g '!node_modules' -g '!dist' -g '!build'.||true

Length of output: 197680


🏁 Script executed:

#!/bin/bashset -euo pipefail
target='d90dd9c57629a93364519b5f8ee5c8a58dd8006e'
parent="${target}^"echo'== Exact revision verification =='printf'HEAD: '; git rev-parse HEAD
printf'TARGET: '; git rev-parse "$target"printf'PARENT: '; git rev-parse "$parent"
git merge-base --is-ancestor "$target" HEAD &&echo'TARGET_IS_ANCESTOR_OF_HEAD=true'||echo'TARGET_IS_ANCESTOR_OF_HEAD=false'echo'== Exact target diff: registry route and test =='
git diff --no-ext-diff --unified=80 "$parent""$target" -- \
src/app/api/v1/registry/register/route.ts \
src/app/api/v1/registry/register/route.test.ts
echo'== Route at target =='
git show "${target}:src/app/api/v1/registry/register/route.ts"| nl -ba
echo'== Route test at target =='
git show "${target}:src/app/api/v1/registry/register/route.test.ts"| nl -ba
echo'== Engine registration call chain at target =='
git show "${target}:src/lib/covenant/engine.ts"| sed -n '110,155p'| nl -ba -v110
git show "${target}:src/lib/covenant/service-registry.ts"| sed -n '195,275p'| nl -ba -v195
echo'== Token identifiers and response/log statements in changed route =='
git show "${target}:src/app/api/v1/registry/register/route.ts"|
rg -n -i -C 3 '(CAPI_REGISTRY_TOKEN|authorization|bearer|expected|presented|NextResponse|console\.|logger\.|error)'echo'== All target-commit changed paths =='
git diff-tree --no-commit-id --name-status -r "$target"

Length of output: 6842


🏁 Script executed:

#!/bin/bashset -euo pipefail
echo'== Registry route at HEAD =='
cat -n src/app/api/v1/registry/register/route.ts
echo'== Registry route tests at HEAD =='
cat -n src/app/api/v1/registry/register/route.test.ts
echo'== Registration mutation call chain at HEAD =='
sed -n '115,145p' src/lib/covenant/engine.ts | cat -n
sed -n '195,270p' src/lib/covenant/service-registry.ts | cat -n
echo'== Token, response, and logging paths in the registry route =='
rg -n -i -C 4 \
'(CAPI_REGISTRY_TOKEN|authorization|bearer|expected|presented|NextResponse|console\.|logger\.|error)' \
src/app/api/v1/registry/register/route.ts
echo'== Pull request base and complete changed-file list =='
gh pr view 40 --repo reprewindai-dev/cAPI --json baseRefOid,headRefOid,commits,files \
--jq '{baseRefOid,headRefOid,commits:[.commits[].oid],files:[.files[].path]}'
base="$(gh pr view 40 --repo reprewindai-dev/cAPI --json baseRefOid --jq .baseRefOid)"echo"BASE=$base"echo'== Pull request diff for registry route and tests =='
git diff --no-ext-diff --unified=100 "$base"...HEAD -- \
src/app/api/v1/registry/register/route.ts \
src/app/api/v1/registry/register/route.test.ts

Length of output: 28549


@reprewindai-dev Reviewed exact head d90dd9c57629a93364519b5f8ee5c8a58dd8006e. I found no blocking issues.

Static source review confirms:

  • In src/app/api/v1/registry/register/route.ts, POST checks authentication before JSON parsing and before getEngine().registerService(). Therefore, production with an absent or whitespace-only CAPI_REGISTRY_TOKEN returns 503 before registry mutation.
  • A configured token preserves 401 for missing or invalid credentials. A matching bearer token continues to the existing 201 registration path.
  • Outside production, an absent token preserves unauthenticated registration with authenticated: false.
  • The route does not log either token value. Its 401 and 503 responses return fixed error messages only.
  • The added regression verifies 503 and verifies that the denied service is not present in the registry.

I did not execute repository tests. The sandbox instructions prohibit executing repository files.

✅ Action performed

Review finished.

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.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/app/api/v1/registry/register/route.test.ts (2)

68-79: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Cover whitespace-only token configuration.

The route treats " " as missing configuration, but this test covers only an absent variable. Add a production case with a whitespace-only CAPI_REGISTRY_TOKEN and assert the same 503 response and absence of registry state.

🤖 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 `@src/app/api/v1/registry/register/route.test.ts` around lines 68 - 79, Add a
production test case alongside the existing missing-token test that sets
CAPI_REGISTRY_TOKEN to whitespace only, then verifies register returns 503 with
the same authentication error and that the submitted service is absent from
services().

45-45: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Make the environment policy explicit in the tests.

The successful unauthenticated test relies on ambient NODE_ENV, and the negative test covers only "production". Set the success case to an explicit test/development environment and add an unknown environment case, such as "staging", that expects 503 and no registry mutation.

Also applies to: 68-79

🤖 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 `@src/app/api/v1/registry/register/route.test.ts` at line 45, Make the registry
route tests explicitly control NODE_ENV instead of relying on ambient state: set
the successful unauthenticated case to a test/development environment, and
extend the negative cases with an unknown environment such as staging that
expects status 503 and verifies no registry mutation. Update the relevant test
setup and assertions around the existing authenticated/unauthenticated cases
while preserving the production behavior.
🤖 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.
Inline comments:
In `@src/app/api/v1/registry/register/route.ts`:
- Around line 49-53: Update the authorization parsing around the presented token
so authentication proceeds only when the trimmed header uses the Bearer scheme;
reject or treat non-Bearer headers as invalid instead of copying them into
presented. Preserve the existing token trimming and comparison behavior for
valid Bearer headers.
- Around line 11-12: Update the environment check in the registration handler
around the production authentication guard to allow unauthenticated registration
only for the repository’s explicit local, development, and test environment
values. Treat unset, staging, and every other unknown NODE_ENV value as
authenticated-required, while preserving the existing rejection behavior when
authentication is not configured.
---
Nitpick comments:
In `@src/app/api/v1/registry/register/route.test.ts`:
- Around line 68-79: Add a production test case alongside the existing
missing-token test that sets CAPI_REGISTRY_TOKEN to whitespace only, then
verifies register returns 503 with the same authentication error and that the
submitted service is absent from services().
- Line 45: Make the registry route tests explicitly control NODE_ENV instead of
relying on ambient state: set the successful unauthenticated case to a
test/development environment, and extend the negative cases with an unknown
environment such as staging that expects status 503 and verifies no registry
mutation. Update the relevant test setup and assertions around the existing
authenticated/unauthenticated cases while preserving the production behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 00517795-5318-470d-bbb0-16026b63998e

📥 Commits

Reviewing files that changed from the base of the PR and between 4cf5b46 and d90dd9c.

📒 Files selected for processing (2)
  • src/app/api/v1/registry/register/route.test.ts
  • src/app/api/v1/registry/register/route.ts

Comment threadsrc/app/api/v1/registry/register/route.ts Outdated
Comment threadsrc/app/api/v1/registry/register/route.ts

@reprewindai-devreprewindai-dev left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

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

Blocking security follow-up on the current head before this can leave draft or merge. The intended fail-closed production registry posture is not yet fail-closed for deployment ambiguity: unauthenticated registration is allowed for unset/unknown NODE_ENV values (including staging/typos) because only the literal production value is denied. Make unauthenticated registration an explicit allowlist for known local/development/test values and require authentication for unset or every other environment. Also require the Bearer scheme; Authorization: <raw token> must not authenticate. Add negative tests for unset NODE_ENV, staging, an unknown value, and a correct raw token without Bearer. Keep the existing 503 behavior when auth is required but CAPI_REGISTRY_TOKEN is absent. Exact-head cAPI CI is currently failed, so do not promote or merge until these fixes are pushed and executable checks pass.

Sign up for freeto 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.

Security: fail closed on missing registry token in production

1 participant

@reprewindai-dev