Skip to content

[PM-29460] feat: Authenticate PricingClient to the pricing service - #8054

Open
amorask-bitwarden wants to merge 2 commits into
mainfrom
billing/PM-29460/add-pricing-api-key-authentication-header
Open

[PM-29460] feat: Authenticate PricingClient to the pricing service#8054
amorask-bitwarden wants to merge 2 commits into
mainfrom
billing/PM-29460/add-pricing-api-key-authentication-header

Conversation

@amorask-bitwarden

@amorask-bitwarden amorask-bitwarden commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-29460

📔 Objective

Make server's cloud-side PricingClient send the shared X-Pricing-Api-Key header on every request to the pricing service, so the pricing service's use-pricing-api-key-authentication flag can be turned on without breaking cloud plan retrieval.

Two small, additive changes:

  • GlobalSettings.PricingApiKey — a new optional (nullable) setting mirroring the existing PricingUri. Absent/empty means "don't send." Binds from globalSettings:pricingApiKey / globalSettings__pricingApiKey like the other globalSettings secrets.
  • AddPricingClient — attaches X-Pricing-Api-Key as a default request header on the typed client, guarded on the key being non-empty (mirrors the existing PricingUri empty-guard). PricingClient is unchanged — it already sends whatever default headers the factory configures.

Why it's safe to ship ahead of the flag flip:

  • Cloud-only. Self-hosted short-circuits in PricingClient before any HTTP call, so the header is never sent from a self-host instance.
  • Inert until enabled. While the pricing service's use-pricing-api-key-authentication flag is off, its middleware is a pass-through and ignores the header. The header is only sent once PricingApiKey is provisioned, so there's no behavior change until then — decoupling the server deploy from the flag flip (no window where both must change together).

✅ Testing

  • New ServiceCollectionExtensionsTests asserts the header is present + correct when the key is configured, and absent when it isn't (verified via IHttpClientFactory.CreateClient(nameof(IPricingClient))).
  • Existing PricingClientTests stay green, including the self-hosted no-call cases.
  • dotnet build, dotnet format --verify-no-changes, and the Billing/Pricing suite (99 tests) all pass.

🚫 Out of scope

  • Prod Key Vault / overlay provisioning of globalSettings__pricingApiKey (separate devops ticket, gated on QA validation; non-prod overlays already wired).
  • No changes in bitwarden/billing-pricing — the authentication middleware already exists there.
  • Local-dev cloud key, if needed, belongs in the internal additional-keys-for-cloud-services.json secrets (not this repo), per contributing-docs.

Send the shared X-Pricing-Api-Key header on every cloud request to the
pricing service so its use-pricing-api-key-authentication flag can be
enabled without breaking plan retrieval. Adds an optional PricingApiKey
to GlobalSettings and attaches it as a default request header in
AddPricingClient when configured.

The header is inert while the pricing service's flag is off (that
middleware is a pass-through), so shipping it early is safe and
decouples the server deploy from the flag flip.
@amorask-bitwarden amorask-bitwarden added ai-review Request a Claude code review t:feature Change Type - Feature Development labels Jul 24, 2026
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed an additive change that makes the cloud-side PricingClient send a shared X-Pricing-Api-Key header to the pricing service. The change adds a new nullable GlobalSettings.PricingApiKey and attaches the header in AddPricingClient, guarded on a non-empty key and placed after the existing PricingUri empty-guard early-return. Self-hosted instances short-circuit in PricingClient before any HTTP call, so the change is inert until the key is provisioned. New unit tests cover both the configured and unconfigured header paths.

Code Review Details

No blocking or actionable findings.

Notes considered and dismissed:

  • PricingApiKey is a plain string with no redaction attribute — this matches the existing pattern for every other secret in GlobalSettings (e.g., SendDefaultHashKey, KdfDefaultHashKey), so it is consistent and not a finding.
  • The header add follows the existing PricingUri early-return guard, so it cannot be reached when the client is unconfigured; the IsNullOrEmpty check correctly prevents adding an empty header value.

@amorask-bitwarden
amorask-bitwarden marked this pull request as ready for review July 24, 2026 16:51
@amorask-bitwarden
amorask-bitwarden requested a review from a team as a code owner July 24, 2026 16:51
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 62.50%. Comparing base (e8917a8) to head (cd3e5ad).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8054      +/-   ##
==========================================
- Coverage   62.50%   62.50%   -0.01%     
==========================================
  Files        2301     2301              
  Lines      100156   100161       +5     
  Branches     9027     9028       +1     
==========================================
+ Hits        62605    62606       +1     
+ Misses      35369    35368       -1     
- Partials     2182     2187       +5     

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants