Skip to content

Simplify Tinfoil proxy passthrough and remove legacy routing#166

Merged
AnthonyRonning merged 2 commits intomasterfrom
fix/simplify-tinfoil-proxy
Apr 9, 2026
Merged

Simplify Tinfoil proxy passthrough and remove legacy routing#166
AnthonyRonning merged 2 commits intomasterfrom
fix/simplify-tinfoil-proxy

Conversation

@AnthonyRonning
Copy link
Copy Markdown
Contributor

@AnthonyRonning AnthonyRonning commented Apr 9, 2026

Summary

  • replace the custom Go request/response translation layer with a raw attested Tinfoil pass-through
  • simplify Rust completion routing to use Tinfoil directly while preserving the existing transcription/audio fallback path
  • remove unused document proxying and legacy llama aliasing, and rebuild the checked-in Nitro proxy binary

Validation

  • cargo fmt --all -- --check
  • CARGO_INCREMENTAL=0 cargo test --all-features
  • CARGO_INCREMENTAL=0 cargo clippy --all-targets --all-features -- -D warnings
  • podman run --rm -v "/Users/tony/Dev/OpenSecret/opensecret/tinfoil-proxy:/src" -w /src docker.io/library/golang:1.25-alpine go test ./...

Open with Devin

Summary by CodeRabbit

  • Bug Fixes

    • Corrected Llama 3.3 70B model naming to match provider specifications.
  • Removals

    • Removed document upload and status endpoints from API.
    • Removed model routing and static model enumeration features.
  • Changes

    • Simplified proxy selection logic for improved stability.
    • Updated tinfoil proxy to generic HTTP passthrough architecture.
    • Updated Go dependencies (v1.25.9, OpenAI API v3, and others).
  • Chores

    • Updated PCR attestation history records.
    • Added Nix flake configuration for builds.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 9, 2026

Walkthrough

The pull request removes document upload/status handling, simplifies proxy routing by eliminating model-specific routing tables and replacing multi-route selection with a single completion-proxy approach, refactors tinfoil-proxy from typed endpoint handlers to a generic request passthrough, updates Go dependencies and model name canonicalization (llama-3.3-70b to llama3-3-70b), and updates PCR history records.

Changes

Cohort / File(s) Summary
Document handling removal
src/main.rs, src/web/documents.rs, src/web/mod.rs
Deleted entire document upload/status module and removed document_routes from Axum router construction and public module exports.
Proxy routing refactor
src/proxy_config.rs
Removed ModelRoute type, model routing tables, and static model listing (get_model_route, get_all_models, get_model_name_for_provider). Added get_completion_proxy() and get_tinfoil_proxy() accessors. Introduced standalone canonicalize_tinfoil_model() function. Updated ProxyConfig to derive PartialEq/Eq and adjusted tinfoil base handling.
Completion handler refactoring
src/web/openai.rs
Removed model-route lookup and fallback cycling; now uses single get_completion_proxy(). Added Tinfoil response canonicalization, updated embeddings/transcription to use proxy selection with fallback logic, and introduced private helpers for stream usage/terminal chunk detection.
Health check proxy selection
src/web/health_routes.rs
Changed model-listing connectivity test proxy from get_default_proxy() to get_completion_proxy().
Model name mapping updates
src/tokens.rs, src/web/responses/handlers.rs, src/web/responses/prompts.rs
Updated llama-3.3-70b to llama3-3-70b across context-window mapping, title-generation request, and query-extractor constant.
Tinfoil proxy service refactor
tinfoil-proxy/main.go, tinfoil-proxy/main_test.go
Removed OpenAI-typed request/response structs and endpoint-specific handlers; replaced with generic request passthrough for /v1/models, /v1/chat/completions, /v1/audio/\*, /v1/embeddings. Added doWithResponseStartTimeout helper and writeProxyError for centralized error responses. Updated tests to cover HTTP header filtering, query preservation, and response-start timeouts.
Tinfoil proxy dependencies and build
tinfoil-proxy/go.mod, tinfoil-proxy/flake.nix
Bumped Go version to 1.25.9; upgraded openai-go to v3.31.0 and tinfoil-go to v0.12.8; reorganized indirect dependency graph. Added Nix flake configuration for package build (pkgs.buildGoModule) and development shell with Go 1.26 and gopls.
PCR history
pcrDevHistory.json, pcrProdHistory.json
Appended new PCR record entries with updated values for PCR0, PCR1, PCR2, timestamp, and signature.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Axum Server
    participant Proxy Router
    participant Tinfoil Proxy
    participant Upstream Service
    
    Client->>Axum Server: POST /v1/chat/completions
    Axum Server->>Proxy Router: get_completion_proxy()
    Proxy Router-->>Axum Server: ProxyConfig (tinfoil or default)
    Axum Server->>Tinfoil Proxy: Forward request (method/path/query/body)
    Tinfoil Proxy->>Upstream Service: Forward with Authorization header
    Upstream Service-->>Tinfoil Proxy: Response (status/body/headers)
    Tinfoil Proxy->>Tinfoil Proxy: Passthrough response & canonicalize if tinfoil
    Tinfoil Proxy-->>Axum Server: Stream response body
    Axum Server-->>Client: Forwarded response
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

  • Model routing #53: Directly inverse refactor—introduces ModelRoute and per-provider model routing while this PR removes them, affecting same core routing APIs.
  • Start on documents feature #43: Adds src/web/documents.rs module and exports document_routes to main.rs router; this PR removes the same module and route integration.
  • Forward reasoning controls through the Tinfoil proxy #154: Tinfoil-proxy change conflict—retrieved PR forwards reasoning-control fields via typed ChatCompletionRequest, while this PR replaces all typed handlers with generic passthrough proxy.

Poem

🐰 ModelRoute hops away, one proxy remains,
Tinfoil flows through like generic streams,
Documents uploaded, then whisked away free,
From llama-3.3 to llama3-3,
Simpler paths lead where routing once roamed! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: simplification of Tinfoil proxy and removal of legacy routing, which are the core objectives reflected throughout the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/simplify-tinfoil-proxy

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

coderabbitai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 8 additional findings.

Open in Devin Review

@AnthonyRonning AnthonyRonning force-pushed the fix/simplify-tinfoil-proxy branch from 434d781 to bb0fbdb Compare April 9, 2026 16:15
coderabbitai[bot]

This comment was marked as resolved.

@AnthonyRonning AnthonyRonning force-pushed the fix/simplify-tinfoil-proxy branch from bb0fbdb to c8695c0 Compare April 9, 2026 17:56
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tinfoil-proxy/main_test.go (1)

17-32: Header-skip coverage looks good; consider adding lowercase variants.

Optional hardening: add cases like authorization / connection to explicitly lock in case-insensitive behavior expectations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tinfoil-proxy/main_test.go` around lines 17 - 32, The test
TestShouldSkipHeader should include lowercase header variants to assert
shouldSkipHeader is case-insensitive; update the tests map in
TestShouldSkipHeader to add entries for "authorization" and "connection" (and
any other lowercase forms you want) with the same expected boolean values,
ensuring the test iterates over those keys so shouldSkipHeader("authorization")
and shouldSkipHeader("connection") are explicitly verified.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tinfoil-proxy/main_test.go`:
- Around line 17-32: The test TestShouldSkipHeader should include lowercase
header variants to assert shouldSkipHeader is case-insensitive; update the tests
map in TestShouldSkipHeader to add entries for "authorization" and "connection"
(and any other lowercase forms you want) with the same expected boolean values,
ensuring the test iterates over those keys so shouldSkipHeader("authorization")
and shouldSkipHeader("connection") are explicitly verified.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5514453e-bd15-4f3d-8c9f-075c2788cf58

📥 Commits

Reviewing files that changed from the base of the PR and between bb0fbdb and c8695c0.

⛔ Files ignored due to path filters (3)
  • flake.lock is excluded by !**/*.lock
  • tinfoil-proxy/dist/tinfoil-proxy is excluded by !**/dist/**
  • tinfoil-proxy/go.sum is excluded by !**/*.sum
📒 Files selected for processing (13)
  • flake.nix
  • src/main.rs
  • src/proxy_config.rs
  • src/tokens.rs
  • src/web/documents.rs
  • src/web/health_routes.rs
  • src/web/mod.rs
  • src/web/openai.rs
  • src/web/responses/handlers.rs
  • src/web/responses/prompts.rs
  • tinfoil-proxy/go.mod
  • tinfoil-proxy/main.go
  • tinfoil-proxy/main_test.go
💤 Files with no reviewable changes (2)
  • src/web/mod.rs
  • src/web/documents.rs
✅ Files skipped from review due to trivial changes (2)
  • src/web/responses/handlers.rs
  • tinfoil-proxy/main.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/web/health_routes.rs
  • src/web/responses/prompts.rs
  • tinfoil-proxy/go.mod

devin-ai-integration[bot]

This comment was marked as resolved.

Keep the raw Tinfoil proxy compliant with hop-by-hop header stripping and bounded response start without capping live SSE streams. Move the newer Go tooling into a dedicated tinfoil-proxy flake so the root Nitro/EIF flake stays on its original setup.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@AnthonyRonning AnthonyRonning force-pushed the fix/simplify-tinfoil-proxy branch from c8695c0 to 279ae60 Compare April 9, 2026 18:42
Refresh the dev and prod PCR snapshots and append the new signed measurements after the latest EIF updates.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/proxy_config.rs (2)

41-47: ⚠️ Potential issue | 🟠 Major

Whitespace-only tinfoil_base still accepted.

If the env var is set to " ", get_completion_proxy() will prefer an invalid Tinfoil endpoint over default_proxy, causing hard failures. Trim before checking emptiness.
,

Suggested fix
         let tinfoil_proxy = tinfoil_base
-            .filter(|base| !base.is_empty())
-            .map(|base_url| ProxyConfig {
-                base_url,
+            .map(|base| base.trim().to_string())
+            .filter(|base| !base.is_empty())
+            .map(|base_url| ProxyConfig {
+                base_url,
                 api_key: None,
                 provider_name: "tinfoil".to_string(),
             });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/proxy_config.rs` around lines 41 - 47, The tinfoil_base value is
currently checked with .filter(|base| !base.is_empty()), which accepts
whitespace-only strings; update get_completion_proxy() so tinfoil_base is
trimmed before emptiness check and before constructing ProxyConfig: compute a
trimmed version (e.g. let trimmed = base.trim().to_string()) and use
.filter(|base| !base.trim().is_empty()) or map from the trimmed string so
tinfoil_proxy only contains valid non-whitespace base_url when creating
ProxyConfig (referencing tinfoil_base, tinfoil_proxy, and get_completion_proxy).

29-38: ⚠️ Potential issue | 🟠 Major

Substring host matching still risks credential leakage.

The contains("api.openai.com") check can match unintended hosts (e.g., api.openai.com.evil.com) and send credentials to the wrong upstream. Parse openai_base as a URL and compare the host exactly.
,

Suggested fix
+        let is_openai_host = url::Url::parse(&openai_base)
+            .ok()
+            .and_then(|u| u.host_str().map(|h| h.eq_ignore_ascii_case("api.openai.com")))
+            .unwrap_or(false);
+
         let default_proxy = ProxyConfig {
             base_url: openai_base.clone(),
-            api_key: if openai_base.contains("api.openai.com") {
+            api_key: if is_openai_host {
                 openai_key
             } else {
                 None
             },
-            provider_name: if openai_base.contains("api.openai.com") {
+            provider_name: if is_openai_host {
                 "openai".to_string()
             } else {
                 "continuum".to_string()
             },
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/proxy_config.rs` around lines 29 - 38, The current substring check using
openai_base.contains("api.openai.com") can leak credentials; instead parse
openai_base as a URL (e.g., using Url::parse) and compare the parsed host
exactly to "api.openai.com" when deciding api_key and provider_name; if URL
parsing fails or host != "api.openai.com" set api_key to None and provider_name
to "continuum". Ensure you reference the openai_base variable and preserve
openai_key for the api_key assignment when the host matches, and handle parse
errors gracefully.
🧹 Nitpick comments (1)
tinfoil-proxy/main_test.go (1)

96-98: Use errors.Is for timeout assertion robustness.

Direct equality is brittle if errors get wrapped; errors.Is(err, context.DeadlineExceeded) is safer.

♻️ Proposed test hardening
 import (
 	"context"
+	"errors"
 	"io"
 	"net/http"
 	"testing"
 	"time"
 )
@@
-	if err != context.DeadlineExceeded {
+	if !errors.Is(err, context.DeadlineExceeded) {
 		t.Fatalf("expected context deadline exceeded, got %v", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tinfoil-proxy/main_test.go` around lines 96 - 98, Replace the direct equality
check against context.DeadlineExceeded with errors.Is to correctly handle
wrapped errors: update the assertion in the test that currently does "if err !=
context.DeadlineExceeded { ... }" to "if !errors.Is(err,
context.DeadlineExceeded) { ... }" and add the "errors" import if missing; this
targets the timeout assertion around the test's error variable (err) so wrapped
timeout errors are detected reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tinfoil-proxy/main_test.go`:
- Around line 37-57: The test reveals that headerSkipSet building in copyHeaders
(tinfoil-proxy/main.go) doesn't split comma-separated Connection header tokens,
so update the code that processes the "Connection" header (the logic that
currently populates headerSkipSet) to split each Connection header value on
commas, trim spaces, normalize case, and add each token to headerSkipSet before
copying; ensure copyHeaders still skips any header whose canonicalized name is
in headerSkipSet (e.g., "X-Per-Connection") so comma-delimited tokens are
correctly honored and those nominated hop-by-hop headers are not forwarded.

---

Duplicate comments:
In `@src/proxy_config.rs`:
- Around line 41-47: The tinfoil_base value is currently checked with
.filter(|base| !base.is_empty()), which accepts whitespace-only strings; update
get_completion_proxy() so tinfoil_base is trimmed before emptiness check and
before constructing ProxyConfig: compute a trimmed version (e.g. let trimmed =
base.trim().to_string()) and use .filter(|base| !base.trim().is_empty()) or map
from the trimmed string so tinfoil_proxy only contains valid non-whitespace
base_url when creating ProxyConfig (referencing tinfoil_base, tinfoil_proxy, and
get_completion_proxy).
- Around line 29-38: The current substring check using
openai_base.contains("api.openai.com") can leak credentials; instead parse
openai_base as a URL (e.g., using Url::parse) and compare the parsed host
exactly to "api.openai.com" when deciding api_key and provider_name; if URL
parsing fails or host != "api.openai.com" set api_key to None and provider_name
to "continuum". Ensure you reference the openai_base variable and preserve
openai_key for the api_key assignment when the host matches, and handle parse
errors gracefully.

---

Nitpick comments:
In `@tinfoil-proxy/main_test.go`:
- Around line 96-98: Replace the direct equality check against
context.DeadlineExceeded with errors.Is to correctly handle wrapped errors:
update the assertion in the test that currently does "if err !=
context.DeadlineExceeded { ... }" to "if !errors.Is(err,
context.DeadlineExceeded) { ... }" and add the "errors" import if missing; this
targets the timeout assertion around the test's error variable (err) so wrapped
timeout errors are detected reliably.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3b1ec261-57fa-455b-8bc6-89c382a903bc

📥 Commits

Reviewing files that changed from the base of the PR and between c8695c0 and 27435ed.

⛔ Files ignored due to path filters (5)
  • pcrDev.json is excluded by !pcrDev.json
  • pcrProd.json is excluded by !pcrProd.json
  • tinfoil-proxy/dist/tinfoil-proxy is excluded by !**/dist/**
  • tinfoil-proxy/flake.lock is excluded by !**/*.lock
  • tinfoil-proxy/go.sum is excluded by !**/*.sum
📒 Files selected for processing (15)
  • pcrDevHistory.json
  • pcrProdHistory.json
  • src/main.rs
  • src/proxy_config.rs
  • src/tokens.rs
  • src/web/documents.rs
  • src/web/health_routes.rs
  • src/web/mod.rs
  • src/web/openai.rs
  • src/web/responses/handlers.rs
  • src/web/responses/prompts.rs
  • tinfoil-proxy/flake.nix
  • tinfoil-proxy/go.mod
  • tinfoil-proxy/main.go
  • tinfoil-proxy/main_test.go
💤 Files with no reviewable changes (2)
  • src/web/mod.rs
  • src/web/documents.rs
✅ Files skipped from review due to trivial changes (5)
  • pcrDevHistory.json
  • src/web/responses/handlers.rs
  • tinfoil-proxy/flake.nix
  • pcrProdHistory.json
  • src/web/openai.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/web/health_routes.rs
  • src/tokens.rs
  • src/web/responses/prompts.rs
  • tinfoil-proxy/main.go

Comment thread tinfoil-proxy/main_test.go
@AnthonyRonning AnthonyRonning merged commit 6a84eec into master Apr 9, 2026
9 checks passed
@AnthonyRonning AnthonyRonning deleted the fix/simplify-tinfoil-proxy branch April 9, 2026 19:17
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.

1 participant