Adds scripts/forge_health_check.py to scan wizard environments for: - Missing .py source files with orphaned .pyc bytecode (GOFAI artifact integrity) - Burn script clutter in production paths - World-readable sensitive files (keystores, tokens, .env) - Missing required environment variables Includes full test suite in tests/test_forge_health_check.py covering orphaned bytecode detection, burn script clutter, permission auto-fix, and environment variable validation. Addresses Allegro formalization audit findings: - GOFAI source files missing (only .pyc remains) - Nostr keystore world-readable - eg burn scripts cluttering /root /assign @bezalel
176 lines
6.5 KiB
Python
176 lines
6.5 KiB
Python
"""Tests for scripts/forge_health_check.py"""
|
|
|
|
import os
|
|
import stat
|
|
from pathlib import Path
|
|
|
|
# Import the script as a module
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
|
|
|
|
from forge_health_check import (
|
|
HealthFinding,
|
|
HealthReport,
|
|
_is_sensitive_filename,
|
|
run_health_check,
|
|
scan_burn_script_clutter,
|
|
scan_orphaned_bytecode,
|
|
scan_sensitive_file_permissions,
|
|
scan_environment_variables,
|
|
)
|
|
|
|
|
|
class TestIsSensitiveFilename:
|
|
def test_keystore_is_sensitive(self) -> None:
|
|
assert _is_sensitive_filename("keystore.json") is True
|
|
|
|
def test_env_example_is_not_sensitive(self) -> None:
|
|
assert _is_sensitive_filename(".env.example") is False
|
|
|
|
def test_env_file_is_sensitive(self) -> None:
|
|
assert _is_sensitive_filename(".env") is True
|
|
assert _is_sensitive_filename("production.env") is True
|
|
|
|
def test_test_file_with_key_is_not_sensitive(self) -> None:
|
|
assert _is_sensitive_filename("test_interrupt_key_match.py") is False
|
|
assert _is_sensitive_filename("test_api_key_providers.py") is False
|
|
|
|
|
|
class TestScanOrphanedBytecode:
|
|
def test_detects_pyc_without_py(self, tmp_path: Path) -> None:
|
|
pyc = tmp_path / "module.pyc"
|
|
pyc.write_bytes(b"\x00")
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_orphaned_bytecode(tmp_path, report)
|
|
assert len(report.findings) == 1
|
|
assert report.findings[0].category == "artifact_integrity"
|
|
assert report.findings[0].severity == "critical"
|
|
|
|
def test_ignores_pyc_with_py(self, tmp_path: Path) -> None:
|
|
(tmp_path / "module.py").write_text("pass")
|
|
pyc = tmp_path / "module.pyc"
|
|
pyc.write_bytes(b"\x00")
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_orphaned_bytecode(tmp_path, report)
|
|
assert len(report.findings) == 0
|
|
|
|
def test_detects_pycache_orphan(self, tmp_path: Path) -> None:
|
|
pycache = tmp_path / "__pycache__"
|
|
pycache.mkdir()
|
|
pyc = pycache / "module.cpython-312.pyc"
|
|
pyc.write_bytes(b"\x00")
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_orphaned_bytecode(tmp_path, report)
|
|
assert len(report.findings) == 1
|
|
assert "__pycache__" in report.findings[0].path
|
|
|
|
|
|
class TestScanBurnScriptClutter:
|
|
def test_detects_burn_script(self, tmp_path: Path) -> None:
|
|
(tmp_path / "burn_test.sh").write_text("#!/bin/bash")
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_burn_script_clutter(tmp_path, report)
|
|
assert len(report.findings) == 1
|
|
assert report.findings[0].category == "deployment_hygiene"
|
|
assert report.findings[0].severity == "warning"
|
|
|
|
def test_ignores_regular_files(self, tmp_path: Path) -> None:
|
|
(tmp_path / "deploy.sh").write_text("#!/bin/bash")
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_burn_script_clutter(tmp_path, report)
|
|
assert len(report.findings) == 0
|
|
|
|
|
|
class TestScanSensitiveFilePermissions:
|
|
def test_detects_world_readable_keystore(self, tmp_path: Path) -> None:
|
|
ks = tmp_path / "keystore.json"
|
|
ks.write_text("{}")
|
|
ks.chmod(0o644)
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_sensitive_file_permissions(tmp_path, report)
|
|
assert len(report.findings) == 1
|
|
assert report.findings[0].category == "security"
|
|
assert report.findings[0].severity == "critical"
|
|
assert "644" in report.findings[0].message
|
|
|
|
def test_auto_fixes_permissions(self, tmp_path: Path) -> None:
|
|
ks = tmp_path / "keystore.json"
|
|
ks.write_text("{}")
|
|
ks.chmod(0o644)
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_sensitive_file_permissions(tmp_path, report, fix=True)
|
|
assert len(report.findings) == 1
|
|
assert ks.stat().st_mode & 0o777 == 0o600
|
|
|
|
def test_ignores_safe_permissions(self, tmp_path: Path) -> None:
|
|
ks = tmp_path / "keystore.json"
|
|
ks.write_text("{}")
|
|
ks.chmod(0o600)
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_sensitive_file_permissions(tmp_path, report)
|
|
assert len(report.findings) == 0
|
|
|
|
def test_ignores_env_example(self, tmp_path: Path) -> None:
|
|
env = tmp_path / ".env.example"
|
|
env.write_text("# example")
|
|
env.chmod(0o644)
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_sensitive_file_permissions(tmp_path, report)
|
|
assert len(report.findings) == 0
|
|
|
|
def test_ignores_test_directory(self, tmp_path: Path) -> None:
|
|
tests_dir = tmp_path / "tests"
|
|
tests_dir.mkdir()
|
|
ks = tests_dir / "keystore.json"
|
|
ks.write_text("{}")
|
|
ks.chmod(0o644)
|
|
report = HealthReport(target=str(tmp_path))
|
|
scan_sensitive_file_permissions(tmp_path, report)
|
|
assert len(report.findings) == 0
|
|
|
|
|
|
class TestScanEnvironmentVariables:
|
|
def test_reports_missing_env_var(self, monkeypatch) -> None:
|
|
monkeypatch.delenv("GITEA_TOKEN", raising=False)
|
|
report = HealthReport(target=".")
|
|
scan_environment_variables(report)
|
|
missing = [f for f in report.findings if f.path == "$GITEA_TOKEN"]
|
|
assert len(missing) == 1
|
|
assert missing[0].severity == "warning"
|
|
|
|
def test_passes_when_env_vars_present(self, monkeypatch) -> None:
|
|
for var in ("GITEA_URL", "GITEA_TOKEN", "GITEA_USER"):
|
|
monkeypatch.setenv(var, "present")
|
|
report = HealthReport(target=".")
|
|
scan_environment_variables(report)
|
|
assert len(report.findings) == 0
|
|
|
|
|
|
class TestRunHealthCheck:
|
|
def test_full_run(self, tmp_path: Path, monkeypatch) -> None:
|
|
monkeypatch.setenv("GITEA_URL", "https://example.com")
|
|
monkeypatch.setenv("GITEA_TOKEN", "secret")
|
|
monkeypatch.setenv("GITEA_USER", "bezalel")
|
|
|
|
(tmp_path / "orphan.pyc").write_bytes(b"\x00")
|
|
(tmp_path / "burn_it.sh").write_text("#!/bin/bash")
|
|
ks = tmp_path / "keystore.json"
|
|
ks.write_text("{}")
|
|
ks.chmod(0o644)
|
|
|
|
report = run_health_check(tmp_path)
|
|
assert not report.passed
|
|
categories = {f.category for f in report.findings}
|
|
assert "artifact_integrity" in categories
|
|
assert "deployment_hygiene" in categories
|
|
assert "security" in categories
|
|
|
|
def test_clean_run_passes(self, tmp_path: Path, monkeypatch) -> None:
|
|
for var in ("GITEA_URL", "GITEA_TOKEN", "GITEA_USER"):
|
|
monkeypatch.setenv(var, "present")
|
|
|
|
(tmp_path / "module.py").write_text("pass")
|
|
report = run_health_check(tmp_path)
|
|
assert report.passed
|
|
assert len(report.findings) == 0
|