Load the manifest check downloads from memory, not a temp file (closes #223) #227

Merged
clawbot merged 1 commits from issue-223-check-url-in-memory into next 2026-10-15 21:59:13 +02:00
Collaborator

Fixes #223.

mfer check given a URL wrote the manifest it downloaded to a file in the temp directory and loaded it from there. That failed in the image script/cibuild builds, which has no /tmp, and on any host whose TMPDIR cannot be written. It now reads the download into memory, as fetch, list and export do. fetchManifestToTemp is removed; downloadManifest replaces it with the same size limit and error messages.

The Checker read its manifest from the filesystem holding the files it checks, so it could not take a manifest held in memory while checking files on disk. CheckerOptions in package mfer gains ManifestReader, an io.Reader read in place of ManifestPath; only check sets it. A Checker built that way has no manifest file for FindExtraFiles to leave out.

verifyRequiredSigner takes the signer's fingerprint, empty for an unsigned manifest, instead of a Checker. fetch passes the signer of the manifest it has already loaded and builds no Checker; verifyFetchedSigner is removed. The --require-signature messages are unchanged.

TestManifestDownloadStopsAtLimit no longer looks at the temp directory, since neither command writes there. Without its t.Setenv it calls t.Parallel(), which the linter requires.

No new files. Changed: package cli (internal/cli/check.go, internal/cli/fetch.go, tests in internal/cli/entry_test.go, internal/cli/errmsg_test.go and internal/cli/fetch_test.go) and package mfer (mfer/checker.go, mfer/checker_test.go).

  • Judgement call: CheckerOptions.ManifestReader adds an exported field to the library while #83 is open.
  • Unchanged: checking against a URL, an index.mf in the base is reported as not in the manifest, as before.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/mfer/issues/223. `mfer check` given a URL wrote the manifest it downloaded to a file in the temp directory and loaded it from there. That failed in the image `script/cibuild` builds, which has no `/tmp`, and on any host whose `TMPDIR` cannot be written. It now reads the download into memory, as `fetch`, `list` and `export` do. `fetchManifestToTemp` is removed; `downloadManifest` replaces it with the same size limit and error messages. The Checker read its manifest from the filesystem holding the files it checks, so it could not take a manifest held in memory while checking files on disk. `CheckerOptions` in package `mfer` gains `ManifestReader`, an `io.Reader` read in place of `ManifestPath`; only `check` sets it. A Checker built that way has no manifest file for `FindExtraFiles` to leave out. `verifyRequiredSigner` takes the signer's fingerprint, empty for an unsigned manifest, instead of a Checker. `fetch` passes the signer of the manifest it has already loaded and builds no Checker; `verifyFetchedSigner` is removed. The `--require-signature` messages are unchanged. `TestManifestDownloadStopsAtLimit` no longer looks at the temp directory, since neither command writes there. Without its `t.Setenv` it calls `t.Parallel()`, which the linter requires. No new files. Changed: package `cli` (`internal/cli/check.go`, `internal/cli/fetch.go`, tests in `internal/cli/entry_test.go`, `internal/cli/errmsg_test.go` and `internal/cli/fetch_test.go`) and package `mfer` (`mfer/checker.go`, `mfer/checker_test.go`). - Judgement call: `CheckerOptions.ManifestReader` adds an exported field to the library while https://git.eeqj.de/sneak/mfer/issues/83 is open. - Unchanged: checking against a URL, an `index.mf` in the base is reported as not in the manifest, as before. Model: opus-5-5
clawbot added the needs-review label 2026-10-15 20:16:36 +02:00
clawbot self-assigned this 2026-10-15 20:16:40 +02:00
Author
Collaborator
  1. verifyFetchedSigner in internal/cli/fetch.go: check now hands a downloaded manifest to the Checker through the new CheckerOptions.Manifest, but fetch still writes its downloaded manifest into an in-memory filesystem for the same purpose, and the comment above that function still says it does so because a Checker loads its manifest from a file, which this change makes untrue. The new field is the right way to do it, since the Checker reads the files it checks from the same filesystem as its manifest file and check cannot use an in-memory one. Acceptable: verifyFetchedSigner builds its Checker with CheckerOptions.Manifest reading the downloaded bytes, with no in-memory filesystem, and its comment drops that reason, so both commands hand a downloaded manifest to the Checker the same way.

  2. TestManifestDownloadStopsAtLimit in internal/cli/fetch_test.go: it points TMPDIR at a new directory, checks that the directory is empty afterwards, and its comment says each command must "leave no temp file". That part covered the temp file check used to write; after this change neither command writes to the temp directory, so it tests code that no longer exists. Acceptable: drop the TMPDIR setup, the check that the directory is empty, and that clause of the comment.

Model: opus-5-5

1. `verifyFetchedSigner` in `internal/cli/fetch.go`: `check` now hands a downloaded manifest to the Checker through the new `CheckerOptions.Manifest`, but `fetch` still writes its downloaded manifest into an in-memory filesystem for the same purpose, and the comment above that function still says it does so because a Checker loads its manifest from a file, which this change makes untrue. The new field is the right way to do it, since the Checker reads the files it checks from the same filesystem as its manifest file and `check` cannot use an in-memory one. Acceptable: `verifyFetchedSigner` builds its Checker with `CheckerOptions.Manifest` reading the downloaded bytes, with no in-memory filesystem, and its comment drops that reason, so both commands hand a downloaded manifest to the Checker the same way. 2. `TestManifestDownloadStopsAtLimit` in `internal/cli/fetch_test.go`: it points `TMPDIR` at a new directory, checks that the directory is empty afterwards, and its comment says each command must "leave no temp file". That part covered the temp file `check` used to write; after this change neither command writes to the temp directory, so it tests code that no longer exists. Acceptable: drop the `TMPDIR` setup, the check that the directory is empty, and that clause of the comment. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-15 20:36:45 +02:00
Author
Collaborator

Rework scope: both findings above, plus one rename. The new field becomes CheckerOptions.ManifestReader, so its name says it is a reader and stays clear of the open question on exporting the manifest type (#83).

Model: opus-5-5

Rework scope: both findings above, plus one rename. The new field becomes `CheckerOptions.ManifestReader`, so its name says it is a reader and stays clear of the open question on exporting the manifest type (https://git.eeqj.de/sneak/mfer/issues/83). Model: opus-5-5
clawbot force-pushed issue-223-check-url-in-memory from 93c66b1c6e to 59b3cbd1dd 2026-10-15 20:48:30 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-15 20:48:39 +02:00
Author
Collaborator

Rework:

  • Finding 1: verifyFetchedSigner hands the downloaded bytes to the Checker through CheckerOptions.ManifestReader, with no in-memory filesystem, and its comment no longer gives the old reason. Superseded: fetch now builds no Checker and verifyFetchedSigner is removed (#227 (comment)).
  • Finding 2: TestManifestDownloadStopsAtLimit has lost the TMPDIR setting, the empty-directory check and the temp-file clause of its comment. With t.Setenv gone the linter requires t.Parallel(), so the test calls it.
  • Rename: the field is CheckerOptions.ManifestReader in the code, tests, comments, commit message and PR body.

Model: opus-5-5

Rework: - Finding 1: `verifyFetchedSigner` hands the downloaded bytes to the Checker through `CheckerOptions.ManifestReader`, with no in-memory filesystem, and its comment no longer gives the old reason. Superseded: `fetch` now builds no Checker and `verifyFetchedSigner` is removed (https://git.eeqj.de/sneak/mfer/pulls/227#issuecomment-143840). - Finding 2: `TestManifestDownloadStopsAtLimit` has lost the `TMPDIR` setting, the empty-directory check and the temp-file clause of its comment. With `t.Setenv` gone the linter requires `t.Parallel()`, so the test calls it. - Rename: the field is `CheckerOptions.ManifestReader` in the code, tests, comments, commit message and PR body. Model: opus-5-5
Author
Collaborator
  1. verifyFetchedSigner in internal/cli/fetch.go builds a Checker only to read the manifest's signer. It gives that Checker a base path of / that nothing reads, and needs its comment to explain why. With Fs no longer set, the Checker now sits on the root of the real filesystem, so anything that later asked it to check files or look for extra ones would search the whole disk. fetchManifest has already loaded the same bytes a few lines earlier, and that manifest's Signer() gives the fingerprint itself. The second load and the placeholder base path are there only because verifyRequiredSigner in internal/cli/check.go takes a Checker. Acceptable: verifyRequiredSigner takes the signer fingerprint, empty when the manifest is unsigned, instead of a Checker. check passes chk.Signer(), fetch passes the Signer() of the manifest it has already loaded, and verifyFetchedSigner is removed. Then fetch builds no Checker, CheckerOptions.ManifestReader is used by check alone, and the commit message and PR body describe it that way.
  • Judgement call: this replaces the form for verifyFetchedSigner that the earlier review (#227 (comment)) accepted.

Model: opus-5-5

1. `verifyFetchedSigner` in `internal/cli/fetch.go` builds a Checker only to read the manifest's signer. It gives that Checker a base path of `/` that nothing reads, and needs its comment to explain why. With `Fs` no longer set, the Checker now sits on the root of the real filesystem, so anything that later asked it to check files or look for extra ones would search the whole disk. `fetchManifest` has already loaded the same bytes a few lines earlier, and that manifest's `Signer()` gives the fingerprint itself. The second load and the placeholder base path are there only because `verifyRequiredSigner` in `internal/cli/check.go` takes a Checker. Acceptable: `verifyRequiredSigner` takes the signer fingerprint, empty when the manifest is unsigned, instead of a Checker. `check` passes `chk.Signer()`, `fetch` passes the `Signer()` of the manifest it has already loaded, and `verifyFetchedSigner` is removed. Then `fetch` builds no Checker, `CheckerOptions.ManifestReader` is used by `check` alone, and the commit message and PR body describe it that way. - Judgement call: this replaces the form for `verifyFetchedSigner` that the earlier review (https://git.eeqj.de/sneak/mfer/pulls/227#issuecomment-143707) accepted. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-15 21:10:20 +02:00
clawbot added 1 commit 2026-10-15 21:32:43 +02:00
check given a URL wrote the manifest it downloaded to a file in the temp
directory before loading it, so it failed wherever that directory is
missing or cannot be written, such as the scratch image script/cibuild
builds. It now keeps the manifest in memory, as fetch, list and export
do. NewChecker reads a manifest handed to it as a reader through the new
CheckerOptions.ManifestReader field, in place of ManifestPath, because it
otherwise reads the manifest from the filesystem holding the files it
checks. Only check uses that field. verifyRequiredSigner takes the
signer's fingerprint instead of a Checker, so fetch passes the signer of
the manifest it has already loaded and builds no Checker.

Model: opus-5-5
clawbot force-pushed issue-223-check-url-in-memory from 59b3cbd1dd to 977ceb1700 2026-10-15 21:32:43 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-15 21:32:55 +02:00
Author
Collaborator

Rework for #227 (comment):

  • verifyRequiredSigner takes the signer's fingerprint, empty for an unsigned manifest; check passes chk.Signer() and fetch the Signer() of the manifest it has already loaded.
  • verifyFetchedSigner is removed, so fetch builds no Checker and only check uses CheckerOptions.ManifestReader; the commit message and PR body say so.
  • The tests of the --require-signature messages pass a fingerprint; the unsigned cases pass an empty one, so the helper that built an unsigned Checker for them is gone.
  • Rebased onto current next.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/mfer/pulls/227#issuecomment-143785: - `verifyRequiredSigner` takes the signer's fingerprint, empty for an unsigned manifest; `check` passes `chk.Signer()` and `fetch` the `Signer()` of the manifest it has already loaded. - `verifyFetchedSigner` is removed, so `fetch` builds no Checker and only `check` uses `CheckerOptions.ManifestReader`; the commit message and PR body say so. - The tests of the `--require-signature` messages pass a fingerprint; the unsigned cases pass an empty one, so the helper that built an unsigned Checker for them is gone. - Rebased onto current `next`. Model: opus-5-5
Author
Collaborator

Review passed.

  • Judgement call: check has no end-to-end test of a manifest signed by a key other than the required one (only the message is tested, directly). That gap is older than this change, so I did not count it against it.

Model: opus-5-5

Review passed. - Judgement call: `check` has no end-to-end test of a manifest signed by a key other than the required one (only the message is tested, directly). That gap is older than this change, so I did not count it against it. Model: opus-5-5
clawbot merged commit 95a37d8009 into next 2026-10-15 21:59:13 +02:00
clawbot deleted branch issue-223-check-url-in-memory 2026-10-15 21:59:14 +02:00
Sign in to join this conversation.