🤖 Rhodibot — RSR Auto-Fix #12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # // Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk> | |
| # SPDX-License-Identifier: MPL-2.0 | |
| # rhodibot.yml — Automated RSR compliance enforcement | |
| # | |
| # 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 | |
| # | |
| # Runs weekly and on Hypatia scan completion. | |
| name: "\U0001F916 Rhodibot — RSR Auto-Fix" | |
| on: | |
| schedule: | |
| - cron: '0 6 * * 1' # Every Monday at 06:00 UTC | |
| workflow_dispatch: # Manual trigger | |
| workflow_run: | |
| workflows: ["Hypatia Neurosymbolic Analysis"] | |
| types: [completed] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| rhodibot: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Rhodibot — Scan and Fix | |
| id: fix | |
| run: | | |
| set -euo pipefail | |
| FIXES="" | |
| ISSUES="" | |
| CHANGED=false | |
| # --- 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 | |
| # Delete stale snapshot files | |
| 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 | |
| done | |
| # --- 2. Rename misnamed files --- | |
| 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 | |
| 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 | |
| fi | |
| # --- 4. Fix SPDX headers in dotfiles --- | |
| 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 | |
| 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 | |
| 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 }}" | |
| fi |