Skip to content

Declare executable archive members and environment helpers; self-test with archive modes - #15

Merged
suffro merged 11 commits into
mainfrom
feat/archive-member-executables
Nov 5, 2026
Merged

suffro merged 11 commits into
mainfrom
feat/archive-member-executables

Conversation

@suffro

@suffro suffro commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • assetArchives[].executables declares expanded members that need the executable bit, relative to the archive destination after stripComponents. The build rejects unsafe, duplicate (within and across archives), missing, non-regular, linked or link-traversing paths, and declarations removed by prunePaths or removeAfterExtract. Linux/macOS ship them as 0755; Windows validates identically and keeps extension-based executability.
  • executablePaths declares helpers the solved environment installs under venv/ outside the scripts directory (e.g. a compiler binary inside a package's own directory), which until now always shipped as 0644. Literal paths only. The reader refuses paths outside venv/ and paths an asset, local file or archive destination already owns, so every executable has one declaration; the build requires a link-free regular file after pruning.
  • The self-test and parity run with the modes the archive will carry. Regular files get the archive writer's synthesized modes before testing, so a helper that only worked because of an inherited upstream bit now fails at build time instead of on the consumer. The failure keeps the original error and points to the declarations; on Windows it is left untouched.
  • ZIP asset archives now reject links before copying, matching TAR.
  • Schema uniqueItems is now enforced by the internal validator.
  • Conformance fixture extended for an executable archive member under umask 077; the Node, Python and Rust consumers prove it.
  • Rust: three assert!(x.is_empty()) rewritten as assert_eq! for the assert_is_empty lint in clippy 1.99 (pre-existing code; CI would fail on main too).
  • Docs, white paper, design decisions, changelog and .context/ updated.

Additive build input within schema version 3: no wire, payload-digest, kind or signature change. Consumers need no upgrade.

Test plan

  • npm test: 661 passed, 1 macOS-only skip (Linux/WSL)
  • New guards proven red by disabling each one (8 failures), then restored
  • Python consumer: 68 passed; Rust: 112 passed, clippy clean
  • cd docs && npm run build, npm run action:check
  • Real packed build, install and run under umask 077, byte-identical rebuild (Linux/WSL), for archive members
  • Real build with executablePaths: conda-forge libtool config.guess refused undeclared, built declared (0755 in ZIP, sibling 0644), consumed under umask 077 and run (exit 0), byte-identical rebuild
  • Native Windows: see .context/history/windows-native-validation.md (remaining failures need the Windows symlink privilege, as on main)
  • CI matrix

🤖 Generated with Claude Code

Every self-test failure was prefixed with an executable-bit hint, including
ordinary import errors, and the hint pointed only at fields that cannot mark a
helper the solved environment installs outside the scripts directory. The
original error now comes first, the hint is conditional and says that case has
no declaration yet, and Windows, which has no modes to lose, keeps the original
error untouched.

Archive membership now joins the destination exactly as the declaration does.
The open follow-up is recorded in .context/state/current.md.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Deploying scrollcase with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9582e80
Status: ✅  Deploy successful!
Preview URL: https://021f8a2f.scrollcase.pages.dev
Branch Preview URL: https://feat-archive-member-executab.scrollcase.pages.dev

View logs

Rust 1.99 clippy adds assert_is_empty, which CI denies through -D warnings. The three assertions predate this branch; assert_eq! against an empty value also prints what was found when one fails.
A package can keep a helper binary in its own directory inside the prefix,
outside the scripts directory the runtime rule covers. It always shipped as
0644, and the mode-faithful self-test turned that into a build failure with
nothing an author could declare.

Top-level executablePaths names such files: literal paths under venv/. The
reader refuses a path outside the environment root and any path an asset,
local file or archive destination already owns, so each executable keeps one
declaration. After pruning, the build requires a link-free regular file, then
adds the paths to the declared set driving the entry-point guard, self-test
modes and archive. Optional build input inside schema version 3; signed
documents, digest and consumers are unchanged.
@suffro suffro changed the title Declare executable asset-archive members and self-test with archive modes Declare executable archive members and environment helpers; self-test with archive modes Nov 5, 2026
@suffro
suffro merged commit 16fc5dd into main Nov 5, 2026
19 checks passed
@suffro
suffro deleted the feat/archive-member-executables branch November 5, 2026 10:04
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