Skip to content

fix(download): reject oversized runtime metadata before replacement - #312

Merged
steipete merged 2 commits into
mainfrom
codex/ocm-round8-download
Oct 7, 2026
Merged

steipete merged 2 commits into
mainfrom
codex/ocm-round8-download

Conversation

@steipete

@steipete steipete commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

What Problem This Solves

Runtime metadata could consume unbounded memory while loading a custom manifest or gzip-compressed registry response. This completes the decoded-byte bound proposed in #117 and proves that rejecting an oversized update source preserves an existing installation.

User Impact

Runtime release JSON is now limited to 64 MiB after decompression. Sources at the limit still work. Operators with larger custom manifests must reduce their metadata before retrying; an oversized source is rejected before downloading replacement artifacts or changing installed runtime files and metadata.

The final squash commit declares this cutoff as a BREAKING CHANGE under the repository release policy, so a future automatic patch release must stop for an explicit version decision. No package version is changed here.

Why This Change Was Made

The shared JSON reader applies the existing capped-copy mechanism before parsing, so plain and gzip-expanded responses follow the same limit. The usage guide describes the compatibility boundary. This retains @SebTardif's original approach and adds exact-boundary and installed-runtime regression coverage.

The changelog also records the already-landed fixes in #307–#310, with contributor credit, so their user-visible behavior is available for the next release.

Evidence

Both new rejection regressions failed against unchanged production code: oversized gzip JSON was accepted, and the CLI accepted an oversized valid update manifest and replaced the installed runtime. After the fix, all download tests passed, including acceptance at exactly 64 MiB. The installed-runtime regression passed with byte-identical metadata and original executable content, no replacement file, and no request for the replacement artifact.

The ordered isolated AWS Linux baseline passed with Rust 1.99.0 and Node.js 24.21.0: formatting, 33 automatic-release policy tests, all-target compilation, all 1,317 Rust tests, isolated cargo install --locked --path ., and the installed ocm --version (0.2.48). Rust 1.88 all-target compilation also passed.

The installed binary fetched the live official catalog successfully (266 releases; stable 2026.9.8 at the time of the check). Independent Codex review completed with no actionable P0–P2 findings. Hosted platform checks remain required before merge.

The remote proof covers the current application, Rust tests, and dependency inputs. The subsequent base change in #313 only adds npm notarization failure diagnostics; refreshed hosted CI is required for this head. The branch history and prepared final squash body both contain the recognized compatibility declaration.

@clawsweeper

clawsweeper Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Oct 7, 2026
@clawsweeper

clawsweeper Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed October 6, 2026, 11:55 PM ET / October 7, 2026, 03:55 UTC (Revision 3).

ClawSweeper review

What this changes

The branch limits decoded runtime metadata to 64 MiB, adds boundary and installed-runtime preservation coverage, documents the cutoff, and records recent fixes in the changelog.

Merge readiness

✅ Ready for maintainer review

The fix remains necessary: neither current main nor v0.2.48 bounds decoded JSON. No actionable correctness or security defect was found, and the current head resolves the previous breaking-change declaration blocker.

Likely related people: SebTardif, vincentkoc, and shakkernerd are relevant routing candidates based on prior download and runtime work.

Priority: P2
Reviewed head: 97d10f7c9a5eb467845d2586d2ee8ea0f1e2f629

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) A focused implementation with strong boundary and installed-state coverage, documented compatibility impact, and the prior release-declaration blocker resolved.
Proof confidence 🌊 off-meta tidepool Not applicable: Verified repository-admin authorship exempts this PR from the external-contributor proof gate. Supplemental evidence reports the real CLI and HTTP transport rejecting an oversized update while preserving installed bytes, exact-limit gzip acceptance, and a successful live official-catalog fetch; this reviewer did not rerun them. No persisted schema or serialized format changes.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: Verified repository-admin authorship exempts this PR from the external-contributor proof gate. Supplemental evidence reports the real CLI and HTTP transport rejecting an oversized update while preserving installed bytes, exact-limit gzip acceptance, and a successful live official-catalog fetch; this reviewer did not rerun them. No persisted schema or serialized format changes.
Evidence reviewed 9 items Pinned introduced change: The verified merge-base-to-head delta contains five files and only one production-code change: applying the existing capped-copy helper before JSON parsing.
Still necessary on main and in the release: Current main and v0.2.48 both parse the decoded reader directly with serde_json::from_reader. The artifact download cap does not bound this metadata path. The latest published release endpoint still identifies v0.2.48.
Release source check: The shipped version retains the uncapped JSON reader; this PR is not redundant with a released fix.
Findings None None.
Security None None.

How this fits together

OCM reads release metadata from the official npm registry or custom manifests to select OpenClaw runtimes. Metadata validation precedes artifact downloads and publication of replacement runtime files.

flowchart TD
  A[Registry or custom manifest] --> B[HTTP reader and gzip decoding]
  B --> C{Decoded JSON within 64 MiB?}
  C -->|Yes| D[Parse and select release]
  D --> E[Download and publish runtime]
  C -->|No| F[Return size error]
  F --> G[Keep installed runtime unchanged]
Loading

Before merge

None.

Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production and test LOC production +7/-2; tests +120/-0 The small production change reuses the existing bound helper, with focused boundary and replacement-preservation coverage.

Technical review

Best possible solution:

Keep the decoded-byte bound before parsing and replacement, with the documented cutoff and recognized breaking-change declaration preserved at landing.

Do we have a high-confidence way to reproduce the issue?

Yes, source establishes that current main parses decoded JSON without a byte bound, and the PR supplies focused before/after regressions for oversized gzip metadata and runtime updates. This read-only review did not execute them.

Is this the best way to solve the issue?

Yes, reusing the existing capped-copy helper at the shared decoded-reader boundary is a narrow solution that covers official and custom metadata before replacement.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 78f414cda7ba.

Labels

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🌊 off-meta tidepool and patch quality is 🦞 diamond lobster.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P2: This is a bounded runtime-metadata reliability fix without evidence of an active widespread outage.
  • merge-risk: 🚨 compatibility: Previously accepted custom manifests above 64 MiB will fail; the repository administrator explicitly accepts and documents this cutoff.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🌊 off-meta tidepool and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: Verified repository-admin authorship exempts this PR from the external-contributor proof gate. Supplemental evidence reports the real CLI and HTTP transport rejecting an oversized update while preserving installed bytes, exact-limit gzip acceptance, and a successful live official-catalog fetch; this reviewer did not rerun them. No persisted schema or serialized format changes.

Evidence

What I checked:

  • Pinned introduced change: The verified merge-base-to-head delta contains five files and only one production-code change: applying the existing capped-copy helper before JSON parsing. (src/infra/download.rs:174, 97d10f7c9a5e)
  • Still necessary on main and in the release: Current main and v0.2.48 both parse the decoded reader directly with serde_json::from_reader. The artifact download cap does not bound this metadata path. The latest published release endpoint still identifies v0.2.48. (src/infra/download.rs:171, 78f414cda7ba)
  • Release source check: The shipped version retains the uncapped JSON reader; this PR is not redundant with a released fix. (src/infra/download.rs, 6c563651c7f0)
  • Replacement sequencing and existing-state preservation: Runtime update resolves release metadata before preparing or committing replacement files. The new regression runs the actual OCM subprocess with isolated state and a real TCP HTTP server, then checks the size error, byte-identical old metadata and executable, absent replacement file, and zero candidate-artifact requests. The captured PR body reports that this regression failed before the fix and passed afterward on the remote Linux worker. (tests/runtime_command_tests.rs:3391, 97d10f7c9a5e)
  • Exact decoded boundary: The new HTTP tests exercise gzip rejection one byte above the limit and acceptance exactly at 64 MiB through both public JSON-fetch entrypoints. The existing helper reads at most the cap into the buffer and probes one additional byte. (tests/download_tests.rs:160, 97d10f7c9a5e)
  • Previous review blocker resolved: The exact pinned head contains a recognized BREAKING CHANGE: footer describing oversized-source rejection and preservation of installed state. Its immediate-parent tree comparison is empty. The release reconciler recognizes this footer and stops automatic patch allocation when it is retained in merged commit metadata; the captured PR body also states that the prepared final squash body contains it. (scripts/auto-release.py:85, 97d10f7c9a5e)

Likely related people:

  • unknown: The claimed source-line change could not be verified from bounded local history. (role: source history unknown; confidence: low)
  • unknown: The claimed source-line change could not be verified from bounded local history. (role: source history unknown; confidence: low)
  • shakkernerd: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (2 earlier review cycles)
  • reviewed 2026-10-07T03:10:41.880Z sha ba3f42d :: needs maintainer review before merge. :: none
  • reviewed 2026-10-07T03:29:28.885Z sha ba3f42d :: blocked before merge. :: none

steipete and others added 2 commits October 6, 2026 20:38
Bound decoded JSON before parsing and preserve installed runtime state when
an oversized update manifest is rejected. Add exact-limit and installed-state
regressions, document the custom-source compatibility boundary, and record
previously landed round-eight fixes in Unreleased.

Complete the approach proposed in #117.

Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
Record the compatibility boundary in commit metadata so the release reconciler
requires an explicit version decision. The tested application tree is unchanged.

BREAKING CHANGE: Runtime release JSON over 64 MiB after decompression is rejected.
Reduce larger custom manifests before retrying installation or updates. Existing
installed runtime files and metadata are preserved when the source is rejected.
@steipete
steipete force-pushed the codex/ocm-round8-download branch from ba3f42d to 97d10f7 Compare October 7, 2026 03:42
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Oct 7, 2026
@steipete
steipete merged commit 2e21cf5 into main Oct 7, 2026
14 checks passed
@steipete
steipete deleted the codex/ocm-round8-download branch October 7, 2026 03:58
@steipete

steipete commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Landed as 2e21cf5. The landed Git tree matches tested head 97d10f7c9a5eb467845d2586d2ee8ea0f1e2f629.

The final commit contains the machine-recognized BREAKING CHANGE: footer required by the re-review, and preserves Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>. The 64 MiB cutoff and large-custom-manifest upgrade behavior are documented.

Both rejection regressions failed before the fix: gzip-expanded JSON was accepted, and an oversized valid update manifest replaced the installed runtime. Afterward, exact-limit acceptance and oversized-source rejection passed; the update regression verified unchanged installed bytes and metadata and no replacement artifact request.

The ordered isolated Linux gate passed with Rust 1.99.0 and Node.js 24.21.0: diff/format checks, 33 release-policy Python tests, all-target compilation, 1,317 Rust tests, isolated Cargo installation/version smoke (0.2.48), and all-target Rust 1.88 compilation. The installed binary also fetched the live official catalog (266 entries, stable 2026.9.8 at verification time). Independent Codex reviews found no actionable P0–P2 code defects.

All 14 hosted checks passed at the final head, including Linux/macOS, Windows, Rust 1.88, npm, and CodeQL: https://github.com/openclaw/ocm/actions/runs/37568000261.

@steipete

steipete commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Post-merge main verification passed on the first attempt at 2e21cf5: https://github.com/openclaw/ocm/actions/runs/37569240684.

All nine CI matrix jobs and all four CodeQL analyses are green, including the Intel macOS signed/notarized npm fixture. Automatic release reconciliation was skipped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant