Skip to content

Per-lane ca_bundle and insecure for http lanes (#78), v1.2.0 - #130

Merged
CryptoJones merged 1 commit into
mainfrom
feat/per-lane-ca-bundle
Oct 7, 2026
Merged

CryptoJones merged 1 commit into
mainfrom
feat/per-lane-ca-bundle

Conversation

@CryptoJones

Copy link
Copy Markdown
Owner

Closes #78

Why

An http lane pointed at a self-hosted or corporate endpoint behind a private CA failed certificate checks. The only workaround was PYTHONHTTPSVERIFY=0, which turns verification off for every lane, OpenRouter included.

What

  • ca_bundle: PATH trusts that PEM file instead of the system roots, for that lane only, so a private CA can't vouch for any other host. ~ is expanded. A missing or bad file fails the lane with an error that names the path.
  • insecure: true turns verification off for one lane and prints warning: <lane>: TLS verification is OFF on every call. It is rejected as a defaults key, rejected together with ca_bundle, and rejected on cli/acp lanes.
  • skill/toolpanel.py uses the same per-lane SSL context.
  • A README section explains how to use both keys.
  • With neither key set, behavior is unchanged: urlopen gets context=None, exactly as before.

The version goes from 1.1.1 to 1.2.0, a minor bump because these are new opt-in config keys.

Verification

  • TestPerLaneTLS runs a real HTTPS stub with a throwaway CA built with cryptography, which is already the one dependency:
    • without a bundle the connection is refused with CERTIFICATE_VERIFY_FAILED;
    • with the bundle it connects;
    • with insecure it connects and warns;
    • the bundle is the lane's only trust root;
    • a missing bundle names the path.
  • New validation tests cover the rejected key combinations.
  • Full suite: 253 tests OK, 0 ResourceWarnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_015eWZfxrGjWj2QpwdgFwBjR

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

A self-hosted endpoint behind a private CA failed certificate checks, and
the only workaround was PYTHONHTTPSVERIFY=0, which turns verification off
for every lane, OpenRouter included.

- ca_bundle: PATH trusts that PEM file instead of the system roots, for
  that lane only (~ is expanded). A missing or bad file fails the lane
  with an error that names the path.
- insecure: true turns verification off for one lane and prints a warning
  on every call. It cannot be a default, cannot be combined with
  ca_bundle, and is rejected on cli/acp lanes.
- skill/toolpanel.py uses the same per-lane context.
- Tests use a real HTTPS stub with a throwaway CA: refused without a
  bundle, accepted with one, insecure warns, and the bundle replaces the
  system roots.

Default behavior is unchanged when neither key is set.

Closes #78

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015eWZfxrGjWj2QpwdgFwBjR
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 6658aa24-849b-41d9-a5bf-a16de6e2a8ff
📥 Commits

Reviewing files that changed from the base of the PR and between 0028d86 and 87076cc.

📒 Files selected for processing (5)
  • BACKLOG.md
  • README.md
  • roundtable
  • skill/toolpanel.py
  • tests/test_roundtable.py

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

📜 Recent review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.14)
🧰 Additional context used
🪛 ast-grep (0.45.3)
skill/toolpanel.py

[info] 98-98: use jsonify instead of json.dumps for JSON output
Context: json.dumps(body)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[warning] 99-99: Request-controlled URL passed to urlopen; validate against an allowlist to prevent SSRF.
Context: urllib.request.urlopen(req, timeout=lane.get("timeout", 300), context=ctx)
Note: [CWE-918] Server-Side Request Forgery (SSRF).

(urlopen-unsanitized-data)

tests/test_roundtable.py

[warning] 274-274: Do not make http calls without encryption
Context: "http://"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)

🪛 Ruff (0.16.7)
skill/toolpanel.py

[warning] 89-120: Missing explicit return at the end of function able to return non-None value

Add explicit return statement

(RET503)


[error] 98-98: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


[error] 99-99: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)

tests/test_roundtable.py

[warning] 221-221: Missing return type annotation for private function name

(ANN202)


[warning] 265-265: Missing return type annotation for special method __init__

Add return type annotation: None

(ANN204)


[warning] 268-268: Missing return type annotation for special method __enter__

(ANN204)


[warning] 294-294: Missing return type annotation for classmethod setUpClass

Add return type annotation: None

(ANN206)


[warning] 299-299: Missing return type annotation for classmethod tearDownClass

Add return type annotation: None

(ANN206)


[warning] 300-300: Boolean positional value in function call

(FBT003)


[warning] 302-302: Missing type annotation for **kw

(ANN003)


[warning] 306-307: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


[warning] 307-307: Use pytest.raises instead of unittest-style assertRaises

Replace assertRaises with pytest.raises

(PT027)


[warning] 323-323: Use pytest.raises instead of unittest-style assertRaises

Replace assertRaises with pytest.raises

(PT027)


[warning] 450-450: Use pytest.raises instead of unittest-style assertRaises

Replace assertRaises with pytest.raises

(PT027)


[warning] 456-456: Use pytest.raises instead of unittest-style assertRaises

Replace assertRaises with pytest.raises

(PT027)

🔇 Additional comments (4)
skill/toolpanel.py (1)

94-94: LGTM!

README.md (1)

311-322: LGTM!

BACKLOG.md (1)

83-86: LGTM!

roundtable (1)

2334-2340: 🎯 Functional Correctness

The inherited ca_bundle and lane-level insecure: true combination is rejected by design. README.md states that a lane cannot set both, and validate_config applies defaults before checking the merged lane. No correction is needed.


📝 Summary

Summary by CodeRabbit

  • New Features
    • HTTP lanes can use a custom CA bundle, replacing system certificate roots for that lane, or disable certificate verification for that lane.
    • Disabling verification prints a warning on every call. Custom CA bundles and disabled verification cannot be combined; disabled verification cannot be configured as a default.
  • Documentation
    • Updated usage guidance to explain lane-specific TLS settings and warn that PYTHONHTTPSVERIFY=0 disables verification across all lanes.

Walkthrough

HTTP lanes can now use a lane-specific CA bundle or disable TLS verification for that lane. Configuration validation enforces where these options can be used, and HTTP request paths pass the resulting TLS context to urlopen.

Changes

HTTP lane TLS

Layer / File(s) Summary
Validate TLS lane settings
roundtable, tests/test_roundtable.py
Validation restricts ca_bundle and insecure to HTTP lanes, checks their values, prevents setting both on one lane, and rejects insecure in defaults. Tests cover these rules and the application of default CA bundles.
Create and apply lane TLS contexts
roundtable, skill/toolpanel.py, tests/test_roundtable.py, README.md, BACKLOG.md
tls_context creates an unverified context with a warning for insecure lanes, loads a configured CA bundle, or returns None. HTTP request paths pass the context to urlopen. Tests cover TLS behavior. The README documents the options, and the backlog records the item as complete in v1.2.0.

Priority: ➖ Normal

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

Change: Feature · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant HTTPRequest
  participant tls_context
  participant urlopen
  HTTPRequest->>tls_context: Build context from lane settings
  tls_context-->>HTTPRequest: Return context or None
  HTTPRequest->>urlopen: Open request with context
Loading

Merge Risk: ⚪ Minimal · up to 87076

No actionable merge-blocking issue remains; the TLS configuration change is ready for normal merge checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 2 files. (3 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the per-lane TLS options for HTTP lanes and includes the version change.
Description check ✅ Passed The description explains the TLS options, validation rules, expected behavior, and test coverage. It is directly related to the changeset.
Linked Issues check ✅ Passed Issue #78 asks for per-lane trust for private-CA HTTP endpoints, strict default verification, and optional lane-specific insecure mode with a warning. The changes add ca_bundle and insecure valida…
Out of Scope Changes check ✅ Passed The changed backlog entry, README documentation, version, HTTP transport code, tool panel, and tests all support implementation or documentation of issue #78. No unrelated changes are identified in th…
Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 2 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@CryptoJones
CryptoJones merged commit aaac5f4 into main Oct 7, 2026
6 checks passed
@CryptoJones
CryptoJones deleted the feat/per-lane-ca-bundle branch October 7, 2026 07:06
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.

No per-lane CA bundle: self-hosted endpoints force global TLS bypass

1 participant