Skip to content

feat(tls): rfc 0030 green (config) — *_tls blocks, preflight, plaintext warning - #442

Merged
jensholdgaard merged 3 commits into
mainfrom
rfc0030-green-config
Jul 9, 2026
Merged

feat(tls): rfc 0030 green (config) — *_tls blocks, preflight, plaintext warning#442
jensholdgaard merged 3 commits into
mainfrom
rfc0030-green-config

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jul 8, 2026

Copy link
Copy Markdown
Owner

First RFC 0030 green slice (post sign-off): RFC0030.5 + RFC0030.7 un-ignored and passing.

What

  • ourios_ingester::receiver::tls — the seam (§3.2): TlsSettings::from_parts is the single §3.1 validation path (errors name the exact {prefix}.* field; all-unset ⇒ None, TLS stays opt-in), TlsSettings::load() reads the PEMs and builds the listener's rustls::ServerConfig (ring provider pinned explicitly; client_ca_fileWebPkiClientVerifier require-and-verify; min-version 1.2/1.3 selection). Errors name the offending path.
  • Config file front-end: receiver.grpc_tls / receiver.http_tls / querier.http_tls blocks (raw string leaves, ${env:…} substitution, deny_unknown_fields), attached to ReceiverParams/QuerierParamscarried, not yet consumed; the acceptor slice wires them into the listeners next.
  • preflight_tls in resolve_config: every configured block is loaded at startup, so unreadable/malformed material is a startup error naming block + path, not a first-handshake surprise.
  • warn_if_plaintext_credentials in startup_guards (§3.4): one warning per plaintext listener when credentials are configured, carrying the new registry event ourios.server.tls.plaintext_credentials (weaver-generated constant; semconv no-diff holds).

Tests

  • RFC0030.5 (ingester it, seam-level per the RFC 0020 §3.1 single-validation-path doctrine): every §3.1 rule arm + unreadable path + non-PEM file + a valid rcgen pair loading under both min-versions.
  • RFC0030.7 (server it, spawned binary): plaintext listener + credentials ⇒ exactly one stderr warning naming querier.http_addr before readiness; the same listener with its http_tls block ⇒ zero.
  • Stub move: .7's stub relocates ingester→server harness (leaf name unchanged; it never asserted anything) because only the server crate can spawn the binary — RFC §6 amended to match. Flagging explicitly per the tests-are-specifications rule.

Invariants / hazards

§3.7-adjacent (credential confidentiality); no storage, schema, or query semantics change. New deps: rustls/rustls-pki-types (already transitive, now direct at the seam), rcgen dev-only — no committed key material.

Verification

cargo fmt --check ✓, cargo clippy --all-targets --all-features -- -D warnings exit 0, both it harnesses green (RFC0030.5 + .7 pass, remaining seven stubs skipped), mdbook build ✓, weaver semconv regenerated.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added TLS configuration support for server listeners, including certificate, key, client CA, and minimum TLS version settings.
    • Startup now checks TLS files early and supports warnings when credentials are served without TLS.
  • Bug Fixes
    • Improved validation for incomplete or invalid TLS settings, including bad versions and reload intervals.
    • Added clearer handling for unreadable, malformed, or empty certificate files.
  • Tests
    • Expanded integration coverage for TLS and plaintext-auth scenarios.

…xt warning

The RFC0030.5 + RFC0030.7 slice. TlsSettings::from_parts is the single
validation path for a *_tls block (field-named errors; all-unset =
plaintext opt-out) and load() builds the rustls ServerConfig at startup
(ring provider pinned; path-named PEM errors; client CA => require-and-
verify). The file front-end gains grpc_tls/http_tls/querier http_tls
sections with ${env:} substitution; resolve_config preflights every
configured block so bad material fails startup, not the first
handshake; startup_guards warns once per plaintext listener when
credentials are configured (registry event
ourios.server.tls.plaintext_credentials via weaver).

.7 moves to the server harness (leaf name unchanged, never asserted as
a stub) — it observes the spawned binary's stderr, which only the
server crate can do; RFC §6 amended to match. rcgen mints all test
material at test time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jensholdgaard
jensholdgaard requested a review from Copilot July 8, 2026 21:40
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jensholdgaard, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 62a5f5dc-81e9-4be9-853e-a23b6a54768e

📥 Commits

Reviewing files that changed from the base of the PR and between dd2df9c and 57a6aca.

📒 Files selected for processing (1)
  • crates/ourios-server/tests/it/rfc0030_tls.rs
📝 Walkthrough

Walkthrough

Introduces TLS/mTLS support for RFC 0030 listeners: ourios-ingester gains a TlsSettings type with validation (from_parts) and rustls-based loading (load); ourios-server wires TLS config through its YAML schema, startup preflight, and plaintext-credential warnings; adds a semconv event and associated tests.

Changes

TLS/mTLS Listener Support

Layer / File(s) Summary
TLS settings contract, validation, and loading
crates/ourios-ingester/Cargo.toml, crates/ourios-ingester/src/receiver.rs, crates/ourios-ingester/src/receiver/tls.rs
Adds rustls/rcgen dependencies, a tls module, and TlsMinVersion/TlsSettings types with from_parts validation and load() producing a rustls::ServerConfig, including optional mTLS client verification.
Ingester validation/loading tests
crates/ourios-ingester/tests/it/rfc0030_tls.rs
Implements rfc0030_5_config_validation covering from_parts/load error and success paths; removes obsolete plaintext-auth stub.
Server file-config TLS schema
crates/ourios-server/src/config/file.rs
Adds TlsSection type, attaches grpc_tls/http_tls fields to ReceiverSection/QuerierSection, and extends env-substitution for nested TLS fields.
Server startup wiring, preflight, and plaintext warnings
crates/ourios-server/Cargo.toml, crates/ourios-server/src/main.rs
Adds TLS fields to param structs, maps TlsSection to TlsSettings, adds preflight_tls invoked at startup, and warn_if_plaintext_credentials in startup_guards.
Server plaintext-warning tests, semconv event, and docs
crates/ourios-semconv/src/lib.rs, semconv/registry/events.yaml, crates/ourios-server/tests/it/rfc0030_tls.rs, docs/rfcs/0030-tls-mtls-listeners.md
Adds EVENT_OURIOS_SERVER_TLS_PLAINTEXT_CREDENTIALS constant and matching semconv registry event, rfc0030_7_plaintext_auth_warning test, and updates RFC scenario-to-crate mapping docs.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Main as ourios-server main
  participant ConfigFile
  participant TlsSettings
  participant Rustls
  participant StartupGuards

  Main->>ConfigFile: server_config_from_file()
  ConfigFile->>TlsSettings: tls_settings(TlsSection)
  Main->>Main: resolve_config()
  Main->>TlsSettings: preflight_tls(config)
  TlsSettings->>Rustls: load() per configured listener
  Rustls-->>TlsSettings: ServerConfig or Err
  Main->>StartupGuards: startup_guards(config)
  StartupGuards->>StartupGuards: warn_if_plaintext_credentials()
Loading

Possibly related PRs

  • jensholdgaard/ourios#441: Introduced the ignored rfc0030_tls config-validation and plaintext-auth-warning test stubs that this PR implements and completes.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description has useful detail, but it does not follow the required template sections or include the checklist/Related headings. Add the required Summary, Related, and Checklist sections, and include the RFC link plus items for fmt, clippy, tests, docs, and RFC applicability.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main TLS config, startup preflight, and plaintext warning changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rfc0030-green-config

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.

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.

Pull request overview

This PR implements the first “green” slice of RFC 0030 by introducing a validated TLS settings seam (TlsSettings), adding config-file *_tls blocks for receiver/querier, preflighting TLS material at startup, and emitting a structured warning when credentials are served over plaintext.

Changes:

  • Added ourios_ingester::receiver::tls::{TlsSettings, TlsMinVersion} with single-path validation (from_parts) and PEM-loading (load) into rustls::ServerConfig.
  • Extended the server config file schema with receiver.{grpc_tls,http_tls} and querier.http_tls, added TLS preflight on startup, and added a plaintext-credentials warning event.
  • Updated RFC 0030 docs and moved/implemented RFC0030.7 as a server integration test that spawns the binary and inspects startup logs.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
semconv/registry/events.yaml Adds semconv event definition for plaintext-credentials warning.
docs/rfcs/0030-tls-mtls-listeners.md Updates testing-strategy mapping for scenario ownership (moves .7 to server).
crates/ourios-server/tests/it/rfc0030_tls.rs Implements RFC0030.7 by spawning ourios-server and asserting warning behavior.
crates/ourios-server/src/main.rs Carries *_tls config into resolved params, preflights TLS, and warns on plaintext credentials.
crates/ourios-server/src/config/file.rs Adds TlsSection blocks to the file-config schema and env-substitution plumbing.
crates/ourios-server/Cargo.toml Adds rcgen dev-dependency for TLS-related tests.
crates/ourios-semconv/src/lib.rs Adds generated constant for the new plaintext-credentials event name.
crates/ourios-ingester/tests/it/rfc0030_tls.rs Implements RFC0030.5 seam-level validation/load tests; removes .7 stub from ingester harness.
crates/ourios-ingester/src/receiver/tls.rs Introduces TLS seam: validation + PEM loading into rustls config (new module).
crates/ourios-ingester/src/receiver.rs Exposes new receiver::tls module.
crates/ourios-ingester/Cargo.toml Adds direct rustls and rustls-pki-types dependencies for the TLS seam.
Cargo.lock Locks new dependencies pulled in by TLS seam and rcgen.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ourios-ingester/Cargo.toml
Comment thread crates/ourios-ingester/src/receiver/tls.rs
Comment thread crates/ourios-server/tests/it/rfc0030_tls.rs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-server/tests/it/rfc0030_tls.rs
Comment thread crates/ourios-server/tests/it/rfc0030_tls.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/ourios-ingester/tests/it/rfc0030_tls.rs (1)

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

Add a test arm for valid mTLS (client CA) loading.

The test exercises the empty-CA error case and the no-CA success case, but never tests load() with a valid client_ca_file. The WebPkiClientVerifier::builder(roots).build()with_client_cert_verifier() path is untested with a non-empty trust store. Since mTLS is security-critical, consider adding an arm that mints a CA cert with rcgen and verifies the config builds successfully.

♻️ Suggested test arm
     // And a valid pair loads — for both min_version selections.
     for (raw, expected) in [
         (None, TlsMinVersion::V1_2),
         (Some("1.3"), TlsMinVersion::V1_3),
     ] {
         let settings = TlsSettings::from_parts(
             "receiver.grpc_tls",
             Some(&cert_path.display().to_string()),
             Some(&key_path.display().to_string()),
             None,
             raw,
             None,
         )
         .expect("valid settings")
         .expect("configured");
         assert_eq!(settings.min_version, expected);
         settings.load().expect("a valid PEM pair builds");
     }
+
+    // A valid pair with a client CA builds an mTLS config.
+    let ca = rcgen::generate_simple_self_signed(vec!["test-ca".into()])
+        .expect("mint a CA");
+    let ca_path = tmp.path().join("ca.crt");
+    std::fs::write(&ca_path, ca.cert.pem()).expect("write CA");
+    let mtls = TlsSettings::from_parts(
+        "receiver.grpc_tls",
+        Some(&cert_path.display().to_string()),
+        Some(&key_path.display().to_string()),
+        Some(&ca_path.display().to_string()),
+        None,
+        None,
+    )
+    .expect("valid mTLS settings")
+    .expect("configured");
+    mtls.load().expect("a valid pair with a client CA builds an mTLS config");
 }
🤖 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 `@crates/ourios-ingester/tests/it/rfc0030_tls.rs` around lines 208 - 225, Add a
test arm in rfc0030_tls.rs to cover successful mTLS loading with a real client
CA, since only the empty-CA error and no-CA success paths are exercised now. Use
the existing TlsSettings::from_parts and settings.load() flow, but provide a
non-empty client_ca_file by minting a CA cert with rcgen and writing it to a
temp file. Verify the WebPkiClientVerifier::builder(roots).build() and
with_client_cert_verifier() path succeeds for this valid trust store.
🤖 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.

Nitpick comments:
In `@crates/ourios-ingester/tests/it/rfc0030_tls.rs`:
- Around line 208-225: Add a test arm in rfc0030_tls.rs to cover successful mTLS
loading with a real client CA, since only the empty-CA error and no-CA success
paths are exercised now. Use the existing TlsSettings::from_parts and
settings.load() flow, but provide a non-empty client_ca_file by minting a CA
cert with rcgen and writing it to a temp file. Verify the
WebPkiClientVerifier::builder(roots).build() and with_client_cert_verifier()
path succeeds for this valid trust store.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bf47e564-d85c-46bf-b9a9-d38e73f8beb7

📥 Commits

Reviewing files that changed from the base of the PR and between 425b96c and dd2df9c.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • crates/ourios-ingester/Cargo.toml
  • crates/ourios-ingester/src/receiver.rs
  • crates/ourios-ingester/src/receiver/tls.rs
  • crates/ourios-ingester/tests/it/rfc0030_tls.rs
  • crates/ourios-semconv/src/lib.rs
  • crates/ourios-server/Cargo.toml
  • crates/ourios-server/src/config/file.rs
  • crates/ourios-server/src/main.rs
  • crates/ourios-server/tests/it/rfc0030_tls.rs
  • docs/rfcs/0030-tls-mtls-listeners.md
  • semconv/registry/events.yaml

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated no new comments.

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.

2 participants