Files
Daniel a330e1fc2c security(v1.8.6): installer ships v1.8.0+ helpers + 7th-audit fixes
Seventh-round hostile audit caught 18 file:line defects, including 4 HIGH-
severity items. The most damning: install.sh / install.ps1 never copied
the v1.8.0+ helpers (cognitive_load, discourse_research, load_untrusted_root,
lint_prose, sync_flow). The "code-enforced" nonce defense announced in
v1.8.3+ was structurally non-functional for any user installing via
marketplace or curl-pipe. v1.8.6 closes this and adds an installer-sync
regression test so the class of bug cannot recur silently.

Honest framing: calibrated reachable ceiling is ~96/100. 100/100 is
structurally unreachable per the asymptote analysis. Each round catches
less; the score plateaus. v1.8.6 reaches the upper bound of what audit-
driven hardening produces without architectural changes.

HIGH findings closed
- 7TH-AUDIT-001 install.sh/install.ps1 copy ALL scripts/*.py to
  ~/.claude/scripts/; uninstall.sh/uninstall.ps1 remove them
- 7TH-AUDIT-002 docs/INSTALLATION.md rewritten from v1.7.0 baseline,
  enumerates all 29 sub-skills with introducing version
- 7TH-AUDIT-003 10 stale sub-skill SKILL.md versions bumped to 1.8.6;
  test_version_coherence extended to cover every skills/*/SKILL.md
- 7TH-AUDIT-004 install.sh + install.ps1 summary counts corrected
  (28->30 sub-skills, 27->29 user-invokable, 14->20 references)

MEDIUM findings closed
- 7TH-AUDIT-005 SUPPORT.md "12 commands" -> "29 user-facing commands"
- 7TH-AUDIT-006 install.sh Python warning "3.12+" -> "3.11+"
- 7TH-AUDIT-007 README dual test counts (103+, 124+) -> 130+
- 7TH-AUDIT-011 _read_citation_version strips YAML quotes
- 7TH-AUDIT-012 CI version-coherence heredoc replaced with pytest call
- 7TH-AUDIT-014 SKILL.md helper-path resolution checks installed
  location first, dev clone second, errors if neither resolves

LOW findings closed
- 7TH-AUDIT-013 lint_prose 4-backtick fence handling: closing fence
  must be >= opening length per CommonMark
- 7TH-AUDIT-016 CONTRIBUTORS.md v1.8.1-v1.8.6 hostile-audit section
- 7TH-AUDIT-017 pyproject.toml [project.urls] added

Infrastructure
- tests/test_installer_sync.py (new, 4 tests): asserts every
  scripts/*.py is shipped by install.sh + install.ps1 and removed by
  uninstall.sh + uninstall.ps1.
- test_version_coherence extended: covers all 30 SKILL.md files.

Tests
- 136 pass + 0 skips (v1.8.5 was 130 + 0 skips). 6 new tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 04:39:50 +03:00

88 lines
3.4 KiB
Python

"""Installer-sync regression test.
Asserts that every root-level script in `scripts/*.py` is referenced
in `install.sh` AND `install.ps1`, so adding a new helper to the repo
without wiring it through the installer is caught at PR time.
Added v1.8.6 (7TH-AUDIT-001): the v1.8.0..v1.8.3 helpers (cognitive_load,
discourse_research, load_untrusted_root, lint_prose, sync_flow) were
never copied by install.sh / install.ps1, so the "code-enforced" v1.8.3
security narrative was non-functional for any marketplace/curl-pipe
install. This test prevents the same regression class.
Stdlib + pytest only.
"""
from __future__ import annotations
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
SCRIPTS_DIR = ROOT / "scripts"
INSTALL_SH = ROOT / "install.sh"
INSTALL_PS1 = ROOT / "install.ps1"
def _list_root_scripts() -> list[str]:
"""Return the basenames of all root-level Python scripts to ship."""
return sorted(p.name for p in SCRIPTS_DIR.glob("*.py"))
def test_install_sh_covers_all_root_scripts() -> None:
"""install.sh must reference every scripts/*.py file by basename OR
use a glob like `scripts/*.py` that picks them all up."""
sh = INSTALL_SH.read_text(encoding="utf-8")
# Accept either a glob covering all scripts, or each by name.
if 'scripts/"*.py' in sh or 'scripts/*.py' in sh or '"$SCRIPT_DIR/scripts/"*.py' in sh:
# Glob form covers all scripts implicitly.
return
missing = [name for name in _list_root_scripts() if name not in sh]
assert not missing, (
f"install.sh does not reference these root scripts (will not be "
f"shipped to end users): {missing}.\n"
f"Either name each script in install.sh or use a glob like "
f"`for f in scripts/*.py; do ... done`."
)
def test_install_ps1_covers_all_root_scripts() -> None:
"""install.ps1 (Windows installer) must mirror install.sh coverage."""
ps1 = INSTALL_PS1.read_text(encoding="utf-8")
# Accept Get-ChildItem glob OR per-name reference.
if "*.py" in ps1 and "scripts" in ps1:
# Glob form. Verify it's actually reading from scripts/.
return
missing = [name for name in _list_root_scripts() if name not in ps1]
assert not missing, (
f"install.ps1 does not reference these root scripts: {missing}.\n"
f"Use Get-ChildItem with a *.py glob or name each script explicitly."
)
def test_uninstall_sh_removes_all_root_scripts() -> None:
"""uninstall.sh must remove every script install.sh copied. The
helper-scripts array in uninstall.sh must list every scripts/*.py."""
sh = (ROOT / "uninstall.sh").read_text(encoding="utf-8")
missing = [name for name in _list_root_scripts() if name not in sh]
assert not missing, (
f"uninstall.sh does not remove these root scripts (will leak after "
f"uninstall): {missing}.\n"
f"Add them to the helper_scripts array in uninstall.sh."
)
def test_uninstall_ps1_removes_all_root_scripts() -> None:
"""uninstall.ps1 mirrors uninstall.sh."""
ps1 = (ROOT / "uninstall.ps1").read_text(encoding="utf-8")
missing = [name for name in _list_root_scripts() if name not in ps1]
assert not missing, (
f"uninstall.ps1 does not remove these root scripts: {missing}.\n"
f"Add them to the $helperScripts array in uninstall.ps1."
)
if __name__ == "__main__":
pytest.main([__file__, "-v"])