From 0e565b0b19c0e3892a486545b1a0ab9bb77629ee Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 29 May 2026 13:09:59 -0700 Subject: [PATCH] Fix CheckYourself org defaults findings --- .github/dependabot.yml | 12 +++ .github/workflows/agent-law-provisioner.yml | 6 +- .github/workflows/agent-law.yml | 4 +- .github/workflows/blacksmith-go-smoke.yml | 6 +- .github/workflows/blacksmith-probe.yml | 4 +- .github/workflows/ci.yml | 22 +++++ .gitignore | 4 + scripts/provision-agent-law.py | 7 +- tests/test_agent_defaults.py | 91 +++++++++++++++++++++ 9 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 tests/test_agent_defaults.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..949c64c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + labels: + - "dependencies" + - "ci" + commit-message: + prefix: "ci(deps)" diff --git a/.github/workflows/agent-law-provisioner.yml b/.github/workflows/agent-law-provisioner.yml index 5d25bb4..34f3ab5 100644 --- a/.github/workflows/agent-law-provisioner.yml +++ b/.github/workflows/agent-law-provisioner.yml @@ -31,7 +31,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout hub - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Provision Agent Law env: @@ -73,7 +75,7 @@ jobs: - name: Upload provisioner report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: agent-law-provisioner-results path: agent-law-provisioner-results.json diff --git a/.github/workflows/agent-law.yml b/.github/workflows/agent-law.yml index 07cbd0a..6f5bdc4 100644 --- a/.github/workflows/agent-law.yml +++ b/.github/workflows/agent-law.yml @@ -14,7 +14,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Verify Empower Orchestrator law shell: bash diff --git a/.github/workflows/blacksmith-go-smoke.yml b/.github/workflows/blacksmith-go-smoke.yml index 5159f89..f35e25e 100644 --- a/.github/workflows/blacksmith-go-smoke.yml +++ b/.github/workflows/blacksmith-go-smoke.yml @@ -24,10 +24,12 @@ jobs: timeout-minutes: 15 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 with: go-version-file: go.mod cache: true diff --git a/.github/workflows/blacksmith-probe.yml b/.github/workflows/blacksmith-probe.yml index f3088cb..9d97918 100644 --- a/.github/workflows/blacksmith-probe.yml +++ b/.github/workflows/blacksmith-probe.yml @@ -19,7 +19,9 @@ jobs: timeout-minutes: 5 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Runner identity run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b0612bf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: CI + +on: + pull_request: + merge_group: + workflow_dispatch: + +permissions: + contents: read + +jobs: + python-tests: + name: Python tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + + - name: Run unit tests + run: python3 -m unittest discover -s tests diff --git a/.gitignore b/.gitignore index e9bc3b2..24f4b68 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ .env .env.* !.env.example +*.pem +*.key .idea/ .vscode/ *.swp @@ -18,6 +20,8 @@ .omc/ # Generated logs and archives +__pycache__/ +*.py[cod] *.log npm-debug.log* pnpm-debug.log* diff --git a/scripts/provision-agent-law.py b/scripts/provision-agent-law.py index 85086c7..41cdd9b 100644 --- a/scripts/provision-agent-law.py +++ b/scripts/provision-agent-law.py @@ -264,7 +264,9 @@ def workflow_text() -> str: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Verify Empower Orchestrator law shell: bash @@ -337,7 +339,8 @@ def upsert_marker_file(path: Path, block: str, header: str) -> None: def choose_recipe_path(repo_dir: Path) -> Path: # Respect repos that already use a capitalized Docs tree on case-insensitive machines. - if (repo_dir / "Docs").exists() and not (repo_dir / "docs").exists(): + names = {child.name for child in repo_dir.iterdir()} if repo_dir.exists() else set() + if "Docs" in names and "docs" not in names: return repo_dir / "Docs" / "agent-law" / "empower-orchestrator.md" return repo_dir / "docs" / "agent-law" / "empower-orchestrator.md" diff --git a/tests/test_agent_defaults.py b/tests/test_agent_defaults.py new file mode 100644 index 0000000..ec5b371 --- /dev/null +++ b/tests/test_agent_defaults.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +import importlib.util +import sys +import tempfile +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def load_script(name: str, path: Path): + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + sys.modules[name] = module + spec.loader.exec_module(module) + return module + + +parity = load_script("check_agent_parity", ROOT / "scripts" / "check-agent-parity.py") +provisioner = load_script("provision_agent_law", ROOT / "scripts" / "provision-agent-law.py") + + +class AgentParityTests(unittest.TestCase): + def test_strip_agent_specific_removes_markers_and_normalizes(self) -> None: + content = """--- +title: hidden +--- +# Rules + +ignore + + +Keep this. +""" + + self.assertEqual(parity.strip_agent_specific(content), "# Rules\n\nignore\n\nKeep this.") + + def test_extract_sections_keeps_nested_section_names(self) -> None: + sections = parity.extract_sections("# One\nAlpha\n\n## Two\nBeta") + + self.assertEqual(sections["One"], "Alpha") + self.assertEqual(sections["Two"], "Beta") + + def test_check_repo_fails_when_agents_file_is_missing(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + repo = Path(tmp) / "example" + repo.mkdir() + (repo / "CLAUDE.md").write_text("# Organization Principles\n\nUseful over flashy.\n") + + result = parity.check_repo(repo) + + self.assertEqual(result.status, "fail") + self.assertIn("AGENTS.md file is missing", result.content_differences) + + +class ProvisionerTests(unittest.TestCase): + def test_upsert_marker_file_replaces_existing_block(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "AGENTS.md" + path.write_text(f"# Rules\n\n{provisioner.START}\nold\n{provisioner.END}\n") + + provisioner.upsert_marker_file(path, f"{provisioner.START}\nnew\n{provisioner.END}", "# Rules") + + text = path.read_text() + + self.assertIn("new", text) + self.assertNotIn("old", text) + self.assertEqual(text.count(provisioner.START), 1) + + def test_choose_recipe_path_respects_capitalized_docs_tree(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + repo = Path(tmp) + (repo / "Docs").mkdir() + + path = provisioner.choose_recipe_path(repo) + + self.assertEqual(path, Path(tmp) / "Docs" / "agent-law" / "empower-orchestrator.md") + + def test_generated_workflow_uses_pinned_checkout_without_credentials(self) -> None: + text = provisioner.workflow_text() + + self.assertIn("actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5", text) + self.assertIn("persist-credentials: false", text) + self.assertNotIn("actions/checkout@v4", text) + + +if __name__ == "__main__": + unittest.main()