Skip to content

[WS-GHPROOF-001-02] Read-only GitHub App facts adapter - #682

Open
flow-research-agents[bot] wants to merge 9 commits into
mainfrom
agent/ws-gh-proof-001-02-github-facts-adapter
Open

flow-research-agents[bot] wants to merge 9 commits into
mainfrom
agent/ws-gh-proof-001-02-github-facts-adapter

Conversation

@flow-research-agents

@flow-research-agents flow-research-agents Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Change

WS-GHPROOF-001-02 - Read-only GitHub App facts adapter

Goal

A typed port and adapter that read one pull request's merge facts and its base branch's required checks from GitHub, as a read-only GitHub App, producing workstream.github_facts.v1.

Intent And Planning Context

What Changed

  • app/interfaces/github_facts.py: port, frozen facts model, typed errors.
  • app/adapters/github/: ADR 0014 factory and app_facts.py (RS256 App JWT → repository-scoped installation token, cached until near expiry; PR, required status checks, paginated check runs, commit statuses; SHA-256 of each response body).
  • core/config.py and .env.example: App id, the private key as a redacted secret setting WORKSTREAM_GITHUB_APP_PRIVATE_KEY, API base, timeouts.
  • Registration in behaviour ownership, partition and the test lane catalogue.

Why It Changed

WorkStream has no GitHub integration; checking proof needs trusted facts read outside the checker sandbox.

Design Chosen

  • Required checks are the union of checks[].context and contexts. A check bound to an App counts only runs from that App. Commit statuses count only for any-source requirements.
  • Only the newest run (highest id) per required name is judged. Re-runs are common: a live test on Flow-Research/harnessy-v2 fix(loop): allow writer-directed reviewed starts #169 found 47 runs under 24 names, and judging any run gave a false failure.
  • Only success passes. No branch protection or no required checks fails closed (non-retryable).
  • Bounded retries for 5xx and rate limits within a 45 s default deadline (maximum 120 s), then a typed facts-unavailable error. It never passes on missing facts.
  • The key and installation tokens never appear in reprs, exception messages or log records.

Alternatives Rejected

  • Treating neutral/skipped as passing, as GitHub does: rejected for now because the facts gate payment; open for the team's view.
  • A new HTTP dependency: httpx and PyJWT[crypto] already exist.

Scope Control

Allowed Files Changed

  • The files listed above.

Files Outside Stated Scope

  • None

Product Behavior

  • No Workstream product behavior changed. (The adapter is registered but not invoked.)

Evidence

Commands Run

pytest tests/test_github_facts_adapter.py
pytest config, observability, lane catalogue, behaviour ownership and module boundary tests
ruff; docstring coverage; behaviour-ownership, module, authorization and test-structure validators

Result Summary

44/44 new tests pass; 558 passed in the wider focused set. Ruff and validators pass; docstring coverage 80.2%.
Mutation spot-checks: breaking redaction, the log line or latest-run selection makes the matching tests fail.
Not run locally: the full backend suite (uv.lock is Linux-only); CI runs it.

Acceptance Criteria Proof

  • Happy path, pagination, 404 PR, missing protection, 5xx retry then success, retries exhausted, rate limits.
  • Re-run selection in both directions (old fail/new pass → success; old pass/new fail → failure).
  • Secret never in exception messages, reprs or log records.

Test Delta

Tests Added

  • backend/tests/test_github_facts_adapter.py

Tests Modified

  • backend/tests/test_ci_lane_catalogue.py (shared-family fingerprint for the new module)

Tests Removed Or Skipped

  • None

Impact-Routed Reviewer Results

Reviewer Result Blocking findings Proof boundary and uncertainty
security PROVISIONAL none Author-side review of credential custody and required-check selection only; no independent security reviewer has run.

Remaining Risks

  • A required check accepted from any source could be satisfied by a check created by a workflow in the PR itself. This matches GitHub's own branch-protection semantics; the human merge approval remains the guard.
  • Reading classic branch protection needs the App's Administration read permission.

Follow-Up Work

Chunk 04 wires this into post-submit evaluation after #677, and decides whether a missing PR is a checker finding or an infrastructure failure.

Human Review Focus

Please inspect:

  • Credential custody in app_facts.py and the secret setting.
  • Required-check selection (_required_checks, _latest, _conclusion).

Update: integrity and security-review fixes

  • Facts now include the PR author, every review (unfiltered), and every changed file (paginated). More than 3,000 files, or a listing shorter than its count, fails with GitHubFactsIncompleteError.
  • Each required check records whether it is App-bound, the App of the judged run, the judged run's html_url, details_url and workflow run id, and whether a commit status was judged.
  • TOCTOU: after all reads the PR is read again. If head SHA, merged, merge SHA, base, state or file count changed, the whole read repeats (up to 3 times within the deadline), then GitHubFactsInconsistentError. Both PR reads are hashed, and check pages for another commit are rejected.
  • Parser differential: facts carry GitHub's PR html_url. parse_pull_request_url is the single strict parser chunk 04 must use.
  • Tests: 73/73 in the module; 688 with the related suites.

CI And Gate Integrity

  • No workflow weakening.
  • No lint/test/docstring gate weakening.
  • Tests protect meaningful behavior; removals identify retained proof or retired requirements. Coverage percentages are diagnostic only.
  • No package script weakening.
  • No unpinned new GitHub Action.
  • Checkout credential persistence disabled where checkout is used.

Human Merge Ownership

The human completes the acceptance/merge checks; agents must not tick them on
the human's behalf or infer approval from a passing CI status.

  • I can explain what changed.
  • I can explain why it changed.
  • I know what could break.
  • I accept the remaining risks.
  • The user explicitly approved this specific PR for merge.

🤖 Generated with Claude Code

durutheguru and others added 2 commits October 24, 2026 13:34
Typed GitHubFactsAdapter port and GitHub App provider registered per
ADR 0014. Reads pull request, classic branch-protection required checks,
check runs and commit statuses with bounded retries and secret-free errors.
No production caller yet (WS-GHPROOF-001-02).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the most recent check run and commit status per required check
count; required checks are the union of protection checks and contexts.
The App private key is the WORKSTREAM_GITHUB_APP_PRIVATE_KEY secret
setting with the existing redacted custody path, replacing the key file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 33a43234-fc53-4f7c-84bd-650b1c3d4184

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · 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.

durutheguru and others added 5 commits October 24, 2026 14:55
The architecture proof counts every ExternalServiceAdapterFactory call site.
Add the GitHub adapter package as one more approved composition root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Integrity facts for owner decision 20: PR author, all reviews, all
changed files (fail closed when GitHub cannot list every file), and the
producing App of each judged required check. The reader makes no policy
decision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Security review (time-of-check binding): re-read the pull request after
all other reads and require head, merge state, base, state and file
count to match; retry the whole read within the deadline, then raise the
retryable GitHubFactsInconsistentError. Check runs and combined statuses
must report the head SHA, and each required check records the commit it
was judged on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Security review (parser differential): facts carry GitHub's pull-request
html_url and each judged run's html_url, details_url and Actions
workflow run id; parse_pull_request_url is the single strict parser for
claimed pull-request URLs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rejecting tests for malformed keys, installation lookups, token
exchanges, pull requests, protection, listings, check results, rate-limit
headers and deadline exhaustion; remove three unreachable branches.
Branch coverage of the adapter and port is now 100%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@durutheguru
durutheguru marked this pull request as ready for review October 24, 2026 17:52
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-24T17:54:32.951926Z b905f25 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b905f25081

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +563 to +564
timeout=timeout,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Enforce an absolute deadline around the facts read

If GitHub sends response chunks frequently enough to avoid HTTPX's read-inactivity timeout, this await can continue beyond github_facts_total_deadline_seconds: the scalar HTTPX timeout limits individual network waits, not total request duration. The budget is checked only before each request, and successful responses return immediately, so an overdue final pull-request reread can even return successful facts. Wrap the complete facts operation in an absolute asynchronous timeout, including token-lock acquisition, and translate expiry to GitHubFactsUnavailableError so the advertised total budget actually bounds execution.

Useful? React with 👍 / 👎.

Base automatically changed from agent/ws-gh-proof-001-01-initiative to main October 24, 2026 20:22
durutheguru and others added 2 commits October 24, 2026 21:24
Resolves the behavior-ownership partition conflict by regenerating
partition.v1.json with scripts.behavior_ownership (entries from both
sides kept; only authority_digest recomputed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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