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

118 lines
4.2 KiB
Python

"""Version-coherence regression test.
Asserts that the project version is the same string across all four
canonical surfaces: pyproject.toml, plugin.json, CITATION.cff, and the
orchestrator skills/blog/SKILL.md frontmatter.
Added v1.8.5 (6TH-AUDIT-010): the v1.8.4 release added the same check
as a CI YAML heredoc. Moving the check into pytest gives local devs the
same signal CI produces, so `pytest` before push catches the drift.
Stdlib + pytest only.
"""
from __future__ import annotations
import json
import re
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
def _read_pyproject_version() -> str | None:
text = (ROOT / "pyproject.toml").read_text(encoding="utf-8")
m = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE)
return m.group(1) if m else None
def _read_plugin_version() -> str | None:
with open(ROOT / ".claude-plugin" / "plugin.json", encoding="utf-8") as f:
return json.load(f).get("version")
def _read_citation_version() -> str | None:
"""Strip optional YAML single/double quotes (v1.8.6: 7TH-AUDIT-011)."""
text = (ROOT / "CITATION.cff").read_text(encoding="utf-8")
m = re.search(r'^version:\s*[\'"]?([0-9][^\'"\s]+)[\'"]?', text, re.MULTILINE)
return m.group(1) if m else None
def _read_skill_md_version() -> str | None:
text = (ROOT / "skills" / "blog" / "SKILL.md").read_text(encoding="utf-8")
m = re.search(r'^\s*version:\s*"?([^"\s]+)"?', text, re.MULTILINE)
return m.group(1) if m else None
def test_all_version_surfaces_aligned() -> None:
"""The same version string must appear in pyproject.toml,
plugin.json, CITATION.cff, and skills/blog/SKILL.md metadata.
v1.8.4 (5TH-AUDIT-001) found skills/blog/SKILL.md frozen at "1.8.0"
while every other surface had moved through 1.8.1, 1.8.2, 1.8.3.
This test prevents that recurring.
"""
versions = {
"pyproject.toml": _read_pyproject_version(),
".claude-plugin/plugin.json": _read_plugin_version(),
"CITATION.cff": _read_citation_version(),
"skills/blog/SKILL.md": _read_skill_md_version(),
}
# None should be missing.
missing = [k for k, v in versions.items() if v is None]
assert not missing, f"version field could not be extracted from: {missing}"
unique = set(versions.values())
assert len(unique) == 1, (
f"version surfaces disagree:\n"
+ "\n".join(f" {k}: {v!r}" for k, v in versions.items())
)
def test_version_string_matches_semver_pattern() -> None:
"""The shared version must be valid semver (X.Y.Z optional pre-release)."""
version = _read_pyproject_version()
assert version is not None
assert re.match(r"^\d+\.\d+\.\d+(-\S+)?$", version), (
f"version {version!r} does not match semver pattern X.Y.Z[-pre]"
)
def test_all_sub_skill_versions_match_project_version() -> None:
"""v1.8.6 (7TH-AUDIT-003): every skills/*/SKILL.md `version:` field
must equal the project version. Pre-v1.8.6, 10 sub-skill SKILL.md
files had stale per-skill versions (1.0.0, 1.4.0, 1.7.0) that were
never bumped through the v1.8.x cycle. The version-coherence test
only covered the orchestrator, missing all 10 sub-skill surfaces.
"""
target = _read_pyproject_version()
assert target is not None
skill_md_files = sorted((ROOT / "skills").glob("*/SKILL.md"))
assert len(skill_md_files) >= 30, (
f"unexpectedly few SKILL.md files: {len(skill_md_files)}"
)
mismatches = []
for f in skill_md_files:
text = f.read_text(encoding="utf-8")
# Match the YAML frontmatter version field; tolerate quote styles.
m = re.search(
r'^\s+version:\s*[\'"]?([0-9][^\'"\s]+)[\'"]?',
text, re.MULTILINE,
)
if m is None:
# Some SKILL.md files may not declare metadata.version at all;
# that is acceptable. We only flag drift, not absence.
continue
if m.group(1) != target:
mismatches.append((f.relative_to(ROOT), m.group(1)))
assert not mismatches, (
f"sub-skill SKILL.md versions disagree with pyproject.toml "
f"({target}):\n"
+ "\n".join(f" {p}: {v}" for p, v in mismatches)
)
if __name__ == "__main__":
pytest.main([__file__, "-v"])