| name | upstream-audit |
| description | Audit and update Pilot Shell upstream dependencies in installer/upstreams.yaml.
Checks npm, PyPI, brew, and curl-pipe entries for newer stable versions,
known security advisories, and sha256 drift. Verifies each update installs
successfully before committing. Use when: "check upstreams", "update dependencies",
"audit upstreams.yaml", "are our dependencies up to date", "supply chain check".
|
Upstream Audit
Checks every entry in installer/upstreams.yaml for newer stable versions, security
advisories, and hash drift. Updates the manifest and verifies each change installs
correctly.
Important
- Never update to pre-release, alpha, beta, rc, or canary versions. Only stable releases.
- Never update a curl entry's sha256 without downloading and verifying the script content first.
- Every version bump must be install-tested before writing to upstreams.yaml.
- Preserve all existing fields (comments,
last_audited, soft_pin, scripts_policy, etc.) — only change version, sha256, and last_audited.
Instructions
Step 1: Load the Manifest
cat installer/upstreams.yaml
Parse the entries. Group them by source_type: npm, brew, curl, pypi.
Step 2: Check for Newer Versions
For each entry, check the latest stable version using the appropriate method:
npm packages (source_type: npm):
npm view <source_url> version 2>/dev/null
PyPI packages (source_type: pypi):
pip index versions <name> 2>/dev/null | head -1
Homebrew formulas (source_type: brew):
brew info --json=v2 <brew_formula> 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['formulae'][0]['versions']['stable'])"
curl-pipe installers (source_type: curl):
Commit-pinned entries (have commit field — extract repo URL from source_url):
git ls-remote <repo_url> HEAD | cut -c1-40
If HEAD differs from the current commit, download the new script, hash it, and update source_url (embed new commit), version (commit-<short>), commit, sha256.
Tag-pinned entries (version starts with v, e.g., nvm):
git ls-remote --tags <repo_url> | grep -oP 'v\d+\.\d+\.\d+$' | sort -V | tail -1
If newer tag exists, update source_url (embed new tag), version, sha256, and name if it includes the version.
Soft-pinned entries (soft_pin: true — vendor-managed live endpoints):
curl -fsSL "<source_url>" -o /tmp/upstream-audit-script.sh
shasum -a 256 /tmp/upstream-audit-script.sh
rm -f /tmp/upstream-audit-script.sh
Compare sha256 to manifest. If different → sha256 drifted, update sha256 and version label (e.g., live-YYYY-MM-DD or vendor-managed-YYYY-MM-DD). If same → no drift, just update last_audited.
Update ALL entries' last_audited to today's date — even entries where the version didn't change. The audit date records when we last verified the version is current, not when it was last bumped.
Step 3: Check Security Advisories
For each entry with a newer version available:
npm packages:
npm audit --json --package <source_url>@<current_version> 2>/dev/null || true
Also check: WebSearch for "<package_name> CVE" or "<package_name> security vulnerability".
PyPI packages:
pip audit --requirement=<(echo "<name>==<version>") 2>/dev/null || true
Or search: WebSearch for "<package_name> CVE" or "<package_name> security advisory".
Homebrew formulas: Check the formula's source repo for security advisories.
Report any findings. If the CURRENT version has known vulnerabilities, flag as urgent.
Step 4: Install-Test Each Update
This step is mandatory. Do not skip it.
For each version bump, verify the new version actually installs and works:
npm packages:
npm install --prefix /tmp/upstream-audit-test <source_url>@<new_version> --ignore-scripts 2>&1
echo "exit: $?"
rm -rf /tmp/upstream-audit-test
For packages with scripts_policy: allow (like better-sqlite3):
npm install --prefix /tmp/upstream-audit-test <source_url>@<new_version> 2>&1
echo "exit: $?"
rm -rf /tmp/upstream-audit-test
curl-pipe installers:
curl -fsSL "<source_url>" -o /tmp/upstream-audit-script.sh
shasum -a 256 /tmp/upstream-audit-script.sh
rm -f /tmp/upstream-audit-script.sh
For commit-pinned curl entries, construct the new URL with the latest commit hash and download.
PyPI packages:
uv pip install --dry-run <name>==<new_version> 2>&1
echo "exit: $?"
Homebrew formulas: No install-test needed — brew formulas are tested by the Homebrew CI.
If any install-test fails, do not update that entry. Report the failure and move on.
Step 5: Update the Manifest AND Cross-File Pins
For each successfully verified update, edit installer/upstreams.yaml:
- Update the
version field to the new version
- Update
sha256 if applicable (curl entries — use the hash from Step 4)
- Update
last_audited to today's date (YYYY-MM-DD format)
- For commit-pinned curl entries: update both
commit and version (commit-<short_hash>)
- For soft_pin curl entries: only update
sha256 and last_audited if the script changed
Cross-file version pins that MUST stay in sync with the manifest:
These files contain hardcoded version strings that duplicate the manifest. After updating
upstreams.yaml, grep for the old version and update every occurrence:
| File | What it pins |
|---|
pilot/.mcp.json | npx-launched MCP servers: context7-mcp@X, open-websearch@X, fetcher-mcp@X |
install.sh | PyPI bootstrap: rich==X, certifi==X, PyYAML==X |
launcher/build.py | PyPI bootstrap: cryptography==X |
.github/workflows/supply-chain.yml | CI PyPI pin: PyYAML==X |
For curl entries with version-pinned URLs (e.g., nvm-curl), also update source_url
to embed the new version in the URL path.
Verification command — find any remaining stale pins after updating:
grep -rn "rich==\|certifi==\|cryptography==\|PyYAML==\|context7-mcp@\|open-websearch@\|fetcher-mcp@" \
install.sh launcher/build.py pilot/.mcp.json .github/workflows/ installer/upstreams.yaml \
--include="*.sh" --include="*.py" --include="*.json" --include="*.yaml" --include="*.yml"
Do not change:
scripts_policy, scripts_justification
soft_pin, soft_pin_reason
pin_kind, auto_upgrade
brew_tap
- Comments in the YAML
Step 6: Validate the Manifest
uv run python -c "from installer.manifest import load; m = load(); print(f'Manifest valid: {len(m.entries)} entries')"
If validation fails, fix the YAML and retry.
Step 7: Run Installer Tests
uv run pytest installer/tests/unit/ -q
All tests must pass. If a test fails due to a version change, investigate and fix.
Step 8: Report
Present a summary table:
| Entry | Type | Current | Latest | Status | Notes |
|---|
| codegraph | npm | 0.7.3 | 0.9.4 | Updated | Install verified |
| better-sqlite3 | npm | 12.9.0 | 12.9.0 | Current | — |
| vtsls | npm | 0.3.0 | 0.3.1 | Updated | Install verified |
| ... | ... | ... | ... | ... | ... |
Flag any:
- Security advisories found (urgent or informational)
- Install failures (version skipped, reason noted)
- sha256 drift on soft-pinned curl entries (re-pin reminder)
- Major version bumps that may have breaking changes (flag for manual review)
When NOT to Use
- For adding NEW upstream entries (that's a code change, not an audit)
- For changing
source_url or source_type (structural change, needs manual review)
- For removing entries (deprecation decision, not an audit)