Skip to content

Let hosts fix attribution headers on every engine request - #196

Merged
senamakel merged 6 commits into
tinyhumansai:mainfrom
senamakel:engine-default-headers
Oct 4, 2026
Merged

senamakel merged 6 commits into
tinyhumansai:mainfrom
senamakel:engine-default-headers

Conversation

@senamakel

@senamakel senamakel commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Summary

A host can now fix non-credential headers that ride every request an engine makes: CortexEngine::with_default_headers, or EngineSettings::headers through the registry and MemoryConfig.

The TinyHumans backend expects every caller to send its product attribution (x-sdk-name and friends). The tinyhumans wire had no way to do that, so OpenHuman's memory calls were the one backend caller without it. OpenHuman now passes its transport's attribution headers to the hosted engine; it sends nothing extra to a direct CortexDB.

Related issue

None.

API or behavior changes

Additive:

  • CortexEngine::with_default_headers(headers) -> Result<Self>.
  • EngineSettings gains headers: BTreeMap<String, String>. It is skipped in JSON when empty and defaults to empty when absent. A struct literal without ..Default::default() breaks.

The transport refuses headers it owns with Error::Config, so a host cannot override the credential or the write claim this way:

  • Authorization and Proxy-Authorization;
  • Cookie, Host and Content-Length;
  • Idempotency-Key and X-Cortex-Actor.

An invalid name or value (including CR/LF) is refused the same way. No refusal message echoes a value.

Validation

  • cargo fmt --all -- --check: clean
  • cargo clippy --all-targets --all-features -- -D warnings: clean
  • cargo build --all-targets --all-features: clean
  • cargo test --all-features: all pass (integrations: 764)
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features: clean

Tests

  • cortex::transport tests:
    • reserved and malformed headers are refused, case-insensitively, without echoing the value;
    • a fixed header rides a built request beside the sensitive Authorization.
  • registry test: build_engine applies EngineSettings::headers, and refuses an Authorization header without echoing it.

Documentation

  • docs/integration.md, section 2: fixing attribution headers.
  • crates/tinymemory-integrations/src/cortex/README.md, Transport section.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Summary by CodeRabbit

  • New Features
    • Configure fixed headers to be sent with every engine request, either through engine settings or the engine’s builder.
    • Invalid and reserved headers are rejected, and error messages do not reveal header values.
  • Documentation
    • Added guidance on configuring request headers and supplying credentials separately.

senamakel and others added 6 commits October 4, 2026 19:27
…ort/mod.rs

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…/mod.rs,crates/tinymemory-integ

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…,crates/tinymemory-integrations

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ort/mod_tests.rs,crates/tinymem

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ort/mod_tests.rs

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
….md,docs/integration.md

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@tinysweeper

tinysweeper Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Tiny Sweeper reviewed this change across 6 lane(s) and found 2 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below.

State: Changes requested
Priority: high
Reviewed head: 19a5e185d7c0
Updated: 1791132467 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 4 Active findings 2
Tests 2 Noted findings 0
Documentation 2 Resolved findings 0
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

The review could not produce a supported behavioral summary; inspect the cited changed surface and lane details below.

Features

None identified with supported citations.

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

  • high · critique · Apply configured headers when building the engine — `EngineSettings::headers` is added to the public configuration and documented as being sent on every request, but the existing `MemoryConfig::build` path passes the settings to `bu (crates/tinymemory\-integrations/src/config/mod\.rs:79)
  • medium · e2e · Drive the running engine with configured headers end to end — The new fixed-headers feature has two external surfaces: the `"headers"` key in engine configuration (parsed through the registry) and the header itself riding every HTTP request t (crates/tinymemory\-integrations/src/cortex/transport/mod\.rs:222)

Before merge

  • Address Apply configured headers when building the engine (crates/tinymemory\-integrations/src/config/mod\.rs).
Agent review details

critique

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 8 files; 1 finding. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), video (also video-v1)","skipped":[],"type":"ladder_router_error"}}), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/src/config/mod\.rs — Apply configured headers when building the engine

security

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 6 files; 0 findings. 2 files were not security-reviewed: crates/tinymemory-integrations/src/cortex/README.md (prose or tabular data), docs/integration.md (prose or tabular data). _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), video (also video-v1)","skipped":[],"type":"ladder_router_error"}}), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The change adds fixed non-credential headers to the cortex transport, wired through the engine and registry config, and the diff does include tests: transport tests cover reserved-name refusal, malformed names, CR/LF-in-value refusal (and that the error hides the value), and that a fixed header actually rides a built request beside the credential; the registry test covers end-to-end application and refusal of an Authorization header through EngineSettings. The stated invariants — reserved headers refused with Error::Config, no value echoed in errors, headers on every request — are each pinned by a test that would fail if they regressed. Docs and README changes need no tests. The change looks sound; nothing to block merging. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), video (also video-v1)","skipped":[],"type":"ladder_router_error"}}), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The description accurately describes the diff: `with_default_headers`, `EngineSettings::headers` with serde skip/default semantics, the reserved-header refusal list (including `Content-Length`), the no-value-echo property, the registry wiring, and the tests and docs all match what the change does. The change looks sound and the write-up needs no work. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), video (also video-v1)","skipped":[],"type":"ladder_router_error"}}), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._

e2e

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: This change adds host-fixed default headers to the Cortex transport (new `headers` config key, `with_default_headers`, reserved-header refusal). Only unit tests exercise it; the end-to-end harness (integration/cortexdb with mock_inference.py) never drives the running engine with configured headers, so the new external surfaces are unverified end to end. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), video (also video-v1)","skipped":[],"type":"ladder_router_error"}}), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/src/cortex/transport/mod\.rs — Drive the running engine with configured headers end to end
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.016885
  • Tokens: 208723 input · 13068 output · 15549 cached · 0 embedding
Head State Pass summary
19a5e185d7c0 changes requested 2 active finding(s), 0 resolved finding(s) (at 1791132467)

tinysweeper 0.1.0

@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (1)
AGENTS.md — auto-discovered

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6d106390-c527-4a22-99e7-17d83b856b13
📥 Commits

Reviewing files that changed from the base of the PR and between 4a5e02a and 19a5e18.

📒 Files selected for processing (8)
  • crates/tinymemory-integrations/src/config/mod.rs
  • crates/tinymemory-integrations/src/cortex/README.md
  • crates/tinymemory-integrations/src/cortex/engine/mod.rs
  • crates/tinymemory-integrations/src/cortex/transport/mod.rs
  • crates/tinymemory-integrations/src/cortex/transport/mod_tests.rs
  • crates/tinymemory-integrations/src/registry/mod.rs
  • crates/tinymemory-integrations/src/registry/mod_tests.rs
  • docs/integration.md

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Engine settings and CortexEngine now accept fixed request headers. The transport validates the headers, rejects reserved or invalid entries, and attaches valid defaults to requests.

Changes

Fixed Request Headers

Layer / File(s) Summary
Header configuration and transport
crates/tinymemory-integrations/src/config/mod.rs, crates/tinymemory-integrations/src/cortex/transport/*
EngineSettings gains a default-empty header map. HttpClient validates and stores fixed headers, then attaches them to requests. Transport tests cover valid headers, rejected headers, and error messages that omit header values.
Engine and registry configuration
crates/tinymemory-integrations/src/cortex/engine/mod.rs, crates/tinymemory-integrations/src/registry/*, crates/tinymemory-integrations/src/cortex/README.md, docs/integration.md
CortexEngine::with_default_headers sets validated defaults. Registry construction applies EngineSettings.headers. Tests and documentation cover configuration and reserved-header rejection.

Priority: ➖ Normal

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

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Registry
  participant CortexEngine
  participant HttpClient
  Registry->>CortexEngine: Apply settings.headers with with_default_headers
  CortexEngine->>HttpClient: Validate headers and replace defaults
  HttpClient->>HttpClient: Attach default headers and authorization to request
Loading

Merge Risk: ⚪ Minimal · up to 19a5e

The remaining header-validation concern does not establish a request failure or contract violation. The change is mergeable after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 19a5e

The new header option preserves the engine’s credential, actor and write-claim controls, and invalid configuration is rejected before installation. Remaining uncertainty concerns who controls host configuration, how remote services interpret custom headers, and whether those headers remain confined to the intended destination.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — A caller controlling engine settings or the builder can select accepted headers for all requests from that configured engine, including actor discovery—not merely one operation. Effective exposure may include all backend resources served through that engine’s credential. Repository evidence does not establish the configuration supplier’s trust level, remote tenant-header semantics or cross-origin redirect propagation.

Trust Boundaries and Controls

  • observed — The fixed-header path rejects Authorization, Proxy-Authorization, Cookie, Host, Content-Length, Idempotency-Key and X-Cortex-Actor. Credential, actor and write-claim generation remain separate transport responsibilities. This filtering does not establish that every other header lacks security significance to a remote service.
  • observed — Initial endpoints must use HTTP or HTTPS, and non-loopback cleartext endpoints are rejected. The HTTP-client builder does not specify redirect policy. Initial endpoint validation therefore does not itself demonstrate validation of redirect destinations; actual redirect behavior remains a dependency-level evidence gap.

Resilience and Maintainability Implications

  • observed — Requests copy fixed headers, while client clones share the mutex-protected actor cache. Actor lookup failures can leave discovery pending, and rejected credentials reset the cache. Retry paths continue resolving credentials per attempt; fixed headers cannot replace the reserved fresh or caller-reused idempotency keys. These local mechanisms do not prove identity equivalence for custom headers interpreted by a remote backend.

Hardening Proposals

  • proposed — For hosts requiring custom headers to remain origin-bound, consider an explicit same-origin redirect policy and boundary tests. This would make destination containment explicit rather than relying on unverified dependency behavior; it is a hardening proposal, not a finding of header leakage.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding fixed attribution headers to engine requests.
Docstring Coverage ✅ Passed Docstring coverage is 93.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 6 files. (2 skipped: 2 …
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.
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

A rabbit packed headers in a neat little row
The transport checked each one before letting it go
Reserved names were stopped at the gate
While valid ones joined each request in the queue
Then the bunny hopped off, ears high, in the glow

Comment @coderabbitai help to get the list of available commands.

@tinysweeper tinysweeper 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.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0169 · 208,723 in / 13,068 out · 15,549 cached (7%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0084 · 99,418 in  / 6,082 out  · 8,220 cached (8%)  · gpt-5.6-luna, glm-5.3-flash
security:    $0.0055 · 81,916 in  / 3,071 out  · 7,329 cached (9%)  · gpt-5.6-luna
tests:       $0.0006 · 7,011 in   / 410 out    · 0 cached (0%)      · glm-5.3-flash
description: $0.0006 · 6,846 in   / 229 out    · 0 cached (0%)      · glm-5.3-flash
e2e:         $0.0007 · 7,536 in   / 593 out    · 0 cached (0%)      · glm-5.3-flash

/// attribution (`x-sdk-name`). Never a credential: the transport refuses
/// `Authorization` and the other headers it sets itself.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub headers: BTreeMap<String, String>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority high critique confident

Apply configured headers when building the engine

EngineSettings::headers is added to the public configuration and documented as being sent on every request, but the existing MemoryConfig::build path passes the settings to build_engine without any visible header application. The repository search shows this field is only declared here; the header-enabled API exists on CortexEngine, but no configuration code invokes it. As a result, a host can successfully deserialize and serialize headers while every request omits them, making the new configuration option ineffective. Forward the map through the registry/build path and call the engine's header configuration method, propagating invalid or reserved-header errors.

[RULE] unused-configuration ·

@@ -166,6 +220,7 @@ impl HttpClient {
Ok(self
.inner
.request(method, url)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium e2e likely

Drive the running engine with configured headers end to end

The new fixed-headers feature has two external surfaces: the "headers" key in engine configuration (parsed through the registry) and the header itself riding every HTTP request to the CortexDB backend. The only coverage is unit-level: fixed_headers_ride_every_request_beside_the_credential inspects a built Request object, and fixed_headers_are_applied_and_a_credential_header_is_refused only checks that build_engine returns Ok/Err. Nothing runs the actual engine against the live harness (integration/cortexdb's docker-compose + mock_inference.py) and asserts the mock server received x-sdk-name on a request, or that a configured reserved header fails engine construction in a real startup path. The candidate lines in mock_inference.py (Content-Length, end_headers) are pre-existing plumbing of the mock server, not tests of this feature — a test would have to start the compose stack with an engine configured with headers, issue a request through the engine, and have mock_inference record and assert the header arrived. Until then, a wiring regression (e.g. headers dropped when the request builder is assembled, or the registry not threading settings.headers) would pass CI silently.

[RULE] e2e-uncovered ·

@tinysweeper tinysweeper Bot added the priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. label Oct 4, 2026
@senamakel
senamakel merged commit ec0edea into tinyhumansai:main Oct 4, 2026
24 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant