Skip to content

feat(identity): add bounded GitHub OIDC transport - #201

Merged
aparragithub merged 6 commits into
mainfrom
feat/github-oidc-transport
Aug 10, 2026
Merged

feat(identity): add bounded GitHub OIDC transport#201
aparragithub merged 6 commits into
mainfrom
feat/github-oidc-transport

Conversation

@aparragithub

@aparragithub aparragithub commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Closes #198

Type

  • Bug fix
  • New feature
  • Documentation only
  • Code refactoring
  • Maintenance/tooling
  • Breaking change

Summary

  • Add an injected GitHub OIDC metadata and JWKS transport.
  • Enforce HTTPS input, finite timeouts, bounded responses, object JSON, and sanitized failures.
  • Add seven hermetic transport tests without live network access.

Changes

File Change
src/odoo_forge/identity_github/transport.py Bounded HTTPS metadata/JWKS transport seam
tests/identity_github/test_transport.py Transport contract and failure-boundary tests

Test plan

  • uv run pytest tests/identity_github/test_transport.py — 7 passed
  • Focused Ruff lint passed
  • Focused Ruff format check passed

Chain context

Strategy: stacked to main.

main → 📍 PR 1 transport → PR 2 provider → PR 3 JOSE validation

This PR starts with the transport boundary and ends with hermetic transport verification. PR 2 depends on this merge. Provider behavior and JOSE validation remain out of scope. Rollback removes these two files.

Contributor checklist

  • Linked approved issue
  • Added exactly one type:* label
  • Applicable checks passed
  • Tests remain with implementation
  • Conventional commit format
  • No AI attribution or co-author trailer

Summary by CodeRabbit

  • New Features

    • Added GitHub OIDC support for securely retrieving provider metadata and signing keys.
    • Added validation for HTTPS URLs, redirects, response sizes, JSON content, and request timeouts.
    • Exposed GitHub OIDC transport interfaces for integration and testing.
  • Bug Fixes

    • Standardized handling of network, response, parsing, and configuration errors.
  • Tests

    • Added comprehensive coverage for URL validation, redirects, bounded responses, malformed data, timeouts, and error handling.

@aparragithub aparragithub added the type:feature New feature label Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an injectable HTTPS transport for GitHub OIDC metadata and JWKS retrieval. It validates URLs and configuration, limits response reads, checks redirects and JSON objects, sanitizes failures, exports the transport, packages the module, and adds hermetic tests.

Changes

GitHub OIDC transport

Layer / File(s) Summary
Transport contract and HTTPS implementation
src/odoo_forge_identity_github/transport.py
Defines transport protocols and the HTTPS implementation. It validates URLs, applies timeout and response-size limits, checks redirects, parses JSON objects, and normalizes failures.
Transport exports and package wiring
src/odoo_forge_identity_github/__init__.py, pyproject.toml
Exports the transport entities and includes the package in the wheel build.
Transport validation and error coverage
tests/identity_github/test_transport.py
Adds test doubles and tests for URL validation, discovery URL construction, bounded reads, redirects, JSON validation, sanitized errors, constructor validation, and factory composition.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant GitHubOidcHttpsTransport
  participant GitHubOIDCEndpoint
  Caller->>GitHubOidcHttpsTransport: Request metadata or JWKS
  GitHubOidcHttpsTransport->>GitHubOIDCEndpoint: Send bounded HTTPS GET
  GitHubOIDCEndpoint-->>GitHubOidcHttpsTransport: Return response bytes
  GitHubOidcHttpsTransport-->>Caller: Return JSON object or RuntimeError
Loading

Possibly related issues

  • 200 — The transport retrieves JWKS documents for assertion signature validation.
  • 199 — The GitHubOidcTransport interface can be consumed by the stateless identity provider.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: adding a bounded GitHub OIDC transport.
Linked Issues check ✅ Passed The transport, validation, limits, sanitized failures, packaging, and hermetic tests satisfy issue #198.
Out of Scope Changes check ✅ Passed The changes support the transport slice and do not add provider behavior, JOSE validation, dependencies, or unrelated portfolio changes.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/github-oidc-transport

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

Comment thread src/odoo_forge_identity_github/transport.py Fixed
Comment thread src/odoo_forge_identity_github/transport.py Fixed

@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: 4

🤖 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 `@src/odoo_forge/identity_github/transport.py`:
- Around line 43-46: Update get_metadata and/or _validate_https_url to reject
issuer URLs containing a query component before appending
_OPENID_CONFIGURATION_PATH. Preserve acceptance of valid HTTPS issuers without
queries and ensure the existing URL validation error behavior is used.
- Around line 55-63: Move concrete urllib I/O out of _read_response in the
identity GitHub transport and introduce an injected, owned bounded HTTP port
that the core uses for fetching response bytes while retaining OIDC protocol and
response handling there. Implement the urllib-backed port in the adapter
package, preserving timeout and maximum-response-size enforcement. Update
tests/identity_github/test_transport.py lines 56-141 to use a fake port and
assert the port contract instead of patching urllib.request.urlopen; no direct
test change is required beyond this replacement.
- Around line 64-65: Update the exception handling in the GitHub OIDC transport
request flow to raise RuntimeError from None instead of chaining exc,
suppressing the underlying transport exception in formatted tracebacks. Add an
assertion in test_transport.py verifying the formatted traceback omits the
chained URLError details.
- Around line 33-41: Update the transport constructor validation around _timeout
and _max_response_bytes to reject non-finite timeout values and require
max_response_bytes to be a positive integer before assignment. Preserve the
existing ValueError behavior for invalid inputs, and add tests covering NaN,
infinity, and a fractional response limit such as 1.5.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3a79ad67-19d7-4bf5-be07-4bf0e730ce71

📥 Commits

Reviewing files that changed from the base of the PR and between 94d5539 and 3d4c90f.

📒 Files selected for processing (2)
  • src/odoo_forge/identity_github/transport.py
  • tests/identity_github/test_transport.py

Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge/identity_github/transport.py Outdated

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

♻️ Duplicate comments (2)
src/odoo_forge/identity_github/transport.py (2)

48-51: ⚠️ Potential issue | 🟡 Minor

Reject empty query and fragment delimiters before building the discovery URL.

urlsplit() removes delimiters from its result fields, so ? and # produce empty values. (docs.python.org)

Therefore, https://issuer.example? and https://issuer.example# pass the truthiness checks. get_metadata then appends the discovery path to the raw delimiter and builds the wrong URL. Reject the delimiters or normalize the parsed URL before concatenation. Add both regression cases.

Suggested validation change
-            or parsed.fragment
-            or (not allow_query and parsed.query)
+            or "#" in url
+            or (not allow_query and "?" in url)

Also applies to: 89-101

🤖 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 `@src/odoo_forge/identity_github/transport.py` around lines 48 - 51, Update
_validate_https_url, used by get_metadata, to reject issuers containing empty
query or fragment delimiters (`?` or `#`) rather than relying only on urlsplit()
field truthiness. Ensure URL normalization or validation occurs before
get_metadata appends _OPENID_CONFIGURATION_PATH, and add regression coverage for
both delimiter-only cases.

Source: MCP tools


60-71: ⚠️ Potential issue | 🟠 Major

Move concrete HTTPS I/O behind an owned port.

GitHubOidcHttpsTransport._read_response still performs urllib.request.urlopen I/O inside src/odoo_forge/**. GitHubOidcTransport does not inject an HTTP dependency. Move the urllib implementation to an adapter package and inject an owned bounded HTTP port. Update the tests to fake that port.

As per path instructions, src/odoo_forge/** is the pure domain core and must not import adapter packages or perform direct network I/O; it may depend only on its own ports and Pydantic models.

🤖 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 `@src/odoo_forge/identity_github/transport.py` around lines 60 - 71, Refactor
GitHubOidcHttpsTransport._read_response so the domain transport no longer
imports or calls urllib.request.urlopen directly. Define or reuse an owned
bounded HTTP port, inject it through GitHubOidcTransport, and move the concrete
urllib implementation into the adapter package while preserving HTTPS
validation, timeout/response-size limits, and existing failure behavior. Update
the related tests to provide a fake implementation of the injected port.

Source: Path instructions

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

Duplicate comments:
In `@src/odoo_forge/identity_github/transport.py`:
- Around line 48-51: Update _validate_https_url, used by get_metadata, to reject
issuers containing empty query or fragment delimiters (`?` or `#`) rather than
relying only on urlsplit() field truthiness. Ensure URL normalization or
validation occurs before get_metadata appends _OPENID_CONFIGURATION_PATH, and
add regression coverage for both delimiter-only cases.
- Around line 60-71: Refactor GitHubOidcHttpsTransport._read_response so the
domain transport no longer imports or calls urllib.request.urlopen directly.
Define or reuse an owned bounded HTTP port, inject it through
GitHubOidcTransport, and move the concrete urllib implementation into the
adapter package while preserving HTTPS validation, timeout/response-size limits,
and existing failure behavior. Update the related tests to provide a fake
implementation of the injected port.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 965bfbd7-29f2-4848-aed1-1ebda6995500

📥 Commits

Reviewing files that changed from the base of the PR and between 3d4c90f and 1a0a5ee.

📒 Files selected for processing (2)
  • src/odoo_forge/identity_github/transport.py
  • tests/identity_github/test_transport.py

Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py Fixed

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/odoo_forge_identity_github/transport.py (1)

67-69: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Validate every redirect hop before following it.

urllib.request.urlopen follows each Location before _read_response checks response.geturl(). An HTTPS URL can therefore redirect to HTTP and perform that request first. Reject every resolved redirect unless its scheme is https, retain the final check, and add a hermetic multi-hop redirect test.

🤖 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 `@src/odoo_forge_identity_github/transport.py` around lines 67 - 69, Update the
request flow around _read_response so every redirect hop is validated as HTTPS
before urllib follows it, rather than checking only the final response URL.
Preserve the existing final _validate_https_url check, and add a hermetic
multi-hop redirect test covering rejection of any redirect resolving to HTTP.
🤖 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 `@src/odoo_forge_identity_github/transport.py`:
- Around line 99-100: Update the URL validation in get_jwks to reject a bare “#”
fragment delimiter unconditionally, while continuing to reject “?” only when
allow_query is false; add a regression test covering a JWKS URL ending in “#”.

---

Outside diff comments:
In `@src/odoo_forge_identity_github/transport.py`:
- Around line 67-69: Update the request flow around _read_response so every
redirect hop is validated as HTTPS before urllib follows it, rather than
checking only the final response URL. Preserve the existing final
_validate_https_url check, and add a hermetic multi-hop redirect test covering
rejection of any redirect resolving to HTTP.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0c1bf330-be2f-4294-829c-0114901450fb

📥 Commits

Reviewing files that changed from the base of the PR and between 1a0a5ee and ce65ad3.

📒 Files selected for processing (4)
  • pyproject.toml
  • src/odoo_forge_identity_github/__init__.py
  • src/odoo_forge_identity_github/transport.py
  • tests/identity_github/test_transport.py

Comment thread src/odoo_forge_identity_github/transport.py Outdated

@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

🤖 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 `@src/odoo_forge_identity_github/transport.py`:
- Line 48: Update GitHubOidcHttpsTransport’s constructor to accept a typed
opener or bounded HTTP port, store and use that injected dependency instead of
calling urllib.request.build_opener in the transport, and construct the concrete
urllib opener only at the composition boundary. Update tests to pass a fake
dependency rather than patching urllib.request.build_opener.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 04038d9a-bb92-4b15-ba8b-bbd4640f26f6

📥 Commits

Reviewing files that changed from the base of the PR and between ce65ad3 and 3b85785.

📒 Files selected for processing (2)
  • src/odoo_forge_identity_github/transport.py
  • tests/identity_github/test_transport.py

Comment thread src/odoo_forge_identity_github/transport.py Outdated
Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py
Comment thread src/odoo_forge_identity_github/transport.py

@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

🤖 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 `@tests/identity_github/test_transport.py`:
- Line 16: Refactor the redirect-rejection test to remove the
`_HttpsRedirectHandler` import and all direct calls to its private method.
Exercise the behavior through the public transport factory and transport API,
using a loopback HTTPS server if needed; mark the resulting test as integration
and deselected by default when it requires that server.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6e6cbd4d-f433-4de9-8605-2ee4e37c0c72

📥 Commits

Reviewing files that changed from the base of the PR and between 3b85785 and 7f2f704.

📒 Files selected for processing (3)
  • src/odoo_forge_identity_github/__init__.py
  • src/odoo_forge_identity_github/transport.py
  • tests/identity_github/test_transport.py

Comment thread tests/identity_github/test_transport.py Outdated
@aparragithub
aparragithub merged commit 7929284 into main Aug 10, 2026
5 checks passed
@aparragithub
aparragithub deleted the feat/github-oidc-transport branch August 10, 2026 11:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add bounded GitHub OIDC metadata transport

2 participants