Skip to content

feat(server): rfc 0026 green a — the token store (RFC0026.1) - #390

Merged
jensholdgaard merged 4 commits into
mainfrom
rfc0026-green-a-token-store
Jul 6, 2026
Merged

feat(server): rfc 0026 green a — the token store (RFC0026.1)#390
jensholdgaard merged 4 commits into
mainfrom
rfc0026-green-a-token-store

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jul 6, 2026

Copy link
Copy Markdown
Owner

What

RFC 0026 green slice (a) — the token store (Scenario RFC0026.1):

  • Schema (config::file): a top-level auth.tokens section — Option<AuthSection> so an absent section (open mode) stays distinguishable from a present-but-empty one (startup error). Entries carry name / token / tenants, get per-leaf ${env:…} substitution like every other scalar, and the token value follows the S3-credential secret rules: inline literals are rejected at parse time (FileConfigError::InlineToken, naming the entry index, never the value) and Debug redacts.
  • Resolved store (ourios_server::auth, new lib module): build_token_store validates the section into a TokenStore — non-empty by construction, unique names (the audit/metric label), unique token values (one value bound to two tenant sets is ambiguous), and a TenantSet enum (All | Listed) so wildcard-vs-list is unrepresentable as a mixed state. TokenStore::authenticate compares in constant time via subtle (already in the tree transitively through rustls). Error text names entries by name/index only.
  • Wiring (src/main.rs): ServerConfig.auth, mapped from the file through the same single validation path as every section; the env-only path always resolves open (tokens ride the ${env:…} indirection by design). When no auth is configured and a network role is enabled, startup emits the registry-backed ourios.server.auth.open_mode warning naming the exposure.
  • Registry: new event ourios.server.auth.open_mode (weaver-generated constant).

Enforcement on the listeners is deliberately not in this slice — it lands with green (b) ingest and (c) query, which consume TokenStore/TenantSet as built here.

Scenario mapping

RFC0026.1 goes green across four homes (the RFC 0020 §5 placement pattern):

  • schema / substitution / secret-hygiene arms — config::file unit tests,
  • the store-validation matrix + constant-time helper API shape (§6) — auth unit tests,
  • the file→store mapping — src/main.rs rfc0026_1_auth_section_maps_onto_the_token_store,
  • the startup-observable arms (empty list ⇒ non-zero exit naming the key; missing section ⇒ open mode with the structured warning, role still binds) — tests/rfc0026_auth.rs against the spawned binary.

.4/.5/.6 stubs remain #[ignore]d for the next slices.

Invariants / hazards

  • §3.7 multi-tenancy: this slice is the configuration half of the enforcement RFC; no data-path behavior changes yet (open-mode parity is scenario .6, asserted when enforcement lands).
  • Secret hygiene (RFC 0020 §3.5 / RFC 0026 §3.1): token values exist only behind ${env:…} indirection; every error/Debug/log surface in this slice names entries, never values — covered by tests on each surface.
  • New OTel name: ourios.server.auth.open_mode goes through semconv/registry + weaver generate (the semconv CI gate).

Checks run locally

cargo fmt --all --check, cargo clippy --all-targets --all-features -- -D warnings (touched crates), cargo test -p ourios-server --all-features.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added bearer-token authentication support with tenant-based access control.
    • Added support for an unauthenticated “open mode” when authentication is not configured.
  • Bug Fixes

    • Improved validation for authentication settings and token lists, with clearer startup errors for invalid configuration.
    • Added safer handling for secret values so tokens are not exposed in logs or debug output.
  • Tests

    • Expanded automated coverage for authentication setup, open-mode behavior, and configuration validation.

auth.tokens config section (Option-al: absent = open mode, present-but-
empty = startup error), ${env:...}-only token values with parse-time
inline-literal rejection and Debug redaction, the validated TokenStore
(constant-time authenticate via subtle, TenantSet::All | Listed) both
enforcement slices will consume, and the registry-backed
ourios.server.auth.open_mode startup warning.

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

coderabbitai Bot commented Jul 6, 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: 49 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: 841750c5-bab5-4c2a-88eb-7916f6f2525c

📥 Commits

Reviewing files that changed from the base of the PR and between 3807e75 and b00a3da.

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

Walkthrough

This PR implements RFC 0026 bearer-token authentication with tenant binding for ourios-server. It adds a TokenStore/ResolvedToken/TenantSet core module with constant-time token comparison, extends YAML config parsing to support an auth section with ${env:...} token substitution, wires the resolved token store into ServerConfig, emits an open-mode startup warning when auth is absent, adds a semconv event constant, and enables previously stubbed integration tests.

Changes

RFC 0026 Bearer-Token Authentication

Layer / File(s) Summary
Semconv event and dependency setup
crates/ourios-semconv/src/lib.rs, semconv/registry/events.yaml, crates/ourios-server/Cargo.toml
Adds EVENT_OURIOS_SERVER_AUTH_OPEN_MODE constant, corresponding registry event definition, and the subtle crate dependency for constant-time comparison.
TokenStore, ResolvedToken, TenantSet core logic
crates/ourios-server/src/auth.rs
New module defining TenantSet (wildcard/listed), ResolvedToken (redacted Debug), TokenStore::authenticate, build_token_store and build_tenant_set validation logic, plus unit tests.
Config parsing, validation, and substitution for auth section
crates/ourios-server/src/config/file.rs
Adds AuthSection/TokenEntry types, FileConfigError::InlineToken, inline-literal rejection, ${env:...} substitution for auth fields, and tests.
Server wiring and startup behavior
crates/ourios-server/src/lib.rs, crates/ourios-server/src/main.rs
Exposes pub mod auth, adds ServerConfig.auth, maps parsed config to TokenStore, defaults to None in env-driven config, and warns on open mode at startup.
Integration tests for auth startup scenarios
crates/ourios-server/tests/rfc0026_auth.rs
Replaces ignored stubs with active tests verifying empty-token-list startup failure and open-mode warning/behavior via spawned binary.

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

Sequence Diagram(s)

sequenceDiagram
  participant Main as main.rs
  participant FileConfig
  participant Auth as auth::build_token_store
  participant Store as TokenStore
  participant Client

  Main->>FileConfig: parse config file (auth section)
  Main->>Auth: build_token_store(auth section)
  Auth-->>Main: Option<TokenStore>
  Main->>Main: warn if auth is None and roles enabled
  Client->>Store: authenticate(presented token)
  Store->>Store: constant-time compare against tokens
  Store-->>Client: Option<&ResolvedToken>
Loading

Possibly related PRs

  • jensholdgaard/ourios#322: Adds the RFC 0020 ${env:...} substitution resolver that this PR relies on for resolving auth tokens.
  • jensholdgaard/ourios#325: Both PRs modify the same config/file.rs parsing/substitution flow, with this PR extending it for auth.tokens.
  • jensholdgaard/ourios#326: Both PRs touch the FileConfigServerConfig mapping in main.rs, extended here to populate the new auth field.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title names the RFC 0026 token-store slice and matches the main change, though the wording is a bit noisy.
Description check ✅ Passed The description covers the PR summary, related context, checklist evidence, and testing, though it doesn't use the exact template headings.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 rfc0026-green-a-token-store

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

Implements RFC 0026 green slice (a) by introducing a configuration-backed bearer-token store (auth.tokens) for the server, including secret-hygiene rules (env-only tokens), validation into a resolved TokenStore, and an “open mode” startup warning/event when network roles are enabled without auth configured.

Changes:

  • Add auth.tokens schema support with per-leaf ${env:…} substitution and inline-literal token rejection + redacted Debug.
  • Introduce ourios_server::auth with build_token_store, TokenStore::authenticate (constant-time per-candidate compare), and TenantSet.
  • Wire the resolved auth store into ourios-server startup, emitting the new registry-backed ourios.server.auth.open_mode warning when applicable, plus add scenario tests.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
semconv/registry/events.yaml Registers new ourios.server.auth.open_mode event in the semconv registry.
crates/ourios-server/tests/rfc0026_auth.rs Adds spawned-binary tests for empty-token-list startup error and open-mode warning behavior.
crates/ourios-server/src/main.rs Wires auth into ServerConfig, runs shared validation path, and emits open-mode warning at startup.
crates/ourios-server/src/lib.rs Exposes new auth module from the ourios-server library.
crates/ourios-server/src/config/file.rs Adds auth schema, ${env:…} substitution for auth leaves, inline-token literal check, and tests.
crates/ourios-server/src/auth.rs New resolved token-store implementation + validation + unit tests.
crates/ourios-server/Cargo.toml Adds subtle dependency for constant-time comparisons.
crates/ourios-semconv/src/lib.rs Regenerates semconv constants to include EVENT_OURIOS_SERVER_AUTH_OPEN_MODE.
Cargo.lock Locks in subtle as a direct dependency of ourios-server.

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

Comment thread crates/ourios-server/tests/rfc0026_auth.rs Outdated
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 8 out of 9 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-server/tests/rfc0026_auth.rs
Comment thread crates/ourios-server/src/config/file.rs
An undrained stderr pipe could fill and block the spawned server before
its stdout readiness line; and a literal token: "" now fails the
parse-time reference rule (a bearer token has no unset-with-fallback
reading, unlike an S3 credential) instead of the misleading
resolved-to-empty message, with an absent key getting its own
token-is-required error.

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 8 out of 9 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-server/tests/rfc0026_auth.rs
Comment thread crates/ourios-server/tests/rfc0026_auth.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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/ourios-server/src/auth.rs (1)

87-100: 🩺 Stability & Availability | 🔵 Trivial

Remember Prometheus metrics/tracing once authenticate is wired to a hot path.

This lookup isn't called from a request path in this slice (enforcement is deferred per the PR description), so no gap exists yet. As per coding guidelines, **/crates/ourios-{ingester,querier,server}/**/*.rs should "Use Prometheus metrics for every subsystem, emit structured logs via Ourios on hot paths, and trace every RPC" once this becomes reachable from the listener enforcement path.

🤖 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-server/src/auth.rs` around lines 87 - 100, The
TokenStore::authenticate lookup is currently fine in isolation, but once it is
connected to the request listener hot path it should be instrumented per our
subsystem guidelines. Update the authenticate call path to emit Prometheus
metrics and structured Ourios logs, and add tracing around the request/RPC
boundary where this method becomes reachable so the hot path is observable
without changing the constant-time token comparison logic.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@crates/ourios-server/tests/rfc0026_auth.rs`:
- Around line 41-50: The test command setup around timeout and Command::new
currently leaves the spawned ourios-server process running if the future is
dropped on timeout. Update the Command used for output() to enable
kill_on_drop(true) before launching it so the child process is terminated
automatically if the 15s timeout ever elapses; keep the change localized to the
RFC0026 auth test helper that builds the command.

---

Nitpick comments:
In `@crates/ourios-server/src/auth.rs`:
- Around line 87-100: The TokenStore::authenticate lookup is currently fine in
isolation, but once it is connected to the request listener hot path it should
be instrumented per our subsystem guidelines. Update the authenticate call path
to emit Prometheus metrics and structured Ourios logs, and add tracing around
the request/RPC boundary where this method becomes reachable so the hot path is
observable without changing the constant-time token comparison logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bb3575b7-98ff-47ba-9214-0c2fab63cb48

📥 Commits

Reviewing files that changed from the base of the PR and between 0a466ed and 3807e75.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • crates/ourios-semconv/src/lib.rs
  • crates/ourios-server/Cargo.toml
  • crates/ourios-server/src/auth.rs
  • crates/ourios-server/src/config/file.rs
  • crates/ourios-server/src/lib.rs
  • crates/ourios-server/src/main.rs
  • crates/ourios-server/tests/rfc0026_auth.rs
  • semconv/registry/events.yaml

Comment thread crates/ourios-server/tests/rfc0026_auth.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 8 out of 9 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