feat(backend): vendor-neutral secrets + outbound TLS 1.2+ enforcement - #204
Open
mercy60 wants to merge 2 commits into
Open
feat(backend): vendor-neutral secrets + outbound TLS 1.2+ enforcement#204mercy60 wants to merge 2 commits into
mercy60 wants to merge 2 commits into
Conversation
Closes NovaCoreLabs1#121, NovaCoreLabs1#122 NovaCoreLabs1#121: Vendor-neutral secret reference via Doppler / Vault / env - Add SecretProvider interface (kind + fetch contract) - Add EnvSecretProvider, DopplerSecretProvider, VaultSecretProvider - Add SecretsService (global, polling-based, single cache) - Add SecretsModule (@global) registered in AppModule - Provider switch via SECRETS_PROVIDER env var (env | doppler | vault) - Optional structured config via SECRETS_PROVIDER_CONFIG (JSON) - Graceful degradation: failed sync keeps previous cache - On boot: warns on unknown SECRETS_PROVIDER and malformed JSON - Polling skipped when provider is env or refreshIntervalMs=0 NovaCoreLabs1#122: Restrict outbound TLS to TLS 1.2+ (PCI DSS) - Add applyTlsHardening() in backend/src/config/tls-hardening.ts - Pinned tls.DEFAULT_MIN_VERSION and https.globalAgent options - Monkey-patches https.request to enforce minVersion=TLSv1.2 and requestCert=true on every outbound call (including custom https.Agent options in place) - Invoked at the very top of bootstrap() in main.ts - package.json scripts: NODE_OPTIONS=--use-openssl-ca on all start variants so the OS trust store is used at process boot Tests: - tls-hardening.spec.ts: 8 cases incl. custom https.Agent override - tls-hardening.spec.ts: badssl.com TLS 1.0 endpoint refused (gated on NOVALABS_CI_OFFLINE) - secrets.module.spec.ts: 24 cases covering env/doppler/vault, warn-on-bad-config, graceful degradation, refresh, polling skip paths, timer cleanup on destroy Note: SecretsModule is the foundation layer. No existing call sites yet consume SecretsService.get(); a follow-up wiring PR will replace selected process.env.X / ConfigService.get("X") reads with secretsService.get(...).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #121
Closes #122
Description
This PR delivers two related security improvements for the NovaLabs backend:
#121 — Vendor-neutral secret reference (Doppler / Vault / env)
SecretProviderinterface (kind+fetch()contract).EnvSecretProvider(default),DopplerSecretProvider(REST/v3/configs/config/secrets),VaultSecretProvider(KV v2{mount}/data/{path}).SecretsServicethat polls the configured provider on a configurable interval (default 60s) so a rotation does not require a redeploy.SecretsModulethat registers the service globally and is wired intoAppModule.SECRETS_PROVIDERenv var (env|doppler|vault); optional structured config viaSECRETS_PROVIDER_CONFIG(JSON).envprovider when no credentials are set — fully backward-compatible; existingprocess.env.X/ConfigService.get("X")reads continue to work.#122 — Restrict outbound TLS to TLS 1.2+ (PCI DSS)
applyTlsHardening()inbackend/src/config/tls-hardening.ts.tls.DEFAULT_MIN_VERSIONandhttps.globalAgent.optionstoTLSv1.2+requestCert=true.https.requestso every outbound call enforcesminVersion="TLSv1.2"andrequestCert=true— including the case where a caller supplies a customhttps.Agent({ minVersion: "TLSv1" }). The agent’s own.optionsare mutated in place because Node consults the agent’s options at TLS handshake time and a request-level option would not override that.bootstrap()inbackend/src/main.ts, before any other module is loaded.package.jsonstart scripts now setNODE_OPTIONS=--use-openssl-caso the OS trust store is used at process boot (in addition to the runtime patch).Change type
Test plan
backend/src/config/{tls-hardening,secrets.module}.spec.ts, all passing (tsc --noEmitclean).SECRETS_PROVIDER=doppler/SECRETS_PROVIDER=vaultconfigurations boot cleanly.Manual smoke test
The badssl.com TLS 1.0 endpoint test is gated on
NOVALABS_CI_OFFLINEso it only runs when the network is available.Breaking changes
SECRETS_PROVIDERunset ⇒ env provider.Scope note (important)
SecretsModuleis the foundation layer. No existing call sites yet consumeSecretsService.get()— the existingprocess.env.X/ConfigService.get("X")reads are unchanged. Wiring a representative subset (e.g.PAYSTACK_SECRET_KEY,JWT_SECRET,SMTP_PASSWORD) intoSecretsService.get(...)is the next step and warrants a follow-up PR so this one stays diff-minimal and reviewable.Files
Requesting review from
@NovaCoreLabs1/backendper CODEOWNERS.