diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8b4051a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +# CI for the public OpSentry repository. +# +# Self-contained on purpose. The rest of the org calls a reusable workflow that +# lives in a private repository; this one cannot, because a public repo should +# not depend on a private repo's workflow to verify itself -- a contributor +# opening a PR must be able to read every step that gates it, and the private +# workflow would be invisible to them. +# +# This repository is what `brew install opsentry` and `git clone` actually pull +# from, so until now the two most-used install paths had nothing checking them. + +name: ci + +on: + pull_request: + push: + branches: [develop, main] + +jobs: + test: + name: hooks + lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Install jq + # The hooks parse Claude Code's PreToolUse JSON with jq; the suite + # cannot run without it. Ubuntu runners ship it, but pinning the install + # keeps the requirement visible rather than inherited. + run: sudo apt-get install -y jq + + - uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Hook test suite + # 168 assertions across the 8 guardrail hooks, simulating the JSON + # Claude Code sends on PreToolUse. + run: bash test.sh + + - name: Lint + run: | + # Pinned: ruff's default rule set grows between releases, and an + # unpinned upgrade would fail CI on a commit that changed nothing. + pip install ruff==0.16.1 + ruff check opsentry + + - name: Verify the installer is self-consistent + # install.sh is the git-clone install path. A broken shebang or syntax + # error here breaks the documented install for everyone who does not use + # brew or pip, and no test would otherwise catch it. + run: | + bash -n install.sh + bash -n opsentry/install.sh + for hook in opsentry/claude/hooks/*.sh; do bash -n "$hook"; done diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d54ebb..dc4be91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.8.4] - 2026-08-03 + +### Added +- **CI.** This repository is what `brew install opsentry` and `git clone` pull + from, and until now nothing verified it — there were no workflows at all, only + issue and PR templates. Every push and pull request now runs the 168-assertion + hook suite, lints the Python, and syntax-checks `install.sh` and all eight + guardrail hooks so a broken installer cannot ship. + + The workflow is **self-contained** rather than calling the organisation's + shared one, which lives in a private repository: a contributor opening a pull + request must be able to read every step that gates it, and a private workflow + would be invisible to them. + +### Fixed +- `baseline.py` and `blocklog_audit.py` carried `#!/usr/bin/env python3` but were + tracked non-executable, so neither could be run directly despite advertising + that it could. Found by CI on its first run. + ## [1.8.3] - 2026-08-03 ### Changed - **Version aligned with the OpSentry release line.** This repository had been diff --git a/VERSION b/VERSION index a7ee35a..bfa363e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.3 +1.8.4 diff --git a/opsentry/baseline.py b/opsentry/baseline.py old mode 100644 new mode 100755 diff --git a/opsentry/blocklog_audit.py b/opsentry/blocklog_audit.py old mode 100644 new mode 100755