-
-
Notifications
You must be signed in to change notification settings - Fork 0
ci(rhodibot): switch to the report-only canary (standards#759) #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,189 +1,94 @@ | ||||||||||
| # This workflow is managed by gh actions-lock. | ||||||||||
| # SPDX-License-Identifier: MPL-2.0 | ||||||||||
| # rhodibot.yml — Automated RSR compliance enforcement | ||||||||||
| # rhodibot.yml — RSR compliance CANARY (report-only) | ||||||||||
| # | ||||||||||
| # Reads root-hygiene rules and auto-fixes what it can: | ||||||||||
| # - Delete banned files (AI.djot, duplicate CONTRIBUTING.adoc, stale snapshots) | ||||||||||
| # - Rename misnamed files (AI.a2ml → 0-AI-MANIFEST.a2ml) | ||||||||||
| # - Fix SPDX headers (AGPL → PMPL in dotfiles) | ||||||||||
| # - Create missing required files (SECURITY.md, CONTRIBUTING.md) | ||||||||||
| # - Report unfixable issues as PR comments | ||||||||||
| # Rhodibot does NOT mutate this repository. It never deletes, renames, | ||||||||||
| # rewrites SPDX headers, creates files, or opens PRs. Instead it DETECTS | ||||||||||
| # what an auto-fixer would have changed and reports it. | ||||||||||
| # | ||||||||||
| # Runs weekly and on Hypatia scan completion. | ||||||||||
| # Design intent (owner): if rhodibot "feels the desire to edit" — i.e. it | ||||||||||
| # detects something it considers non-compliant — that is itself a MAJOR | ||||||||||
| # WARNING. Either the repo has drifted, OR rhodibot's own rules have | ||||||||||
| # diverged from the normative style it is meant to enforce. Both warrant | ||||||||||
| # a human look, so the canary FAILS the run when it finds would-mutate | ||||||||||
| # drift. Dangerous-pattern hits are advisory warnings only. | ||||||||||
| # | ||||||||||
| # Licence note: SPDX/licence drift is reported for MANUAL, owner-only | ||||||||||
| # correction. Rhodibot must never edit a licence header (estate directive). | ||||||||||
|
|
||||||||||
| name: "\U0001F916 Rhodibot — RSR Auto-Fix" | ||||||||||
| name: "\U0001F916 Rhodibot — RSR Compliance Canary" | ||||||||||
| on: | ||||||||||
| schedule: | ||||||||||
| - cron: '0 6 * * 1' # Every Monday at 06:00 UTC | ||||||||||
| workflow_dispatch: # Manual trigger | ||||||||||
| workflow_run: | ||||||||||
| workflows: ["Hypatia Neurosymbolic Analysis"] | ||||||||||
| types: [completed] | ||||||||||
|
|
||||||||||
| concurrency: | ||||||||||
| group: ${{ github.workflow }}-${{ github.ref }} | ||||||||||
| cancel-in-progress: true | ||||||||||
|
|
||||||||||
| permissions: | ||||||||||
| contents: write | ||||||||||
| pull-requests: write | ||||||||||
| contents: read | ||||||||||
| jobs: | ||||||||||
| rhodibot: | ||||||||||
| canary: | ||||||||||
| runs-on: ubuntu-latest | ||||||||||
| timeout-minutes: 15 | ||||||||||
| steps: | ||||||||||
| - name: Checkout | ||||||||||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4 | ||||||||||
| uses: actions/checkout@v7.0.1 | ||||||||||
| with: | ||||||||||
| fetch-depth: 1 | ||||||||||
| - name: Rhodibot — Scan and Fix | ||||||||||
| id: fix | ||||||||||
| - name: Rhodibot — detect drift (no mutations) | ||||||||||
| run: | | ||||||||||
| set -euo pipefail | ||||||||||
| FIXES="" | ||||||||||
| ISSUES="" | ||||||||||
| CHANGED=false | ||||||||||
| set -uo pipefail | ||||||||||
| DRIFT=0 | ||||||||||
| warn() { echo "::warning title=Rhodibot canary::$*"; DRIFT=$((DRIFT+1)); } | ||||||||||
| note() { echo "::warning title=Rhodibot advisory::$*"; } | ||||||||||
|
|
||||||||||
| # --- 1. Delete banned files --- | ||||||||||
| for pattern in "AI.djot" "NEXT_STEPS.md" "TODO.md" "NOTES.md" "TASKS.md"; do | ||||||||||
| if [ -f "$pattern" ]; then | ||||||||||
| rm "$pattern" | ||||||||||
| FIXES="$FIXES\n- Deleted \`$pattern\` (superseded)" | ||||||||||
| CHANGED=true | ||||||||||
| fi | ||||||||||
| done | ||||||||||
| echo "## 🤖 Rhodibot canary — report only (no edits made)" >> "$GITHUB_STEP_SUMMARY" | ||||||||||
|
|
||||||||||
| # Delete stale snapshot files | ||||||||||
| # --- would-DELETE: banned files --- | ||||||||||
| for f in AI.djot NEXT_STEPS.md TODO.md NOTES.md TASKS.md; do | ||||||||||
| [ -f "$f" ] && warn "banned file present: $f (an auto-fixer would delete it)" | ||||||||||
| done | ||||||||||
| # would-DELETE: stale snapshots | ||||||||||
| for f in *-STATUS-*.md *-COMPLETION-*.md *-COMPLETE.md *-VERIFIED-*.md; do | ||||||||||
| if [ -f "$f" ]; then | ||||||||||
| rm "$f" | ||||||||||
| FIXES="$FIXES\n- Deleted stale snapshot \`$f\`" | ||||||||||
| CHANGED=true | ||||||||||
| fi | ||||||||||
| [ -f "$f" ] && warn "stale snapshot present: $f (would be deleted)" | ||||||||||
| done | ||||||||||
|
|
||||||||||
| # --- 2. Rename misnamed files --- | ||||||||||
| # would-RENAME: legacy manifest name | ||||||||||
| if [ -f "AI.a2ml" ] && [ ! -f "0-AI-MANIFEST.a2ml" ]; then | ||||||||||
| mv AI.a2ml 0-AI-MANIFEST.a2ml | ||||||||||
| FIXES="$FIXES\n- Renamed \`AI.a2ml\` → \`0-AI-MANIFEST.a2ml\`" | ||||||||||
| CHANGED=true | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| # --- 3. Delete duplicate format files --- | ||||||||||
| if [ -f "CONTRIBUTING.md" ] && [ -f "CONTRIBUTING.adoc" ]; then | ||||||||||
| rm CONTRIBUTING.adoc | ||||||||||
| FIXES="$FIXES\n- Deleted duplicate \`CONTRIBUTING.adoc\` (keeping .md for GitHub)" | ||||||||||
| CHANGED=true | ||||||||||
| warn "AI.a2ml present without 0-AI-MANIFEST.a2ml (would be renamed)" | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| if [ -f "README.md" ] && [ -f "README.adoc" ]; then | ||||||||||
| # Only delete README.md if it's a stub (<5 lines) | ||||||||||
| lines=$(wc -l < README.md) | ||||||||||
| if [ "$lines" -lt 5 ]; then | ||||||||||
| rm README.md | ||||||||||
| FIXES="$FIXES\n- Deleted stub \`README.md\` (keeping .adoc)" | ||||||||||
| CHANGED=true | ||||||||||
| fi | ||||||||||
| # would-DELETE: duplicate community files | ||||||||||
| [ -f "CONTRIBUTING.md" ] && [ -f "CONTRIBUTING.adoc" ] && warn "duplicate CONTRIBUTING.md + CONTRIBUTING.adoc (one would be removed)" | ||||||||||
| if [ -f "README.md" ] && [ -f "README.adoc" ] && [ "$(wc -l < README.md)" -lt 5 ]; then | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Count the final unterminated line.
Proposed fix- if [ -f "README.md" ] && [ -f "README.adoc" ] && [ "$(wc -l < README.md)" -lt 5 ]; then
+ if [ -f "README.md" ] && [ -f "README.adoc" ] && [ "$(awk 'END { print NR }' README.md)" -lt 5 ]; then📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| warn "stub README.md alongside README.adoc (would be removed)" | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| # --- 4. Fix SPDX headers in dotfiles --- | ||||||||||
| # SPDX drift — MANUAL owner-only fix, never auto-edited | ||||||||||
| for dotfile in .gitignore .gitattributes .editorconfig; do | ||||||||||
| if [ -f "$dotfile" ] && grep -q "AGPL-3.0" "$dotfile" 2>/dev/null; then | ||||||||||
| sed -i 's/AGPL-3.0-or-later/MPL-2.0/g; s/AGPL-3.0/MPL-2.0/g' "$dotfile" | ||||||||||
| FIXES="$FIXES\n- Fixed SPDX header in \`$dotfile\` (AGPL → PMPL)" | ||||||||||
| CHANGED=true | ||||||||||
| if [ -f "$dotfile" ] && grep "AGPL-3.0" "$dotfile" 2>/dev/null | grep -v "AGPL-3.0-or-later" | grep -q .; then | ||||||||||
| warn "$dotfile carries an AGPL-3.0 SPDX header; estate policy is MPL-2.0 — fix MANUALLY (owner-only, never auto-edited)" | ||||||||||
| fi | ||||||||||
| done | ||||||||||
|
|
||||||||||
| # --- 5. Create missing required files --- | ||||||||||
| if [ ! -f "SECURITY.md" ]; then | ||||||||||
| cat > SECURITY.md << 'SECEOF' | ||||||||||
| <!-- SPDX-License-Identifier: MPL-2.0 --> | ||||||||||
| # Security Policy | ||||||||||
|
|
||||||||||
| ## Reporting a Vulnerability | ||||||||||
|
|
||||||||||
| **Email:** j.d.a.jewell@open.ac.uk | ||||||||||
|
|
||||||||||
| **Response timeline:** | ||||||||||
| - Acknowledgement within 48 hours | ||||||||||
| - Initial assessment within 7 days | ||||||||||
| - Fix or mitigation within 90 days | ||||||||||
|
|
||||||||||
| **Safe harbour:** We will not pursue legal action against security researchers who follow responsible disclosure. | ||||||||||
| SECEOF | ||||||||||
| FIXES="$FIXES\n- Created missing \`SECURITY.md\`" | ||||||||||
| CHANGED=true | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| if [ ! -f "CONTRIBUTING.md" ]; then | ||||||||||
| cat > CONTRIBUTING.md << 'CONTEOF' | ||||||||||
| <!-- SPDX-License-Identifier: MPL-2.0 --> | ||||||||||
| # Contributing | ||||||||||
|
|
||||||||||
| 1. Fork the repository | ||||||||||
| 2. Create a feature branch | ||||||||||
| 3. Ensure SPDX headers on all files | ||||||||||
| 4. Submit a pull request | ||||||||||
|
|
||||||||||
| **Author:** Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk> | ||||||||||
| CONTEOF | ||||||||||
| FIXES="$FIXES\n- Created missing \`CONTRIBUTING.md\`" | ||||||||||
| CHANGED=true | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| # --- 6. Check for issues we can't auto-fix --- | ||||||||||
| if [ ! -f "0-AI-MANIFEST.a2ml" ] && [ ! -f "AI.a2ml" ]; then | ||||||||||
| ISSUES="$ISSUES\n- Missing AI manifest (0-AI-MANIFEST.a2ml)" | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| if [ ! -f "LICENSE" ] && [ ! -f "LICENSE.md" ] && [ ! -f "LICENSE.txt" ]; then | ||||||||||
| ISSUES="$ISSUES\n- Missing LICENSE file" | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| if [ ! -f "README.adoc" ] && [ ! -f "README.md" ]; then | ||||||||||
| ISSUES="$ISSUES\n- Missing README" | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| # Check for third-party fork (skip SPDX enforcement) | ||||||||||
| if [ -f "LICENSE" ] && grep -q "multiple licenses\|LGPL\|Apache" LICENSE 2>/dev/null; then | ||||||||||
| echo "FORK=true" >> $GITHUB_OUTPUT | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| # --- 7. Check dangerous patterns --- | ||||||||||
| DANGEROUS="" | ||||||||||
| for pattern in "believe_me" "assert_total" "Admitted" "sorry" "unsafeCoerce" "Obj.magic"; do | ||||||||||
| count=$(grep -r "$pattern" --include='*.idr' --include='*.v' --include='*.lean' --include='*.hs' --include='*.ml' --include='*.res' . 2>/dev/null | grep -v node_modules | wc -l || echo 0) | ||||||||||
| if [ "$count" -gt 0 ]; then | ||||||||||
| DANGEROUS="$DANGEROUS\n- \`$pattern\`: $count occurrences" | ||||||||||
| fi | ||||||||||
| # would-CREATE: missing required files | ||||||||||
| [ -f "SECURITY.md" ] || [ -f ".github/SECURITY.md" ] || warn "no SECURITY.md (would be created)" | ||||||||||
| [ -f "CONTRIBUTING.md" ] || [ -f ".github/CONTRIBUTING.md" ] || warn "no CONTRIBUTING.md (would be created)" | ||||||||||
|
|
||||||||||
| # --- unfixable compliance gaps (also drift) --- | ||||||||||
| [ -f "0-AI-MANIFEST.a2ml" ] || [ -f "AI.a2ml" ] || warn "missing AI manifest (0-AI-MANIFEST.a2ml)" | ||||||||||
| [ -f "LICENSE" ] || [ -f "LICENSE.md" ] || [ -f "LICENSE.txt" ] || warn "missing LICENSE file" | ||||||||||
| [ -f "README.adoc" ] || [ -f "README.md" ] || warn "missing README" | ||||||||||
|
|
||||||||||
| # --- advisory only: dangerous verification-bypass patterns --- | ||||||||||
| for pattern in believe_me assert_total Admitted sorry unsafeCoerce Obj.magic; do | ||||||||||
| count=$(grep -rl "$pattern" --include='*.idr' --include='*.v' --include='*.lean' --include='*.hs' --include='*.ml' --include='*.res' . 2>/dev/null | grep -v node_modules | wc -l || true) | ||||||||||
|
Comment on lines
+82
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '1,110p' verification/proofs/README.adoc
sed -n '1,110p' .github/workflows/rhodibot.yml
rg -n 'postulate|\.agda|believe_me|assert_total|unsafeCoerce|proofs-only' .github verification README* CONTRIBUTING* 2>/dev/nullRepository: hyperpolymath/krl Length of output: 8696 🏁 Script executed: #!/bin/bash
set -o pipefail
printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/*' | sort
printf '%s\n' '--- enforcement and canary references ---'
rg -n -C 3 'panic-attack|proofs-only|postulate|\\.agda|Rhodibot|canary|verification-bypass' .github verification justfile Makefile README* CONTRIBUTING* 2>/dev/nullRepository: hyperpolymath/krl Length of output: 23043 Include - for pattern in believe_me assert_total Admitted sorry unsafeCoerce Obj.magic; do
- count=$(grep -rl "$pattern" --include='*.idr' --include='*.v' --include='*.lean' --include='*.hs' --include='*.ml' --include='*.res' . 2>/dev/null | grep -v node_modules | wc -l || true)
+ for pattern in believe_me assert_total postulate Admitted sorry unsafeCoerce Obj.magic; do
+ count=$(grep -rl "$pattern" --include='*.idr' --include='*.agda' --include='*.v' --include='*.lean' --include='*.hs' --include='*.ml' --include='*.res' . 2>/dev/null | grep -v node_modules | wc -l || true)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| [ "$count" -gt 0 ] && note "verification-bypass pattern '$pattern' in $count file(s) (advisory)" | ||||||||||
| done | ||||||||||
|
|
||||||||||
| # Output results | ||||||||||
| echo "CHANGED=$CHANGED" >> $GITHUB_OUTPUT | ||||||||||
| { | ||||||||||
| echo "FIXES<<EOF" | ||||||||||
| echo -e "$FIXES" | ||||||||||
| echo "EOF" | ||||||||||
| } >> $GITHUB_OUTPUT | ||||||||||
| { | ||||||||||
| echo "ISSUES<<EOF" | ||||||||||
| echo -e "$ISSUES" | ||||||||||
| echo "EOF" | ||||||||||
| } >> $GITHUB_OUTPUT | ||||||||||
| { | ||||||||||
| echo "DANGEROUS<<EOF" | ||||||||||
| echo -e "$DANGEROUS" | ||||||||||
| echo "EOF" | ||||||||||
| } >> $GITHUB_OUTPUT | ||||||||||
| - name: Create PR with fixes | ||||||||||
| if: steps.fix.outputs.CHANGED == 'true' | ||||||||||
| run: "git config user.name \"rhodibot\"\ngit config user.email \"rhodibot@hyperpolymath.dev\"\nBRANCH=\"rhodibot/rsr-compliance-$(date +%Y%m%d)\"\ngit checkout -b \"$BRANCH\"\ngit add -A\ngit commit -m \"fix(rhodibot): automated RSR compliance fixes\n\n${{ steps.fix.outputs.FIXES }}\n\nCo-Authored-By: rhodibot <rhodibot@hyperpolymath.dev>\"\n\ngit push origin \"$BRANCH\"\n\nBODY=\"## \U0001F916 Rhodibot — RSR Compliance Fixes\n\n### Changes Made\n${{ steps.fix.outputs.FIXES }}\n\"\n\nif [ -n \"${{ steps.fix.outputs.ISSUES }}\" ]; then\n BODY=\"$BODY\n### Issues Found (manual fix needed)\n${{ steps.fix.outputs.ISSUES }}\n\"\nfi\n\nif [ -n \"${{ steps.fix.outputs.DANGEROUS }}\" ]; then\n BODY=\"$BODY\n### ⚠️ Dangerous Patterns Detected\n${{ steps.fix.outputs.DANGEROUS }}\n\n_These bypass formal verification. See \\`proven\\` repo for alternatives._\n\"\nfi\n\ngh pr create \\\n --title \"\U0001F916 Rhodibot: RSR compliance fixes\" \\\n --body \"$BODY\" \\\n --base main \\\n --head \"$BRANCH\"\n" | ||||||||||
| env: | ||||||||||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||||||
| - name: Report (no changes needed) | ||||||||||
| if: steps.fix.outputs.CHANGED != 'true' | ||||||||||
| run: | | ||||||||||
| echo "✅ Repository is RSR-compliant. No fixes needed." | ||||||||||
| if [ -n "${{ steps.fix.outputs.ISSUES }}" ]; then | ||||||||||
| echo "⚠️ Issues found (manual fix needed):" | ||||||||||
| echo -e "${{ steps.fix.outputs.ISSUES }}" | ||||||||||
| fi | ||||||||||
| if [ -n "${{ steps.fix.outputs.DANGEROUS }}" ]; then | ||||||||||
| echo "⚠️ Dangerous patterns:" | ||||||||||
| echo -e "${{ steps.fix.outputs.DANGEROUS }}" | ||||||||||
| echo "" >> "$GITHUB_STEP_SUMMARY" | ||||||||||
| if [ "$DRIFT" -gt 0 ]; then | ||||||||||
| echo "🔴 **Canary tripped: $DRIFT would-mutate finding(s).** Either the repo drifted or rhodibot's rules diverged from the norm — investigate (no edits were made)." >> "$GITHUB_STEP_SUMMARY" | ||||||||||
| echo "::error title=Rhodibot canary::$DRIFT would-mutate finding(s) detected — rhodibot wants to edit. Investigate; nothing was changed." | ||||||||||
| exit 1 | ||||||||||
| fi | ||||||||||
| echo "✅ Canary clean — rhodibot has no desire to edit. Repository matches the norm." >> "$GITHUB_STEP_SUMMARY" | ||||||||||
| echo "✅ Rhodibot canary clean — no drift, no mutations." | ||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🛡️ Analyzed with Security Review | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: hyperpolymath/krl
Length of output: 14586
🤖 get_repo_knowledge executed:
get_repo_knowledge hyperpolymath/krl /tmp/coderabbit-repo-knowledge/hyperpolymath-krl-cef792b7/conventionsLength of output: 4232
🏁 Script executed:
Repository: hyperpolymath/krl
Length of output: 22823
Security Misconfiguration
Reachability: External
Exploitability: Difficult
CWE: CWE-829 — Inclusion of Functionality from Untrusted Control Sphere
Pin
actions/checkoutto an immutable commit and regenerate the lock file.actions/checkout@v7.0.1is a mutable tag. A retargeted or compromised tag can execute code with this job’s repository read token. Replace it with the verified commit SHA forv7.0.1, then rungh actions-lockand commit the resulting.github/workflows/actions.lockupdate. The lock file is generated; do not edit it by hand.🤖 Prompt for AI Agents