Skip to content

fix: send X-Vault-Namespace header on all vault calls - #47

Open
JBScaled wants to merge 4 commits into
masterfrom
fix/vault-namespace-header
Open

JBScaled wants to merge 4 commits into
masterfrom
fix/vault-namespace-header

Conversation

@JBScaled

@JBScaled JBScaled commented Oct 2, 2026 •

Copy link
Copy Markdown

Overview

Closes #46.

VaultService sent the X-Vault-Namespace header on most of its Vault calls but not on four of them (getTokenWithRole, checkToken, transitCreateKey, getKeys). Those four went to the root namespace, where a namespaced Vault keeps none of our mounts. Sign-in, user creation and user listing answered 403, and the AppRole login at boot failed.

What changed

One private helper, namespaceHeaders(), returns the header when VAULT_NAMESPACE is set and an empty object otherwise. All fourteen call sites spread it into their headers, including the three that landed on master with post-quantum accounts (canCreateUserKey, the shared PQ request path, kvCreate). The ten that already sent the header send exactly what they sent before. getTokenWithRole never passed an axios config, so it gets one.

Behaviour change

AppRole login used to ignore VAULT_NAMESPACE and log in at root. Now it logs in inside the namespace like every other call. If you run a namespaced Vault with AppRole mounted at root and the transit mounts in a child namespace, login breaks after this change. Move the AppRole mount into the namespace, alongside the transit, PQ and KV mounts. .env.template and the README both say so.

Tests

  • A table of the fourteen Vault calls with their exact expected arguments, and two parametrised tests over it: each call sends the header when the namespace is set, and none send it when the variable is unset or empty. The omit check inspects header keys, so a key with an undefined value still fails. pqListKeys stands in for the four PQ methods, which share one request path.
  • getTokenWithRole had no tests. It gets a success case and a 401 case.
  • jest.resetAllMocks() never reset these mocks. jest-create-mock-instance builds them on its own ModuleMocker, so call history leaked from test to test. The spec now recreates the mocks before each test. Without this, the empty-namespace check passed on a broken helper.
  • The two checkToken fixtures returned the base URL for every config key, including the namespace. They now stub by key, using one shared configWith helper that replaces the two identical local copies master had. One describe label that named the wrong method is corrected. Nothing else in the existing tests moved.
  • 29 suites, 386 tests, lint, prettier and tsc all pass. Mutation checks: an empty-string namespace sent as a header, the helper dropped from any of the fourteen call sites, getTokenWithRole without its config, and an undefined-valued header all fail named tests.

Verified against OpenBao 2.7.1

Run on the merged branch, with an intermezzo/ namespace holding the transit, KV and AppRole mounts and a policy granting the PQ engine paths. With master's service, boot-time AppRole login threw VaultException, and POST /v1/wallet/user and GET /v1/wallet/users returned 403. With this branch, login succeeds and they return 201 and 200. Not tested on Vault Enterprise or HCP. CI runs with the namespace empty.

JBScaled and others added 2 commits October 2, 2026 17:56
Resolves the conflict in vault.service.spec.ts by taking master's spec and
re-applying the namespace test block on top of it. Master added three Vault
call sites since the branch point (canCreateUserKey, the shared pqRequest
path, kvCreate); they now go through namespaceHeaders() like the rest, and
the header table covers all fourteen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Coverage report

St.❔
Category Percentage Covered / Total
🟡 Statements
74.66% (+0.38% 🔼)
1962/2628
🔴 Branches
56.5% (+0.02% 🔼)
387/685
🟡 Functions
69.07% (+0.62% 🔼)
259/375
🟡 Lines
75.13% (+0.41% 🔼)
1819/2421

Test suite run success

386 tests passing in 29 suites.

Report generated by 🧪jest coverage report action from 31b8480

@JBScaled
JBScaled requested a review from PhearZero October 2, 2026 23:12
@bwmx
bwmx requested a balanced review from Copilot October 5, 2026 15:09

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

The implementation consistently covers all Vault request paths with focused regression tests and aligned documentation.

Review effort: Balanced
Findings: None

What changed in this PR

Centralizes Vault namespace headers and applies them consistently across all Vault requests.

Changes:

  • Adds a shared namespace-header helper.
  • Expands tests for namespaced and non-namespaced requests.
  • Documents namespace configuration and mount requirements.
File Description
src/​vault/​vault.service.ts Applies namespace headers to all Vault calls.
src/​vault/​vault.service.spec.ts Adds comprehensive namespace-header coverage.
README.md Documents namespaced Vault setup.
.env.template Explains VAULT_NAMESPACE configuration.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

bwmx
bwmx previously approved these changes Oct 6, 2026
The PQ spec block kept its own `ok` helper, identical to the shared
`okResponse`; its calls now use `okResponse`, as was already done for
`configWith`.
@PhearZero

Copy link
Copy Markdown
Collaborator

We have a rule that you must sign commits @JBScaled . Once the commit is signed and pushed, it will trigger another review.

Implementation looks good! Thanks for the contribution!

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.

Four Vault calls are missing the namespace header

4 participants