-
-
Notifications
You must be signed in to change notification settings - Fork 0
ci(rhodibot): switch to the report-only canary (standards#759) #78
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,236 +1,94 @@ | ||||||||||||||||||
| # SPDX-License-Identifier: MPL-2.0 | ||||||||||||||||||
| # This workflow is managed by gh actions-lock. | ||||||||||||||||||
| # This workflow is managed by gh actions-lock. | ||||||||||||||||||
| # rhodibot.yml — Automated RSR compliance enforcement | ||||||||||||||||||
| # SPDX-License-Identifier: MPL-2.0 | ||||||||||||||||||
| # 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 → MPL-2.0 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. | ||||||||||||||||||
|
|
||||||||||||||||||
| name: "🤖 Rhodibot — RSR Auto-Fix" | ||||||||||||||||||
| # 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 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] | ||||||||||||||||||
| - cron: '0 6 * * 1' # Every Monday at 06:00 UTC | ||||||||||||||||||
| workflow_dispatch: # Manual trigger | ||||||||||||||||||
|
|
||||||||||||||||||
| permissions: | ||||||||||||||||||
| contents: write | ||||||||||||||||||
| pull-requests: write | ||||||||||||||||||
| concurrency: | ||||||||||||||||||
| group: ${{ github.workflow }}-${{ github.ref }} | ||||||||||||||||||
| cancel-in-progress: true | ||||||||||||||||||
|
|
||||||||||||||||||
| permissions: | ||||||||||||||||||
| contents: read | ||||||||||||||||||
| jobs: | ||||||||||||||||||
| rhodibot: | ||||||||||||||||||
| canary: | ||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||
| timeout-minutes: 15 | ||||||||||||||||||
| steps: | ||||||||||||||||||
| - name: Checkout | ||||||||||||||||||
| 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 | ||||||||||||||||||
| warn "AI.a2ml present without 0-AI-MANIFEST.a2ml (would be renamed)" | ||||||||||||||||||
| 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 | ||||||||||||||||||
| # 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 | ||||||||||||||||||
| warn "stub README.md alongside README.adoc (would be removed)" | ||||||||||||||||||
| 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 --- | ||||||||||||||||||
| # 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 → MPL-2.0)" | ||||||||||||||||||
| 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)" | ||||||||||||||||||
|
Comment on lines
+68
to
+69
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 '31,95p' .github/workflows/rhodibot.yml
bash --version | head -1Repository: hyperpolymath/atsiser Length of output: 3993 🏁 Script executed: #!/usr/bin/env bash
set -u
printf '%s\n' '--- relevant workflow lines ---'
nl -ba .github/workflows/rhodibot.yml | sed -n '40,74p'
printf '%s\n' '--- dotfile sizes and matching lines ---'
for f in .gitignore .gitattributes .editorconfig; do
if [ -f "$f" ]; then
printf '%s: ' "$f"
wc -c -l "$f"
printf '%s\n' 'matching non-later lines:'
grep 'AGPL-3.0' "$f" 2>/dev/null | grep -v 'AGPL-3.0-or-later' || true
else
printf '%s: absent\n' "$f"
fi
done
printf '%s\n' '--- synthetic pipefail probe ---'
python3 - <<'PY'
from pathlib import Path
p = Path('/tmp/rhodibot-pipefail-probe.txt')
for n in [1, 10, 100, 500, 1000, 2000, 4000, 8000, 16000, 32000]:
p.write_text('AGPL-3.0\\n' * n)
print(f'n={n}', end=' ')
# Keep the pipeline and PIPESTATUS in the same shell.
import subprocess
script = r'''
set -o pipefail
grep "AGPL-3.0" "$1" 2>/dev/null | grep -v "AGPL-3.0-or-later" | grep -q .
ps=("${PIPESTATUS[@]}")
printf 'status=%s pipe_status=%s\n' "$?" "${ps[*]}"
'''
out = subprocess.check_output(
['bash', '-c', script, 'probe', str(p)],
text=True,
stderr=subprocess.STDOUT,
)
print(out.strip())
p.unlink()
PYRepository: hyperpolymath/atsiser Length of output: 3131 🏁 Script executed: #!/usr/bin/env bash
set -u
printf '%s\n' '--- relevant workflow lines ---'
nl -ba .github/workflows/rhodibot.yml | sed -n '40,74p'
printf '%s\n' '--- dotfile sizes and matching lines ---'
for f in .gitignore .gitattributes .editorconfig; do
if [ -f "$f" ]; then
printf '%s: ' "$f"
wc -c -l "$f"
printf '%s\n' 'matching non-later lines:'
grep 'AGPL-3.0' "$f" 2>/dev/null | grep -v 'AGPL-3.0-or-later' || true
else
printf '%s: absent\n' "$f"
fi
done
printf '%s\n' '--- synthetic pipefail probe ---'
python3 - <<'PY'
from pathlib import Path
import subprocess
p = Path('/tmp/rhodibot-pipefail-probe.txt')
for n in [1, 10, 100, 500, 1000, 2000, 4000, 8000, 16000, 32000]:
p.write_text('AGPL-3.0\n' * n)
print(f'n={n}', end=' ')
script = r'''
set -o pipefail
grep "AGPL-3.0" "$1" 2>/dev/null | grep -v "AGPL-3.0-or-later" | grep -q .
ps=("${PIPESTATUS[@]}")
printf 'pipe_status=%s\n' "${ps[*]}"
'''
out = subprocess.check_output(
['bash', '-c', script, 'probe', str(p)],
text=True,
stderr=subprocess.STDOUT,
)
print(out.strip())
p.unlink()
PYRepository: hyperpolymath/atsiser Length of output: 3053 Avoid When the first two Count the offending lines instead: 🐛 Proposed fix for the pipefail false negative for dotfile in .gitignore .gitattributes .editorconfig; do
- if [ -f "$dotfile" ] && grep "AGPL-3.0" "$dotfile" 2>/dev/null | grep -v "AGPL-3.0-or-later" | grep -q .; then
+ agpl_hits=0
+ if [ -f "$dotfile" ]; then
+ agpl_hits=$(grep "AGPL-3.0" "$dotfile" 2>/dev/null | grep -cv "AGPL-3.0-or-later" || true)
+ fi
+ if [ "${agpl_hits:-0}" -gt 0 ]; 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📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
| 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) | ||||||||||||||||||
| [ "$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" | ||||||||||||||||||
| git config user.email "rhodibot@hyperpolymath.dev" | ||||||||||||||||||
| BRANCH="rhodibot/rsr-compliance-$(date +%Y%m%d)" | ||||||||||||||||||
| git checkout -b "$BRANCH" | ||||||||||||||||||
| git add -A | ||||||||||||||||||
| git commit -m "fix(rhodibot): automated RSR compliance fixes | ||||||||||||||||||
|
|
||||||||||||||||||
| ${{ steps.fix.outputs.FIXES }} | ||||||||||||||||||
|
|
||||||||||||||||||
| Co-Authored-By: rhodibot <rhodibot@hyperpolymath.dev>" | ||||||||||||||||||
|
|
||||||||||||||||||
| git push origin "$BRANCH" | ||||||||||||||||||
|
|
||||||||||||||||||
| BODY="## 🤖 Rhodibot — RSR Compliance Fixes | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Changes Made | ||||||||||||||||||
| ${{ steps.fix.outputs.FIXES }} | ||||||||||||||||||
| " | ||||||||||||||||||
|
|
||||||||||||||||||
| if [ -n "${{ steps.fix.outputs.ISSUES }}" ]; then | ||||||||||||||||||
| BODY="$BODY | ||||||||||||||||||
| ### Issues Found (manual fix needed) | ||||||||||||||||||
| ${{ steps.fix.outputs.ISSUES }} | ||||||||||||||||||
| " | ||||||||||||||||||
| fi | ||||||||||||||||||
|
|
||||||||||||||||||
| if [ -n "${{ steps.fix.outputs.DANGEROUS }}" ]; then | ||||||||||||||||||
| BODY="$BODY | ||||||||||||||||||
| ### ⚠️ Dangerous Patterns Detected | ||||||||||||||||||
| ${{ steps.fix.outputs.DANGEROUS }} | ||||||||||||||||||
|
|
||||||||||||||||||
| _These bypass formal verification. See \`proven\` repo for alternatives._ | ||||||||||||||||||
| " | ||||||||||||||||||
| fi | ||||||||||||||||||
|
|
||||||||||||||||||
| gh pr create \ | ||||||||||||||||||
| --title "🤖 Rhodibot: RSR compliance fixes" \ | ||||||||||||||||||
| --body "$BODY" \ | ||||||||||||||||||
| --base main \ | ||||||||||||||||||
| --head "$BRANCH" | ||||||||||||||||||
| 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.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Write each finding to the step summary.
warnandnoteemit annotations only. The step summary receives the header, a blank line, and the final verdict. An owner who opens the run summary sees the count but not the findings. Annotations for a scheduled run are also easy to miss.Append each message to
$GITHUB_STEP_SUMMARYin both helpers.♻️ Proposed fix to record findings in the summary
📝 Committable suggestion
🤖 Prompt for AI Agents