build(worker): raise the pypdf floor and pin to 6.18.0 - #188
Conversation
Refs #187 The advisory stream first-patches everything it knows about at 6.16.1, so an advisory-driven floor never reaches 6.17.0 ("Limit value for Roman numerals", 2026-09-04) or 6.18.0 ("Limit allowed length of indirect object tokens", 2026-09-07). Both are the same hardening class as the three advisories #156 exists for, and pypdf here parses user-uploaded files (worker/mem_worker/processors/pdf.py:79). Naming the floor 6.18.0 rather than leaning on the lock is what makes the requirement survive a from-scratch resolve: uv resolves to the newest release satisfying a floor, not to the floor. Locked with the CI-pinned uv 0.9.27. Of the 76 changed lock lines, 8 are pypdf; no other package's version moves (85 name/version pairs differ only for pypdf).
Head unchanged; the body needed a tracking-record keywordThe first Fixed by one clause in the Process section: Re-run The CI result the body said it had not runThe Evidence table had one honest gap — I wrote that the Worker test leg runs in
Everything else in this comment is a status record, not new evidence for the |
PeterGuy326
left a comment
There was a problem hiding this comment.
Review result
APPROVE for the current head 6e7536fe975ac60d38f47f25441e1e2f1dd0bfa7.
The diff is limited to the pypdf floor and the locked dependency resolution; git diff --check is clean. The latest head-matched policy run, Go, Worker, Web, PostgreSQL integration, recall, wrapper-compatibility, CodeQL, and dependency-review checks are green. The earlier linked-issue check failure is superseded by the later successful run. This is an approval of the current draft only; it does not mark the draft ready or authorize a release.
## Canonical requirement Refs bytefolk/.github#32 - Canonical Issue URL: bytefolk/.github#32 - Consumed revision: R1 - No automatic close keywords: acknowledged Decision reference: the initial R1 Issue body. It explicitly records that local candidates preceded this prospective publication record; no retrospective approval is claimed. ## Requirement trace | REQ/AC IDs | Changed files / domain | Tests or review evidence | |---|---|---| | REQ-001 / AC-001 | 4 exact-pinned version annotations | Exact expected-byte replacement PASS | | REQ-002 / AC-002 | 2 files in bytefolk/mem | Repository inventory PASS; aggregate 7 repositories, 13 files, 21 lines | | REQ-003 / AC-003 | Existing workflow content and modes | Parsed YAML and comment-stripped bytes identical | | REQ-004 / AC-004 | Current-head CI and independent review | Local independent replay recorded in the canonical R1 Issue linked above; hosted CI collected on head `f464f686` (19 of 20 checks succeed, see Validation); independent human review requested and still pending | ## File domains `.github/workflows/bytefolk-scorecard.yml` (47); `.github/workflows/bytefolk-security.yml` (58, 65, 68). Prepared parent / merge base: `2986fe38175f54d99f15dd38a498708c6ecd88cd` PR base at publication: `87db0dfe0507be2190fe2fdcce0e267be8224f4d`. Since that baseline `main` advanced by six commits through `3c13f04e` (#162, #160, #165, #188, #158, #204) — not only `web/package-lock.json` as previously stated here. None of them touched `.github/workflows/`, so the F9 workflow blobs and the PR diff are unchanged. The reviewed commit and original parent are preserved. Head: `f464f68636adc6bb5295c3818aa6654c46a3caad` — `d2a9ec5` plus one non-forced `Merge branch 'main'` commit (`f464f686`) that brought the branch up to `3c13f04e` so it is no longer `BEHIND`. Verified: `git rev-parse d2a9ec5:.github/workflows/bytefolk-scorecard.yml` and `...:bytefolk-security.yml` return the same blobs (`2058126c`, `48a507e0`) as at `f464f686`, and `git diff main...f464f68` is still exactly these 2 files, `+4/-4`. The comment-only payload is therefore byte-identical to the reviewed commit and the equality proof above holds on the current head. ## Scope and non-goals Correct only `# v4.37.4` to `# v4.37.9` on CodeQL uses-lines pinned to `cdf488f595d80d6e07e03d4674febd5ab45fa938`. The [official tag object](https://api.github.com/repos/github/codeql-action/git/tags/a35ac6e6798d72df5475948b28efb89edc2e19ca) resolves to that existing pin. Action SHAs, permissions, triggers, steps, matrices, other pins, and runtime code are unchanged. ## Validation - Exact commands: `ruby evidence/verify.rb --baseline` and `ruby evidence/verify.rb --committed` from the retained review packet; `git diff --check 2986fe3 d2a9ec5` from this repository. - Observed counts/results: PASS 2/2 files and 4/4 replacements here; aggregate PASS 13/13 files and 21/21 replacements. Baseline intentionally exits 1 after detecting all 21 stale annotations; committed verification exits 0. - Check URLs: collected on head `f464f686` — 19 of 20 checks succeed. The single failure is [`HTTP, CLI and MCP lifecycle`](https://github.com/bytefolk/mem/actions/runs/34807101354/job/103861020551), whose log is `pull access denied for minio/minio` at ~13s: a container-image pull failure in an unrelated job. The same workflow was green on `main` at `3c13f04e`, and the identical failure is present on #198 and #199, so it is not caused by this comment-only change. Root-cause tracking is separate and open. The strict verifier checks the changed-file allowlist; exact old blobs and line inventory; complete expected-byte replacement; absence of stale target annotations; parsed YAML equality; comment-stripped byte equality and SHA-256 digests; whitespace and unchanged modes; one commit with the exact parent; and clean worktrees with no untracked files. All passed. The independent replay is recorded in canonical R1. The verifier and inventory are retained outside repository commits. | ID | REQ/AC | Observable acceptance criterion | Command or manual steps | Environment | Expected | Observed | Status | |---|---|---|---|---|---|---|---| | V1 | AC-001, AC-002, AC-003 | Exact annotations with executable YAML unchanged | `ruby evidence/verify.rb --committed` | Ruby 2.6.10, Psych 3.1.0, isolated review packet | Exact scoped replacements and equality | 2/2 files; 4/4 lines; all invariants pass | PASS | | V2 | AC-004 | Hosted checks on this exact head | Inspect this PR's checks at `f464f686` | GitHub Actions | Applicable checks succeed | 19 of 20 succeed; `HTTP, CLI and MCP lifecycle` fails on `pull access denied for minio/minio` (infra, unrelated job, also failing on #198/#199, green on `main`) | PARTIAL | ## Security and compatibility Documentation annotation only. No dependencies, permissions, credentials, data flows, or runtime behavior change. The diff and commit identity were inspected for public-safe content. No CHANGELOG entry or behavior-documentation update is needed because only explanatory comments change. ## Known limitations Runtime suites, build, coverage, and dependency audits were not rerun for this comment-only change; no runtime test result is claimed. Hosted CI is separate from local equality proof. Two limits now apply: (1) the strict verifier's `one commit with the exact parent` invariant describes the reviewed payload commit `d2a9ec5`, not the current branch shape, which carries two additional `Merge branch 'main'` commits; (2) this PR is **not merge-ready yet** — repository `AGENTS.md` step 6 requires passing CI *and* an approval from someone other than the author, and `HTTP, CLI and MCP lifecycle` is red on the unrelated `minio` pull, so the green-CI half is unmet until that infrastructure failure is fixed. ## Risk and rollback Low-risk annotation correction. Roll back through an ordinary revert of this single commit. There is no migration or release action. ## Product review handoff - Implementation/publication owner: @PeterGuy326 - Automated pre-review result: independent local replay recorded in R1; no human approval implied. - Human final review: PENDING; no human review requested by this publication. - Merge ledger owner: @PeterGuy326 - Product reviewer: @PeterGuy326 - Milestone or release packet: N/A: bounded documentation annotation maintenance - Merge, CI, release, and model judgment do not accept or close the Issue: acknowledged ## Maintenance update (2026-09-14, @waterbro-8) Records written by the maintainer account, not by the implementation owner: - `f464f686 Merge branch 'main'` was pushed to this head branch (non-forced, `main` at `3c13f04e` is an ancestor of the head) to clear the `BEHIND` state this PR's own body said blocked merging. No workflow file content changed: both blobs are identical to `d2a9ec5`. - The stale facts above were corrected in place: the recorded head SHA, the "Main advanced only `web/package-lock.json` in PR #192" claim, the `NOT VERIFIED` hosted-CI rows, and the "this is a draft, not merge-ready" note. - This PR was marked ready for review and an independent review was requested. The maintainer account that pushed the merge commit did **not** approve it: `AGENTS.md` step 6 requires an approval from someone other than the author, and a commit author on the head cannot supply that approval for their own push. `@PeterGuy326` remains implementation and merge-ledger owner. Co-authored-by: 勒布朗-詹姆斯 <2986253039@qq.com>
Not a review vote, and not an acceptance
I am the author of this branch, so under this org's
require_code_owner+require_last_push_approvalconfiguration my own ticket cannot be the one thatclears it. Nothing here asks for a merge, a close, a label, or a tag. The
commitment is only: here is a change, here is what I measured.
Supersedes nothing by itself: #156 is a separate, still-valid Dependabot PR.
See Sequencing below.
What changes
Two files, +39/−39:
worker/pyproject.toml:31—"pypdf>=4.0"→"pypdf>=6.18.0"worker/uv.lock—pypdf 6.15.0 → 6.18.0, nothing else movesThat is the whole diff. No test, no docs, no CI file, no
CHANGELOG.mdentry:grep -i 'pypdf\|numpy\|torch\|dependabot' CHANGELOG.mdonmainreturnszero dependency-bump entries across its 381 lines, and #156 is 2 files too,
so an entry here would be inventing a convention.
Why the floor is written
>=6.18.0and not>=6.16.1Three open Dependabot alerts name
pypdfin this lock —#71(
GHSA-jp53-mhqp-8xcg,< 6.16.0),#72(GHSA-763m-79hh-57f2,< 6.16.1),#73(GHSA-23w6-3w8w-8484,< 6.16.1). This satisfies all three, the same as#156, once it is on the default branch.
It additionally takes two upstream releases that have no advisory, so no
alert will ever schedule them:
Security (SEC): Limit value for Roman numerals (#4047)Security (SEC): Limit allowed length of indirect object tokens (#4055)Re-measured for this PR:
GET /advisories?affects=pypdf→ 43 entries, alltype: reviewed, and the newestfirst_patched_versionanywhere in that set is6.16.1. Both new entries are the same hardening class as the three above
(bound an unbounded parser input), and the surface is the untrusted one:
worker/mem_worker/processors/pdf.py:79runsPdfReader(BytesIO(file.data))onuser-uploaded files.
Writing the floor at 6.18.0 rather than letting the lock alone carry it is the
part that survives a from-scratch resolve. Measured: uv resolves to the newest
release satisfying a floor, not to the floor —
>=6.16.1re-resolved todaylands on 6.18.0, and after the next release it would land past it, in a manifest
whose stated requirement was never 6.18.0.
Evidence
All of it executed on a tarball of
main @ 2986fe38175f54d99f15dd38a498708c6ecd88cdwhose tree was proved equal to the remote (
.commit.tree.shaf447ca554377e85ba26090d59882b8d4f2b78731==git init && git add -A && git write-tree), with the tool CI pins — uv0.9.27(ci.yml:185-187) — in asanitized env (no mirror/proxy variables;
uv lockthrough a mirror-configureduv rewrites thousands of URL lines and its "lock is stale" verdict is then
worthless).
uv lockon the untouched treeworker/uv.lock— the pin is reproducible, so everything below is about the resolve, not a stale tooluv lockafter only the constraint editUpdated pypdf v6.15.0 -> v6.18.0, 76 lock linespypdf 6.15.0 → 6.18.0uv lock --lockedrc=0— so the Worker leg'suv sync --frozen(ci.yml:193,UV_FROZEN: "1"at:170) accepts itae58b7d93c22c169ffb02c3b06321c45c4f223b4916536568adb57d789d95d01, wheel05b762b77bcb9dcb4a7c91fcf5dded585b25bee7269ab3d3001d7c55fa1b324b— byte-identical topypi.org/pypi/pypdf/jsontest_processor_logic.py:419) extracted at 6.15.0 / 6.16.1 / 6.18.0 on Python 3.11 (ci.yml:182)page_count, identicalsha256(extracted_text)(46e7c072b2684841…, 214 chars),"1800 RMB" in texttrue on all three, malformed input raises the samePdfStreamErroron all threeDEP: Rework configuration value handling (#4044))grepover the whole tree foroverwrite_configuration/apply_configuration/disable_legacy_handling/pypdf.constants→ 0 hits;pypdfappears in only 3 files (worker/pyproject.toml,worker/mem_worker/processors/pdf.py,scripts/seed_demo_data.sh)Checks 1–4 and 7 are the ones CI cannot shortcut; 6 is the one that says "the
worker's PDF path behaves the same", and 4 is the one that says "this lock is
self-consistent". The Worker test leg on the exact head remains the real proof
of the full pipeline (
test_processor_logic.py:457) — that runs in CI, I didnot run it here; the local venv has none of the Worker's own dependencies
installed.
About the diff size: of the 76 changed lock lines, 8 are pypdf (specifier,
version, sdist, wheel — each on both sides). The other 68 are uv's marker
renormalisation: the
python_full_version >= '3.15' and sys_platform == 'darwin'fork marker hopping betweentorch 2.13.0and2.13.0+cpu(likewisetorchvision 0.28.0/+cpu),python_full_versionnarrowing dropping offnumpy/scipy/tifffile, and theresolution-markerslist reordering.That is not avoidable churn I chose: a plain
uv lockon either side of a pincosts 0 lines, but any resolve that moves pypdf pays them — #156's own
+53/−53is the same shape. No other package's version changes.Process: this PR is ahead of its issue's readiness gate
AGENTS.mdrule 2 says not to implement a material change until its issue hasacceptance criteria and
status:ready. Refs #187, which I filed with the AClist and reproduction steps for exactly this; it is
status:needs-triage, andstatus:readyis a maintainer's label, not mine to set. So this is a draft,and undrafting it is the step that should follow that label rather than precede
it. If triage would rather the change go in behind #156, #187 can simply wait.
Sequencing with #156
Both branches touch the same two files, so they will conflict with each other,
not with
main.main— the manifest lineis a one-token edit and the lock is one
uv lockwith the pinned tool. Ioffered to do that; it is not something to do unasked.
three alerts are dismissed by this branch instead. I am not asking for build(deps): bump pypdf from 6.15.0 to 6.16.1 in /worker #156
to be closed — it has an in-force
APPROVEDfromPeterGuy326on itscurrent head and I am not in a position to spend someone else's ticket. That
call, and the release-cadence call about whether 6.17.0/6.18.0 belong in this
repo's Worker at all, is the owner's.
What I did not do
No review submitted, no vote, no merge, no close, no label change on anything
except the new issue's own labels, no ref moved on #156, no
Update branchclicked anywhere, no
CHANGELOG.mdedit, no tag, no publish.