feat: add provider-neutral std/secrets#161
Conversation
Greptile SummaryThis PR introduces
Confidence Score: 5/5Safe to merge. Secret plaintext only flows through explicitly audited outbound HTTP sinks; all other serialization paths reject or redact; manifest enforcement fails closed on every error condition. Large security-critical addition with thorough defence-in-depth: expose() is pub(crate), RwLock poison recovery fails closed to Invalid, env provider is production-gated, and canary-value tests confirm secrets never appear in error messages or serialized output. The two flagged observations are forward-looking quality notes, not correctness gaps. No files require special attention. src/stdlib/secrets.rs and src/secret.rs are the new security-critical core; both are well-tested and invariants are upheld consistently. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant App as ntnt App Code
participant Secrets as std/secrets
participant Decl as DeclarationState (RwLock)
participant PG as ProviderGroup
participant Env as EnvSecretProvider
participant HTTP as std/http.fetch()
participant Net as Remote API
App->>Secrets: require_secret("API_KEY")
Secrets->>Secrets: validate_secret_name
Secrets->>Decl: enforce_declared
Decl-->>Secrets: Ok or Err
Secrets->>PG: configured_provider_group().lookup
loop per endpoint
PG->>Env: lookup
Env-->>PG: Found or Missing or Error
end
PG-->>Secrets: SecretValue (opaque)
Secrets-->>App: Value::Secret([REDACTED])
App->>HTTP: fetch with secret header
HTTP->>HTTP: disable redirects
HTTP->>HTTP: expose() at approved sink
HTTP->>Net: request with plaintext
Net-->>HTTP: Response
HTTP-->>App: "Result<Response>"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant App as ntnt App Code
participant Secrets as std/secrets
participant Decl as DeclarationState (RwLock)
participant PG as ProviderGroup
participant Env as EnvSecretProvider
participant HTTP as std/http.fetch()
participant Net as Remote API
App->>Secrets: require_secret("API_KEY")
Secrets->>Secrets: validate_secret_name
Secrets->>Decl: enforce_declared
Decl-->>Secrets: Ok or Err
Secrets->>PG: configured_provider_group().lookup
loop per endpoint
PG->>Env: lookup
Env-->>PG: Found or Missing or Error
end
PG-->>Secrets: SecretValue (opaque)
Secrets-->>App: Value::Secret([REDACTED])
App->>HTTP: fetch with secret header
HTTP->>HTTP: disable redirects
HTTP->>HTTP: expose() at approved sink
HTTP->>Net: request with plaintext
Net-->>HTTP: Response
HTTP-->>App: "Result<Response>"
Reviews (3): Last reviewed commit: "fix: stabilize manifest declaration enfo..." | Re-trigger Greptile |
|
Addressed the second Greptile pass in 9a5f5f0: declaration identity is now always derived from the canonical source directory, so adding |
|
Late architecture-review follow-up in 3e94e48: |
Summary
std/secretswithget_secretandrequire_secretSecretruntime/typechecker value with redacted display/debug and zeroized storage[secrets.<NAME>]inntnt.tomlwhen a project manifest exists; reject values and undeclared accessNTNT_ENV=production|prodstd/secretsand the updated HTTP sink semanticsProduction boundary
This PR intentionally does not couple ntnt to Infisical. The production Larri Unix-socket provider/control plane remains a follow-up implementation behind the provider contract introduced here. No production provider silently falls back to environment variables.
Verification
cargo test --all-targetscargo build --profile dev-releasecargo run --quiet -- docs --generatecargo run --quiet -- docs --validatecargo fmt --all -- --checkgit diff --check