Repository navigation
Make the llama wrapper quoting test pass on SIP-enabled Macs (wrapper unaffected) - #178
Closed
seathatflowsinourveins wants to merge 1 commit into
Closed
seathatflowsinourveins wants to merge 1 commit into
seathatflowsinourveins wants to merge 1 commit into
Conversation
LlamaWrapperQuotingTests failed on a SIP-enabled Mac (macOS 26.5.1) and passed on GitHub's hosted macos-15 runner. Its stand-in llama-server was a #!/bin/sh script: with System Integrity Protection enabled, macOS purges DYLD_* variables when it launches a SIP-protected binary such as /bin/sh, so the stand-in printed an empty DYLD_LIBRARY_PATH even though the wrapper had exported it. The product wrapper is not affected. It sets DYLD_LIBRARY_PATH after its own /bin/sh has started and execs the real llama-server, an unprotected, ad-hoc signed Mach-O, so the value arrives. On the same SIP-enabled Mac the pinned b11057 asset installed through install_llama_cpp into a shell-syntax path runs through the generated wrapper, and with its dylibs moved away the wrapper's DYLD_LIBRARY_PATH alone still loads them. The stand-in is now a script for the test's own Python, unprotected like the real binary. A control run first checks that this interpreter sees a DYLD_* value handed to it directly; if not, the test skips only the DYLD_LIBRARY_PATH assertion, after the data-safety assertions have run. The wrapper now receives DYLD_LIBRARY_PATH unset rather than empty: an inherited variable stays exported, so a missing export line had gone unnoticed on every non-SIP host. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This was referenced Sep 24, 2026
Merged
seathatflowsinourveins
added a commit
that referenced
this pull request
Sep 24, 2026
…nd the macOS pnpm 12.6.0 re-qualification (#201) * Record macos-m5pro-20260924 application and data use receipts Seven use-stage native_proven receipts were recorded on the Mac from a detached checkout of main 3699012, so catalog_revision stays reachable after a squash merge. All are pin-bound, all commands exit 0, and each carries --second-physical-machine and --hardware-profile-ref macos-m5pro-20260924: - postgresql 18.6: SHA-256-pinned source build, server running, Alembic 0001, a temp-table transaction summing to 6, then rolled back; - fastapi 0.141.1: 12 API tests against ledger_test and schema/type agreement; - nextjs 16.3.5: typegen, TypeScript check and production build; - react 19.3.0: production build and the Chrome create/update workflow; - playwright-test 1.63.0: 1 passed, 0 flaky; - playwright-cli 0.1.21: an isolated Chrome session created a run (revision 1), 0 console messages, servers stopped; - duckdb 1.5.5: mise-pinned; a 1,000-row Parquet round trip returned sum 332833500. The receipts ran through the committed blueprint (pnpm@12.4.2 self-pin), outside the Claude Code sandbox, which blocks PostgreSQL shared memory, loopback database connections and pnpm 12 network/store operations here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Record the macOS application re-qualification at the 2026-09-24 pins The 2026-09-24 catalog pin bumps (uv 0.12.18, pnpm 12.6.0) left the Mac application-slice gate unverified. The typed run-ledger blueprint was re-run on host macos-m5pro-20260924 and recorded as a platform-scoped convergence record, experiment-macos-20260924.json (observed, adopt_within_scope, native_cli_execution, zero model calls). pnpm 12 stores its own version in pnpm-lock.yaml as well as in packageManager, so the committed blueprint keeps running pnpm 12.4.2 whatever the global pin is. The qualifying run used a scratch copy with only that self-pin raised to 12.6.0. Both changed files are retained under evidence/artifacts/macos-application-20260924/variant/, and the lockfile's project dependency section is byte-identical. The blueprint itself is unchanged, so experiment.json's frozen inputs stay valid; the README says how to move the recipe with a new frozen record. All 15 attempts are retained in order. Six failed: - five inside the Claude Code Bash sandbox: pnpm self-pin/lockfile mismatch, pnpm registry TLS, initdb shared memory, loopback database connect, pnpm store lock; - one native attempt, a post-SIGTERM bind probe that saw a TIME_WAIT socket. The qualification is the last native attempt: setup and repeat, native PostgreSQL 18.6, Alembic up/repeat and down/base/re-upgrade, 12 API tests, drift/type/build checks, the Chrome Playwright Test, an isolated playwright-cli create/update, the same record after database and server restart, and release of the owned ports. Checks: validate_convergence.py on the record and --all-recorded (19 valid). Tampered copies (failed run as the qualification, altered variant hash, dropped failure entry) are each rejected. validate.py, validate_catalogs.py, build_ecosystem.py --check and evidence_manifest.py --check pass. unittest ran 3939 tests with 1 failure, the pre-existing SIP-related llama wrapper quoting test that #178 addresses; the 34 sandbox-only PermissionError cases pass outside the sandbox. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Regenerate the component evidence matrix for the macos-m5pro-20260924 application receipts component_matrix.py --write and evidence_manifest.py --write after the seven new receipts and the macOS convergence record. host_receipts validate (16), validate.py, component_matrix --check, new_host_grand_list --check, evidence_manifest --check, validate_convergence --all-recorded (19), validate_catalogs.py and build_ecosystem.py --check pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * List the retained macOS pnpm variant in the OSV lockfile inventory tests/test_osv_lockfile_coverage.py requires every tracked lockfile and manifest in .github/osv-scanner-lockfiles.json. The retained variant pnpm-lock.yaml joins lockfiles, and its package.json joins covered_by_lockfile against that lockfile, matching how the blueprint's own pair is listed. Its project dependency section is byte-identical to the blueprint lockfile already scanned. The only additions are pnpm's own 12.6.0 entries, for which the OSV API reports no known vulnerabilities (pnpm and @pnpm/exe, queried 2026-09-24). The inventory's hash is re-registered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Record independent reviews of the macos-m5pro-20260924 application and data receipts The foundation-lane-setup session reviewed the seven use receipts from #201 (postgresql, fastapi, nextjs, react, playwright-test, playwright-cli, duckdb) and appended an independent_session agree review to each. It re-ran every recorded command from a clean detached checkout of the recorded catalog_revision 3699012. Every command exited 0. Deterministic outputs match the recorded output_sha256 byte for byte. The rest match once the PID, checkout path, temp-dir name, timings or snapshot ref id are substituted. The review re-registers the receipt hashes and regenerates the component evidence matrix and the new-host grand list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
seathatflowsinourveins
added a commit
that referenced
this pull request
Sep 25, 2026
…(tests only; supersedes #178) (#228) * Make the llama wrapper quoting test observe DYLD_LIBRARY_PATH under SIP LlamaWrapperQuotingTests failed on a SIP-enabled Mac (macOS 26.5.1) and passed on GitHub's hosted macos-15 runner. Its stand-in llama-server was a #!/bin/sh script: with System Integrity Protection enabled, macOS purges DYLD_* variables when it launches a SIP-protected binary such as /bin/sh, so the stand-in printed an empty DYLD_LIBRARY_PATH even though the wrapper had exported it. The product wrapper is not affected. It sets DYLD_LIBRARY_PATH after its own /bin/sh has started and execs the real llama-server, an unprotected, ad-hoc signed Mach-O, so the value arrives. On the same SIP-enabled Mac the pinned b11057 asset installed through install_llama_cpp into a shell-syntax path runs through the generated wrapper, and with its dylibs moved away the wrapper's DYLD_LIBRARY_PATH alone still loads them. The stand-in is now a script for the test's own Python, unprotected like the real binary. A control run first checks that this interpreter sees a DYLD_* value handed to it directly; if not, the test skips only the DYLD_LIBRARY_PATH assertion, after the data-safety assertions have run. The wrapper now receives DYLD_LIBRARY_PATH unset rather than empty: an inherited variable stays exported, so a missing export line had gone unnoticed on every non-SIP host. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 3fd39cd) * Skip the symlinked-prefix platform-dependency test when npm is absent test_places_the_verified_tarball_correctly_when_the_prefix_is_reached_through_a_symlink uses the npm-packed fixtures that PlatformDependencyInstallTests.setUpClass builds only when npm is on PATH: self.verified_tarball directly and self.verified_sha256 through _platform_dependency_pin. Unlike its npm-dependent siblings it had no @unittest.skipUnless(NPM, ...) since it was added in #94, so on a host without npm it errored with AttributeError instead of skipping. Hosted runners have npm, so CI never hit it. The class's other three undecorated tests use no npm fixtures and still run without npm. Re-hash tests/test_adoption_bootstrap_macos.py in manifests/evidence.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Scout <scout@local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
tests.test_adoption_bootstrap_macos.LlamaWrapperQuotingTestsfails on a real Mac with System Integrity Protection (SIP) enabled and passes on GitHub's hostedmacos-15runner. The bug is in the test harness. The generatedbin/llama-serverwrapper works under SIP. This PR changes only the test and re-hashes it inmanifests/evidence.json.Root cause
llama-serverwas a#!/bin/shscript that printed$0and$DYLD_LIBRARY_PATH.DYLD_*variable when it launches a SIP-protected binary./bin/shis one (ls -lO /bin/shshowsrestricted).DYLD_LIBRARY_PATHafter its own/bin/shhas started, thenexecs its target:/bin/shagain, so the value is purged and the stand-in printed an empty line.Reproduced at the untouched head 4911baf (the report was against 8eacd8b). Path shortened:
Each exec hop was probed on macOS 26.5.1 (25F80) arm64 with
csrutil statusreporting enabled. The native probe was compiled and ad-hoc signed;PLAIN_PROBEis a control variable:DYLD_LIBRARY_PATHPLAIN_PROBE/bin/sh/bin/sh, thenexeca native binary (the wrapper's shape)/bin/sh, thenexeca#!/bin/shscript (the old stand-in's shape)#!/bin/shscript directlyWhy CI passed: on
mainat 4911baf, thevalidate-macosjob (job 107565829718, labelmacos-15) passed "Gate on the adoption test modules" with the old stand-in. So that runner did not purgeDYLD_*for/bin/sh. This is consistent with GitHub running hosted macOS images with SIP disabled, which actions/runner-images#8162 documents formacos-13.csrutil statuswas not observed on themacos-15runner itself.The product wrapper works under SIP (unchanged)
I downloaded the pinned asset
llama-b11057-bin-macos-arm64.tar.gz(11,178,107 bytes); its sha256 matched the pin. Itsllama-serveris a Mach-O arm64 binary, signedflags=0x20002(adhoc,linker-signed)with no hardened runtime and no entitlements. It loads@rpath/libllama*.dyliband@rpath/libggml*.dyliband hasLC_RPATH @loader_path.fetch,find_oneandinstall_llama_cppwere extracted verbatim from the script. The archive was pre-placed, sofetch's checksum short-circuit ran and curl never did. The install root contained$(touch PWNED), backticks, quotes and$HOME.<root>/bin/llama-server --versionprintedversion: 0.4.1-dev (build 11057, commit 59657a613)and exited 0.sh <wrapper> --versiongave the same result.PWNEDorPWNED2file was created.DYLD_LIBRARY_PATHalone loads the dylibs: a copy of the binary with no dylibs beside it aborts withdyld: Library not loaded: @rpath/libllama-server-impl.dylib. The same copy runs when started by the wrapper's own three lines, evaluated by/bin/sh.com.native-stack.llama-embedruns${ECO_ROOT}/bin/llama-serverdirectly and sets noDYLD_*of its own.@loader_pathresolves the dylibs even through a bare symlink from another directory. The wrapper'sDYLD_LIBRARY_PATHis therefore a fallback for this build, and the script comment saying a symlink would fail does not hold for it.DYLD_LIBRARY_PATHnever reaches the wrapper. The${DYLD_LIBRARY_PATH:+:…}append only takes effect on hosts without SIP.Test change
sys.executable, the test's own interpreter. Like the real binary, that interpreter is not SIP-protected.DYLD_LIBRARY_PATH=controland must print that value. If the interpreter drops it (a SIP-protected or hardened-runtime interpreter), the test skips only theDYLD_LIBRARY_PATHassertion, and only after thePWNED, exit-code and exec-target assertions have run.DYLD_LIBRARY_PATHunset instead of empty. A POSIX shell keeps exporting a variable it inherited, even after reassignment. With""inherited, a wrapper missing itsexportline still passed on Linux and on the SIP-disabled runners. With the variable unset, every host needs theexportline. On this host, a plain variable showed the rule: inherited empty then reassigned, the child seesx; unset then assigned, the child sees nothing.PWNED/PWNED2checks, and the same exact exec target andDYLD_LIBRARY_PATHvalue.Mutation checks on this SIP-enabled Mac, each run against a scratch copy of the script (none committed):
export DYLD_LIBRARY_PATHremovedllama_prefix="$prefix"(double quotes)$(...)executedexectarget/usr/bin/python3Limitation: I could not run the missing-
exportmutant against a shell without SIP. This host has no non-Apple shell, and a copied/bin/bashis killed at launch. This PR's Linux andmacos-15CI runs exercise the new test there.Checks (this host: macOS 26.5.1 arm64, Python 3.14.7)
python3 -m unittest -v tests.test_adoption_bootstrap_macos.LlamaWrapperQuotingTestspasses (not skipped). Before this change it failed.test_adoption_bootstrap,test_adoption_bootstrap_macos,test_adoption_contract,test_adoption_docs_consistency,test_adoption_guarded_runners,test_adoption_launchdandtest_adoption_status.test_render_config,test_workflow_hardeningandtest_workflow_security_coverage, plustest_evidence_manifest.skipped=41, plus 6 errors. All 6 wereEmbedAcceptanceScriptTestshitting aPermissionErrorwhen binding127.0.0.1inside the command sandbox. That class re-run outside the sandbox: 8 tests OK.python3 scripts/validate.pypassed (5228 hashed files, 143 receipts).-S style):adoption/bootstrap-macos.shandadoption/bootstrap-linux.share clean.manifests/evidence.jsonwas re-hashed withhost_receipts.register_file, fortests/test_adoption_bootstrap_macos.pyonly.Evidence class: local integration on one SIP-enabled Mac, plus CI job metadata. No launchd service, embedding acceptance or model run, and no receipt added.
🤖 Generated with Claude Code