Skip to content

fix(pingora): read Contents-API-oversized files through the Git Blobs API - #1946

Open
seonghobae wants to merge 2 commits into
mainfrom
lane-jan/pingora-oversized-blob-evidence
Open

fix(pingora): read Contents-API-oversized files through the Git Blobs API#1946
seonghobae wants to merge 2 commits into
mainfrom
lane-jan/pingora-oversized-blob-evidence

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

required-workflow-bootstrap fails closed in about 5 s with Pingora edge policy could not establish complete evidence: GitHub content evidence for docs/sbom/inventory.json exceeds the size contract on #1678 (run 33989047645, and every push of that automation branch). The mechanism is deterministic and has nothing to do with Nginx:

  • The SBOM inventory automation regenerates docs/sbom/inventory.json at 1,148,611 bytes (236 bytes on main).
  • GitHub omits the diff patch for a file that large, so _needs_content_scan returns True on patch absence (.json is neither a documentation suffix nor a binary document format).
  • The Contents API answers encoding: "none" with an accurate size for anything over its 1 MiB inline ceiling, and _load_raw_file_bytes turned that into ContentSizeExceededError, which only the documentation-PDF path knows how to absorb. Everything else fails the whole check closed.
  • Scanned offline with main's own scan_content, the file carries zero Nginx runtime forms (it does not even contain the string nginx).

So the SBOM inventory could never pass the required policy, and the same would hold for any PR that adds a text file over 1 MiB.

Change

scripts/ci/pingora_edge_policy.py

  • _resolve_oversized_content follows a Contents response that could not inline the file to its blob sha and fetches the same blob through the Git Blobs API (/repos/{repo}/git/blobs/{sha}, already inside _validate_github_api_url's origin and /repos/ path rule, same contents: read permission the Contents call needs).
  • _load_oversized_blob_bytes binds every blob field back to the Contents metadata it was reached from: the response sha must be the one requested, its size must equal the declared size, and the decoded bytes must have exactly that length; any other shape is a malformed-evidence PolicyError that fails closed, exactly as for an inline response.
  • New MAX_BLOB_BYTES = 11 MiB, chosen so a 60-column-wrapped base64 blob response plus its JSON envelope fits _github_open_json's existing 16 MiB MAX_RESPONSE_BYTES bound with margin; test_blob_ceiling_fits_the_bounded_response pins the arithmetic.
  • ContentSizeExceededError keeps its narrow meaning for the remainder: a declared size over the blob ceiling, or a response with no well-formed blob sha to follow. The oversized-documentation-PDF suffix convention therefore now applies only there, and a .pdf within the blob ceiling is verified by its %PDF- magic bytes instead of trusted on its suffix (strictly stronger than before).

docs/policies/PINGORA_EDGE_POLICY.md and CHANGELOG.md describe the new bound.

Verification

  • tests/test_pingora_edge_policy.py: 18 new tests — the chore: refresh org SBOM inventory #1678 shape end to end (oversized patchless docs/sbom/inventory.json, clean → (), with FROM nginx appended → nginx_container_image at line 2, proving it is scanned rather than exempted); an oversized real PDF passes on magic bytes and a textual file named .pdf is rejected; a PDF over MAX_BLOB_BYTES still uses the suffix convention with no blob request; the older base64-with-empty-content oversized shape takes the same route; five malformed/missing-sha shapes keep the size-contract signal without any blob request; seven malformed blob responses fail closed as plain PolicyError, never as ContentSizeExceededError; the ceiling arithmetic contract. Every pre-existing test is unchanged and passes.
  • Full gate on db361daa8 with GITHUB_ACTIONS=true: 2921 passed, 1 skipped, coverage report --fail-under=100 → 100%, interrogate → 100%.
  • Offline reproduction: scan_content("docs/sbom/inventory.json", <#1678 head content>) → 0 violations, 1,148,611 bytes.

Chicken-and-egg note: required-workflow-bootstrap runs the base branch's pingora_edge_policy.py at the immutable required-workflow SHA, so this PR's own contexts cannot exercise the change; #1678 (or any oversized-text PR) will, once this is on main.

Developer experience

Two small helpers with docstrings that state the binding rules and why the ceiling is 11 MiB; no new dependency, no change to the opener contract, no change to how any inline file is handled.

User experience

None visible to PR authors of ordinary files. Authors of a PR that adds or regenerates a text file over 1 MiB get a real content verdict instead of an unconditional "exceeds the size contract" failure; the SBOM inventory automation becomes mergeable on its merits.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4


Generated by Claude Code

… API

The Contents API stops inlining content at 1 MiB and answers
`encoding: "none"`; `_load_raw_file_bytes` turned that into
ContentSizeExceededError and, for any file that is not a documentation
suffix or a verified binary document, the whole check failed closed.
#1678's regenerated docs/sbom/inventory.json (1,148,611 bytes, no diff
patch, zero Nginx runtime forms when scanned offline with this module)
therefore failed required-workflow-bootstrap in 5 s on every push.

Follow the Contents response's blob `sha` to the Git Blobs API (bounded
by a new MAX_BLOB_BYTES of 11 MiB so the 60-column-wrapped base64
response fits the 16 MiB reader), bind every blob field back to the
Contents metadata it was reached from, and scan the bytes like any
inline file. ContentSizeExceededError keeps its narrow meaning for a
file over the blob ceiling or a response with no well-formed blob sha;
the oversized-documentation-PDF suffix convention now applies only
there, so a .pdf within the ceiling is verified by its magic bytes.

Gate: 2921 passed / 1 skipped with GITHUB_ACTIONS=true, coverage 100%,
interrogate 100%; tests/test_pingora_edge_policy.py 85 passed (18 new).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 10 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 4dce7967-2006-4fe1-9ec9-e3bcd87e085e

📥 Commits

Reviewing files that changed from the base of the PR and between efb8926 and cf76b40.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • docs/policies/PINGORA_EDGE_POLICY.md
  • scripts/ci/pingora_edge_policy.py
  • tests/test_pingora_edge_policy.py

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.

@seonghobae
seonghobae marked this pull request as ready for review September 5, 2026 22:32

Copy link
Copy Markdown
Contributor Author

CI status note on head db361daa8 — standing down on the two red checks.

CodeQL compatibility analysis (python) and (actions) (run 33996197171) ended with VERDICT_STATE=pending: the compat job's designed fail-fast after dispatching a CodeQL PR scan whose terminal verdict has not been published yet (catalog signature 9). Nothing in this diff is involved; the dispatch workflow re-runs these exact jobs once the verdict lands. Not re-running them manually — a re-run dispatches again and enlarges the queue that delays the verdict — and the dispatched scan also has to clear the OPENCODE_REPOSITORY_DISPATCH_ACTOR gate that #1929 tracks, which is an owner action.

Everything else on this head is green or queued: required-workflow-bootstrap, coverage source/evidence and the Pingora policy itself passed; strix, noema-review, and opencode-review are queued behind the organization runner ceiling.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

CI note on head db361daa8: noema-review (run 33996197307, job 101393472189) failed in "Prepare Noema model verdict" with HTTP Error 502: Bad Gateway; caller attempts=1, duration=2539.2s, phase=response_error, served_model=deepseek-ai/deepseek-v4-flash-0731. Gateway-side; nothing in this diff (the Pingora policy's blob route) is on that path. strix passed on this head; the two CodeQL shards are the designed pending state noted above.

This run is the first of mine created after #1944, so it shipped noema-sidecar-evidence (artifact 9980320306), and the per-candidate timeline is no longer inference:

  • Preflight: ready 5 / 12nvidia_nim deepseek-v4-pro, nvidia_nim_sub deepseek-v4-flash and v4-pro, openrouter cohere/north-mini-code and dots-3-note; rejected: primary-key v4-flash 529, the four gemma-3 404s, two OpenRouter gemma-4 429s.
  • Review phase, 00:43–01:26Z: nvidia_nim_sub deepseek-v4-flash was attempted 29 times and answered none — 24 TimeoutError at the 90 s per-recv limit, 2 HTTP errors; provider_exhausted attempts=3 nine times. Its circuit opened twice (failures=3.0 threshold=3 reset_seconds=30.0, 01:00:08 and 01:19:40), was back in service within a minute each time (circuit_reset 01:04:58, 01:25:10), and the final passthrough attempt at 01:25:10 (attempt=1/1) went to the same route and timed out at 01:26:40 → 502. openrouter cohere answered ProviderResponseError (permanent) three times and was also re-admitted after its circuit reset. nvidia_nim deepseek-v4-pro was attempted 4 times with no failure line.
  • Cost: about 36 of the 43 minutes were spent waiting on one route that never answered once.

So the ceiling on this class is not the pool alone: the breaker's 30 s reset is shorter than a single 90 s attempt, so a stalled route is re-admitted every cycle, and the candidate order keeps putting it first. That is contextual-orchestrator#1045's "request-scoped candidate exclusion" RED, now with the evidence it asked for (posted there). Standing down on this check; no re-run while the served set contains a route that stalls on every contact. The next base-merge push carries the current sidecar pin and re-runs it.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

CI note on head db361daa8, third red check: opencode-review (run 33996197314, job 101401467187) failed in seconds at "Fail closed without a current-head OpenCode verdict" — catalog signature 1, not a review verdict; no opencode-agent review exists on this head. The dispatch step succeeded and created handler run 34004439058 (queued 01:39Z), but every app-token handler completed since 2026-09-05T17:00Z has been rejected in validate-pr-metadata because opencode-agent[bot] is not in OPENCODE_REPOSITORY_DISPATCH_ACTOR (latest rejection 01:30Z on #1916's handler). #1932's multi-identity parser is on main; the variable is an owner action tracked in #1929, where I have also noted that the one scheduler-dispatched handler that passed the gate tonight ended in a deterministic REQUEST_CHANGES on an exhausted model pool.

Nothing in this diff is involved, and no push or re-run from this side changes the outcome — a re-run re-dispatches into the same rejected gate, and the dispatch workflow re-runs this exact job by itself once a verdict is published. Standing down on this check. Current head state: strix passed, noema-review failed on the stalled-route loop noted above, CodeQL shards designed-pending.


Generated by Claude Code

seonghobae pushed a commit that referenced this pull request Sep 6, 2026
… size contract)

Signature 3: the first post-#1939 noema-review runs split 1/1; the
failing run's policy report shows the diversified pool #1939 promised
and still ends in a 502 after a ~548 s-per-route walk (host 1's
arithmetic from source), so a base-merge push recovers pre-#1939 heads
but does not shorten the post-#1939 walk; #1943/#1944/#1945 make the
per-route timeline readable from the noema-sidecar-evidence artifact;
the remaining lever is inside contextual-orchestrator.

Signature 12: required-workflow-bootstrap exit 2 in ~5 s on
"exceeds the size contract" -- the Contents API's 1 MiB inline ceiling
on a patchless text file, fixed by #1946's Git Blobs API route.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

OpenCode reviewed the current-head mergeability evidence and changed-file flow before approval, then found merge conflicts on the affected path.

Findings

1. HIGH Merge Conflict Guidance - Resolve the PR branch against the latest base branch

  • Problem: GitHub reports mergeStateStatus DIRTY for this pull request.
  • Root cause: Branch lane-jan/pingora-oversized-blob-evidence cannot be merged cleanly into main; the changed-file flow below shows which review/runtime path is blocked by the conflict.
  • Fix: Merge or rebase the latest main into lane-jan/pingora-oversized-blob-evidence, resolve conflict markers in the PR branch, rerun the focused checks, and push the same branch.
  • Repair commands:
gh pr checkout 1946 --repo ContextualWisdomLab/.github
git fetch origin main
git merge --no-ff origin/main  # or: git rebase origin/main
git status --short
# resolve files, then git add <resolved-files>
# merge path: git commit
# rebase path: git rebase --continue
git push origin HEAD:lane-jan/pingora-oversized-blob-evidence
# rebase path only: git push --force-with-lease origin HEAD:lane-jan/pingora-oversized-blob-evidence
  • Regression test: Keep OpenCode approval gated on mergeability so model-output failures cannot approve a conflicted PR.

Merge Conflict Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Repository file: CHANGELOG.md"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Docs: PINGORA_EDGE_POLICY.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["docs review"]
  Evidence --> S3["CI script: pingora_edge_policy.py"]
  S3 --> I3["review and security gate shell path"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test: test_pingora_edge_policy.py"]
  S4 --> I4["regression suite"]
  I4 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V4["targeted test run"]
Loading
  • Result: REQUEST_CHANGES
  • Reason: mergeStateStatus is DIRTY; mergeable is CONFLICTING.
  • Head SHA: db361daa819ef31cf99e5cc5431405218abe6f2a
  • Workflow run: 33998627665
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Repository file: CHANGELOG.md"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Docs: PINGORA_EDGE_POLICY.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["docs review"]
  Evidence --> S3["CI script: pingora_edge_policy.py"]
  S3 --> I3["review and security gate shell path"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test: test_pingora_edge_policy.py"]
  S4 --> I4["regression suite"]
  I4 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V4["targeted test run"]
Loading

@opencode-agent

opencode-agent Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

…ence

CHANGELOG.md: both new top entries kept, main's pin-bump entry first.

Binds the sidecar pin bump to contextual-orchestrator@414f2297
(contextual-orchestrator#1081's retry-stacking fix, .github efb8926) and the
#1943/#1944/#1945 workflows to this head's required runs; the previous head's
Noema/Strix runs failed on the stalled-route loop that fix removes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4

Copy link
Copy Markdown
Contributor Author

CI note and push: head db361daa8cf76b40c7 (a base merge only; no change to the PR's own commits; 4 h 47 m since the previous push — earlier than the usual batching because it resolves a real conflict).

Merges main@efb892692, the owner's bypass-merged sidecar pin bump to contextual-orchestrator@414f2297 (contextual-orchestrator#1081, the fix for the _invoke retry-stacking loop that this head's own noema-sidecar-evidence artifact showed: one route attempted 29 times), plus #1943 / #1944 / #1945. That bump added a CHANGELOG.md entry at the same top position as this PR's, which is the DIRTY / CONFLICTING state OpenCode's REQUEST_CHANGES on db361daa8 reported; resolved by keeping both entries with main's newer one first, no other file touched.

Local gate on cf76b40c7 with GITHUB_ACTIONS=true: 2921 passed / 1 skipped, coverage 100%, interrogate 100%, git diff --check clean; the head is mergeable again. strix passed on the previous head; noema-review now runs on the fixed pin; opencode-review stays fail-closed until #1929's variable is set (the OpenCode verdict above was produced by a scheduler-path dispatch and will need a fresh one for this head); the CodeQL shards will read designed-pending again.


Generated by Claude Code

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.

2 participants