3.3 KiB
3.3 KiB
codex-package-manager
codex-package-manager is the shared installer used for versioned runtime bundles and other cached artifacts in codex-rs.
It owns the generic parts of package installation:
- current-platform detection
- manifest and archive fetches
- checksum and archive-size validation
- archive extraction for
.zipand.tar.gz - staging and promotion into a versioned cache directory
- cross-process install locking
Package-specific code stays behind the ManagedPackage trait.
Model
The package manager is intentionally small:
- A
ManagedPackageimplementation describes how to fetch a manifest, choose an archive for aPackagePlatform, and load a validated installed package from disk. PackageManager::resolve_cached()returns a cached install for the current platform ifload_installed()succeeds and the version matches.PackageManager::ensure_installed()acquires a per-install lock, downloads the archive into a staging directory, extracts it, validates the staged package, and promotes it into the cache.
The default cache root is:
<codex_home>/<default_cache_root_relative>
Callers can override that root with PackageManagerConfig::with_cache_root(...).
ManagedPackage Contract
The trait is small, but the invariants matter:
install_dir()should be unique per package version and platform. If two versions or two platforms share a directory, promotion and cleanup become unsafe.load_installed()must fully validate the installed package, not just deserialize a manifest.resolve_cached()trusts a successful load as a valid cache hit.- The default
detect_extracted_root()looks formanifest.jsonat the extraction root or inside a single top-level directory. Override it if your package layout differs. archive_url()should be derived from manifest data, not recomputed from unrelated caller state, so manifest selection and download stay aligned.
Consumer Guidance
- If your feature can install on demand, do not gate feature registration on a preinstalled-cache check alone.
resolve_cached()only answers "is it already present?" whileensure_installed()is the bootstrap path. - Keep cache-root overrides inside your manager/config surface. Separate helpers that reconstruct install paths can drift from
PackageManagerConfig. - Prefer surfacing package-specific validation failures from
load_installed()when debugging. The generic manager treats failed cache loads as cache misses today.
Security and Extraction Rules
.zipextraction rejects entries that escape the extraction root and preserves Unix executable bits when the archive carries them..tar.gzextraction rejects symlinks, hard links, sparse files, device files, and FIFOs. Only regular files and directories are promoted.- The archive SHA-256 is always verified, and
size_bytesis enforced when present in the manifest.
Extending It
Typical usage looks like this:
let config = PackageManagerConfig::new(codex_home, MyPackage::new(...));
let manager = PackageManager::new(config);
let package = manager.ensure_installed().await?;
In practice, most packages should expose their own small wrapper config/manager types over the generic crate so the rest of the codebase does not depend on ManagedPackage details directly.