Skip to content

feat(ingester): rfc 0026 green d — rejection telemetry + denial audit - #409

Merged
jensholdgaard merged 5 commits into
mainfrom
rfc0026-green-d-telemetry
Jul 6, 2026
Merged

feat(ingester): rfc 0026 green d — rejection telemetry + denial audit#409
jensholdgaard merged 5 commits into
mainfrom
rfc0026-green-d-telemetry

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jul 6, 2026

Copy link
Copy Markdown
Owner

What

RFC 0026 green slice (d) — the last scenario, RFC0026.7 (rejection telemetry + audit):

  • Metrics, no new names (§3.4, the OTel recording-errors convention): ingest rejections count on the existing ourios.ingest.batches counter with error.typeunauthenticated recorded by the transports that own the 401 surface (the gRPC interceptor and the HTTP handler), permission_denied by the pipeline's binding check. Query rejections record on the existing ourios.query.duration histogram under a new registry member rejected for the enumerated ourios.query.kind (authn/authz answer before the body parse, so neither logs nor drift applies) — weaver-generated, no hand-written names.
  • The denial audit event (§3.4): a tenant-binding rejection emits ingest_denied (kind 8) — the offending derived tenant on the envelope, the token's audit label in the new denied_token_name column (OPTIONAL Utf8, appended after the quarantine group; RFC 0005 §3.7 additive rules, schema pin updated citing RFC 0026), never a token value. Wired through the same durable audit sink as every other event (IngestPipeline::with_denial_audit_sink, threaded in the server receiver).
  • Read path: the audit reader decodes kind 8 with §3.7 absent-column tolerance (pre-amendment files stay readable), round-trip covered.

Scenario mapping

RFC0026.7 lives in the dedicated tests/rfc0026_telemetry.rs binary — it installs the process-global meter provider, the RFC0028.2 harness-exemption class (README updated). One test covers: both error.type values on the exported batches counter, the ingest_denied event's tenant + token label, WAL emptiness on denial, and a no-token-value sweep across every surface. The Parquet round-trip is in the parquet harness (rfc0026_ingest_denied_audit_event_round_trips); the schema pin is the RFC 0026 §3.4 amendment record.

This closes the RFC 0026 §5 board — all seven scenarios green. The green-flip doc PR follows.

Invariants / hazards

  • §3.5 schema evolution: one additive OPTIONAL column; readers tolerate absence (tested); the pin documents the amendment.
  • Secret hygiene: token values appear on no surface — metric attributes, audit payloads, error text — asserted in the test.
  • New OTel name discipline: the only registry change is the rejected member on the existing ourios.query.kind; error.type is upstream-standard, deliberately not Ourios-coined.

Checks run locally

cargo fmt --all --check, cargo clippy -p {core,parquet,ingester,server} --all-targets --all-features -- -D warnings, cargo test on all four crates.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added telemetry for rejected ingest and query requests, including authentication and permission-denied cases.
    • Tenant-binding denials now generate a durable audit event, making rejected ingest attempts visible in audit history.
    • Audit exports and reads now support the new ingest-denied event and its associated field.
  • Bug Fixes

    • Rejection paths now consistently record metrics before returning an error, improving observability for failed requests.
  • Tests

    • Added coverage for rejection telemetry, audit event round-trips, and updated schema expectations.

Rejections count on the existing request counters with error.type
(unauthenticated | permission_denied; the ingest batches counter and
the query duration histogram under a new registry 'rejected' kind
member), and an ingest tenant-binding denial emits an ingest_denied
audit event (kind 8, denied_token_name column — RFC 0005 §3.7
additive-OPTIONAL) carrying the token's audit label and the offending
tenant, never a token value. RFC0026.7 goes green in a dedicated
global-provider-exempt test binary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jensholdgaard
jensholdgaard requested a review from Copilot July 6, 2026 19:52
@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: 20 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: 3eebe409-7b7f-4fb1-b56a-167dfb11cc52

📥 Commits

Reviewing files that changed from the base of the PR and between a4431fe and 2892846.

📒 Files selected for processing (5)
  • crates/ourios-ingester/src/receiver/grpc.rs
  • crates/ourios-ingester/src/receiver/http.rs
  • crates/ourios-ingester/src/receiver/pipeline.rs
  • crates/ourios-parquet/src/lib.rs
  • crates/ourios-server/src/querier.rs
📝 Walkthrough

Walkthrough

This PR introduces a new AuditPayload::IngestDenied audit event for cross-tenant ingest attempts rejected before the WAL. It adds core schema constants, alias replay handling, ingest pipeline emission with metrics, gRPC/HTTP telemetry, Parquet writer/reader support, and querier rejection metrics with corresponding semconv updates.

Changes

IngestDenied audit event and ingest pipeline

Layer / File(s) Summary
Core audit schema and alias replay
crates/ourios-core/src/audit.rs, crates/ourios-core/src/alias.rs
Adds AuditPayload::IngestDenied { token_name }, EVENT_KIND_INGEST_DENIED/EVENT_TYPE_INGEST_DENIED constants, updates mapping methods, and ignores the payload during alias replay.
Rejection metrics helpers
crates/ourios-ingester/src/metrics.rs
Adds record_rejected_batch and error.type constants for unauthenticated/permission_denied.
Pipeline denial audit emission
crates/ourios-ingester/src/receiver/pipeline.rs
Adds denial_audit sink field, with_denial_audit_sink, record_unauthenticated, and emits IngestDenied on tenant-binding denial in ingest_bound.
gRPC/HTTP telemetry wiring
crates/ourios-ingester/src/receiver/grpc.rs, crates/ourios-ingester/src/receiver/http.rs
AuthInterceptor records rejected-batch metrics on unauthenticated gRPC calls; HTTP handler records unauthenticated rejections.
Server wiring and querier metrics
crates/ourios-server/src/receiver.rs, crates/ourios-server/src/querier.rs, semconv/registry/attributes.yaml
Wires denial audit sink into pipeline construction; adds QUERY_KIND_REJECTED and records rejection metrics on auth failures; documents rejected query kind in semconv.
Integration tests and docs
crates/ourios-ingester/tests/it/ingest_support/mod.rs, crates/ourios-ingester/tests/it/rfc0026_auth.rs, crates/ourios-ingester/tests/rfc0026_telemetry.rs, crates/ourios-ingester/tests/README.md
Adds capturing pipeline test helper, removes old stub, adds RFC0026.7 telemetry test validating audit events and metric counters.

Parquet audit storage for IngestDenied

Layer / File(s) Summary
Schema and column constant
crates/ourios-parquet/src/lib.rs, crates/ourios-parquet/tests/it/schema_pin.rs
Adds DENIED_TOKEN_NAME column constant, extends audit_schema(), updates schema pin fixture.
RecordBatch writer support
crates/ourios-parquet/src/audit_record_batch.rs
Adds denied_token_name builder, nulling logic for other kinds, and population for IngestDenied.
Reader decoding
crates/ourios-parquet/src/audit_reader.rs
Adds rejection_columns and decode_denied_payload helpers and dispatch for the new event kind.
Round-trip tests
crates/ourios-parquet/tests/it/audit_round_trip.rs
Adds test helper and round-trip test for IngestDenied events.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

  • jensholdgaard/ourios#134: Extends the same IngestPipeline in crates/ourios-ingester/src/receiver/pipeline.rs that introduced the WAL-before-ack flow used by the new denial audit logic.
  • jensholdgaard/ourios#398: Both modify the ReceiveError::TenantDenied handling path in ingest_bound, with this PR adding audit emission on top of the earlier TenantDenied enforcement.
  • jensholdgaard/ourios#386: Both update AliasMap::apply in crates/ourios-core/src/alias.rs to ignore a newly added AuditPayload variant during replay.

Poem

A rabbit sniffs a token gone astray,
"Denied!" it hops, then logs the fray.
Metrics tick, an audit gleams,
Parquet columns hold the schemes.
No secret token leaks in sight—
just names and tenants, safe and tight. 🐰📊

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description has useful content, but it omits the required Summary/Related/Checklist sections from the template. Rewrite it to match the template: add a Summary, Related links or RFC reference, and the Checklist items for fmt, clippy, tests, docs, and RFC.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: RFC 0026 rejection telemetry and denial audit.
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-d-telemetry

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 (d)” by adding rejection telemetry (using existing metric names + error.type) and emitting/round-tripping a new ingest_denied audit event (kind 8) that records the offending tenant plus the token’s audit label (never the token value).

Changes:

  • Adds ourios.query.kind=rejected semconv member and records query rejections on the existing query duration metric with error.type.
  • Emits ingest rejection metrics (ourios.ingest.batches + error.type) and introduces an ingest_denied audit event carrying denied_token_name.
  • Extends the audit Parquet schema + reader/writer to support the new event kind/column, and adds dedicated RFC0026.7 tests.

Reviewed changes

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

Show a summary per file
File Description
semconv/registry/attributes.yaml Adds ourios.query.kind enum member rejected for pre-dispatch rejections.
crates/ourios-server/src/receiver.rs Wires the denial audit sink into the shared ingest pipeline.
crates/ourios-server/src/querier.rs Records authn/authz query rejections as kind rejected with error.type.
crates/ourios-parquet/tests/it/schema_pin.rs Pins the audit schema with the new optional denied_token_name column.
crates/ourios-parquet/tests/it/audit_round_trip.rs Adds a round-trip test for the new ingest_denied audit event.
crates/ourios-parquet/src/lib.rs Extends the audit schema + column constants for denied_token_name.
crates/ourios-parquet/src/audit_record_batch.rs Writes AuditPayload::IngestDenied into the new column; nulls it for other kinds.
crates/ourios-parquet/src/audit_reader.rs Reads kind 8 and tolerates absent rejection-group columns for older files.
crates/ourios-ingester/tests/rfc0026_telemetry.rs Dedicated RFC0026.7 binary test for metrics + audit + token-value redaction.
crates/ourios-ingester/tests/README.md Documents the new harness-exempt telemetry test binary.
crates/ourios-ingester/tests/it/rfc0026_auth.rs Removes the RFC0026.7 stub and points to the dedicated telemetry binary.
crates/ourios-ingester/tests/it/ingest_support/mod.rs Adds helper to build a capturing pipeline with a denial audit sink attached.
crates/ourios-ingester/src/receiver/pipeline.rs Implements rejection metric recording + ingest_denied emission on tenant-binding denial.
crates/ourios-ingester/src/receiver/http.rs Records unauthenticated rejection telemetry on HTTP 401.
crates/ourios-ingester/src/receiver/grpc.rs Records unauthenticated rejection telemetry in the gRPC auth interceptor.
crates/ourios-ingester/src/metrics.rs Adds record_rejected_batch helper and error.type value constants.
crates/ourios-core/src/audit.rs Adds AuditPayload::IngestDenied plus kind/type constants and mappings.
crates/ourios-core/src/alias.rs Updates match coverage to include the new audit payload variant.

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

Comment thread crates/ourios-ingester/src/receiver/pipeline.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 18 out of 18 changed files in this pull request and generated no new comments.

@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-parquet/tests/it/audit_round_trip.rs (1)

140-152: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extend the audit round-trip suite with property coverage
The new ingest_denied case is only covered by an example-based round-trip. Add it to the existing proptest-based audit coverage, or expand the generator so this variant is included with the other audit payloads.

🤖 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-parquet/tests/it/audit_round_trip.rs` around lines 140 - 152,
The new ingest_denied audit case is only covered by the example helper
denied_event, so the property-based audit round-trip suite still misses it.
Update the proptest coverage in the audit round-trip tests to include
AuditPayload::IngestDenied, either by extending the existing generator used for
AuditEvent payloads or by adding this variant to the shared audit payload
strategy so it is exercised alongside the other cases.

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.

Nitpick comments:
In `@crates/ourios-parquet/tests/it/audit_round_trip.rs`:
- Around line 140-152: The new ingest_denied audit case is only covered by the
example helper denied_event, so the property-based audit round-trip suite still
misses it. Update the proptest coverage in the audit round-trip tests to include
AuditPayload::IngestDenied, either by extending the existing generator used for
AuditEvent payloads or by adding this variant to the shared audit payload
strategy so it is exercised alongside the other cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ca2b4e4-3e95-48dd-b7e4-2d2d4fc180e0

📥 Commits

Reviewing files that changed from the base of the PR and between 529a575 and a4431fe.

📒 Files selected for processing (18)
  • crates/ourios-core/src/alias.rs
  • crates/ourios-core/src/audit.rs
  • crates/ourios-ingester/src/metrics.rs
  • crates/ourios-ingester/src/receiver/grpc.rs
  • crates/ourios-ingester/src/receiver/http.rs
  • crates/ourios-ingester/src/receiver/pipeline.rs
  • crates/ourios-ingester/tests/README.md
  • crates/ourios-ingester/tests/it/ingest_support/mod.rs
  • crates/ourios-ingester/tests/it/rfc0026_auth.rs
  • crates/ourios-ingester/tests/rfc0026_telemetry.rs
  • crates/ourios-parquet/src/audit_reader.rs
  • crates/ourios-parquet/src/audit_record_batch.rs
  • crates/ourios-parquet/src/lib.rs
  • crates/ourios-parquet/tests/it/audit_round_trip.rs
  • crates/ourios-parquet/tests/it/schema_pin.rs
  • crates/ourios-server/src/querier.rs
  • crates/ourios-server/src/receiver.rs
  • semconv/registry/attributes.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 18 out of 18 changed files in this pull request and generated 3 comments.

Comment thread crates/ourios-server/src/querier.rs Outdated
Comment thread crates/ourios-ingester/src/receiver/pipeline.rs
Comment thread crates/ourios-parquet/src/lib.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 18 out of 18 changed files in this pull request and generated 4 comments.

Comment thread crates/ourios-ingester/src/receiver/pipeline.rs Outdated
Comment thread crates/ourios-ingester/src/receiver/pipeline.rs Outdated
Comment thread crates/ourios-ingester/src/receiver/grpc.rs Outdated
Comment thread crates/ourios-ingester/src/receiver/http.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 18 out of 18 changed files in this pull request and generated no new comments.

@jensholdgaard
jensholdgaard merged commit e0cb265 into main Jul 6, 2026
22 checks passed
@jensholdgaard
jensholdgaard deleted the rfc0026-green-d-telemetry branch July 6, 2026 20:36
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