Store now spells its root \\?\C:\... on Windows so PM's own file calls
under it pass MAX_PATH. That spelling must not escape: the same folder
spelled two ways hashes and compares differently, and children such as
cmd.exe, gpg or uv refuse or record the prefix (uv would write it into
pyvenv.cfg).
native() now converts store-derived paths where their text leaves PM:
- process argv and cwd: uv via PythonEnvironment._run (its one exit),
binary version probes, npm self-install, the PortableGit extractor,
gpg provenance checks, the plugin-eviction interpreter probe;
- environment values: compose_env (PATH and package env diffs), the
activation PATH dirs, HERMES_RUNTIME_DIR;
- hashed identities: the PM runtime inputs and isolated-environment
identity, so existing records still match and nothing rebuilds;
- API results callers execute or compare: installed_package,
uv_launcher, verified_tools entries;
- user-facing verification messages.
Facts records already store {STORE}-templated env, so no absolute path
reaches them. Tests pin that identities are spelling-independent and that
records, composed env and uv invocations from a verbatim root carry no
prefix (both fail on e8c97320ac).
tirith ran `tirith check` on every terminal command, default-on with fail-open, as a
pinned PM binary auto-downloaded at startup. Measured against the shipped 0.4.2 binary
it caught 14/16 attack commands but flagged 12/24 everyday agent commands
(`echo $((6*7))`, `"$VAR/x.sh"`, `gh api | python3`, LAN curls, `.dev` hosts,
`pip install` via analysis_incomplete), and in cron/-q deny mode each of those is a
hard block. It only ever saw terminal strings (execute_code, writes and the browser
bypass it), fail-open meant no protection wherever the binary could not install
(Windows, Termux, x64 musl), and it produced a steady issue/PR stream (fail_open
semantics four times, install loops filling disks, a SIGSEGV hang, session-approval
scoping, third-party promo text on approval cards).
Removed: tools/tirith_security.py, the tirith branches of the command guard (the
is_tirith tuple, session-only "always" downgrade, import-error/fail-open paths,
unattended tirith pass), the CLI and gateway startup installers, the PM package and
lock pins, the nix runtime dep, security.tirith_* defaults, the CLI warning string
and three tirith tips (gaps refilled from the tail so translations survive), plus
the gateway's "no automated assessor" warning that only existed to point at tirith.
Config v50 drops security.tirith_* and enables nothing in its place. Hermes ships
no tirith plugin; if tirith upstream publishes one, it goes through normal catalog
admission under their name.
packages.py and security_packages.py imported the private _MUSL_TARGETS
across modules; make it a public store constant next to ALL_TARGETS.
The _pin_tool hash memo is an unrelated optimisation, out of scope here.
Skip glibc-linked FFmpeg on musl in both default install and update roots.
Select musl uv during the standalone shell bootstrap, and let the native
userland resolve libc before bootstrap Python build metadata.
Add regression checks for the closure, target precedence, and installer pins.
security_packages.py referenced _MUSL_TARGETS without importing it, so
IronProxy.fetch_url raised NameError on linux-*-musl (the PR's own
test_portable_go_tools_resolve_the_generic_linux_archives caught it).
Review fix pushed to the contributor branch.
pm/security_packages.py imported the private _allowlisted_env across
package boundaries. It is a real cross-module contract (the pm probe
must use the same scrubbed env as the proxy), so name it publicly and
list it in __all__. No alias for the old name.
pm.security_packages calls it from the Tirith package; a leading
underscore hides a cross-module contract. The consumer still owns the
signature semantics (pm/security_packages._SignedBinary), so the lazy
pm→tools→pm reference stays; only the name changes.
Run historical updater completion in a fresh interpreter so cached imports
cannot revive retired dependency installers. Share Git and ZIP completion,
carry receipt and recovery state, and preserve child exit status.
Route plugin admission, binary acquisition, desktop launch and build paths
through PM. Replace redundant helpers and tests with real worker, package,
publication and launch checks. Keep the shipped compatibility surface fixed.
Targeted Python and desktop checks pass. Native update journeys and fresh
production image qualification remain pending. This is a checkpoint before
those acceptance runs.