Skip to content

Commit 753f801

Browse files
Jonathan D.A. Jewellclaude
andcommitted
feat(panicbot): add Tier 1 Verifier bot wrapping panic-attack
Panicbot fills the fleet audit gap: wraps panic-attack as a subprocess, translates WeakPoint findings into fleet Finding structs (PA001–PA020), classifies fixable vs unfixable, writes unfixable to per-repo A2ML debt registers (.panicbot/PANICBOT-FINDINGS.a2ml), and feeds fixable issues to Hypatia for automated remediation. New crate: bots/panicbot/ (10 source files, 3 test files, 74 tests passing) - scanner.rs: subprocess wrapper for panic-attack assail/adjudicate/diagnostics - translator.rs: 20 WeakPoint categories mapped to fleet categories + triangle tiers - a2ml_writer.rs: A2ML debt register generation (overwrite-per-scan semantics) - directives.rs: per-repo config from .machine_readable/bot_directives/panicbot.scm - fleet.rs: BotMode (Advisor/Auditor/Guardian) + run_fleet_scan pipeline - config.rs: configurable confidence values, severity filters, timeouts Modified: - shared-context/src/bot.rs: Panicbot variant in BotId enum + BotInfo::standard() - fleet-coordinator.sh: panicbot in execution order + run_panicbot_scan() + deploy status - .github/workflows/panicbot-sweep.yml: weekly cron batch scan of all repos Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7b5d288 commit 753f801

16 files changed

Lines changed: 3277 additions & 8 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Panicbot Sweep — weekly batch scan of all repos via panic-attack.
3+
#
4+
# Catches drift in dormant repos that don't get per-PR scans.
5+
# Active repos are already scanned on every push via hypatia-scan.yml.
6+
7+
name: Panicbot Sweep
8+
9+
on:
10+
schedule:
11+
# Sunday 04:00 UTC — weekly sweep of all repos
12+
- cron: '0 4 * * 0'
13+
workflow_dispatch:
14+
inputs:
15+
scope:
16+
description: 'Scan scope (all, or a specific repo name)'
17+
required: false
18+
default: 'all'
19+
type: string
20+
mode:
21+
description: 'Bot operating mode'
22+
required: false
23+
default: 'advisor'
24+
type: choice
25+
options:
26+
- advisor
27+
- auditor
28+
- guardian
29+
30+
permissions: read-all
31+
32+
jobs:
33+
sweep:
34+
name: Panicbot Sweep Scan
35+
runs-on: ubuntu-latest
36+
timeout-minutes: 120
37+
38+
steps:
39+
- name: Checkout gitbot-fleet
40+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
41+
42+
- name: Install Rust toolchain
43+
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
44+
with:
45+
toolchain: stable
46+
47+
- name: Cache Rust dependencies
48+
uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
49+
with:
50+
workspaces: |
51+
bots/panicbot -> target
52+
shared-context -> target
53+
54+
- name: Build panicbot
55+
run: |
56+
cd bots/panicbot
57+
cargo build --release
58+
59+
- name: Install panic-attack
60+
run: |
61+
if ! command -v panic-attack &>/dev/null; then
62+
echo "::warning::panic-attack not found, attempting cargo install"
63+
cargo install panic-attacker || echo "::error::Failed to install panic-attack"
64+
fi
65+
66+
- name: Run sweep
67+
env:
68+
PANICBOT_MODE: ${{ inputs.mode || 'advisor' }}
69+
PANICBOT_SCOPE: ${{ inputs.scope || 'all' }}
70+
run: |
71+
set -euo pipefail
72+
73+
PANICBOT="./bots/panicbot/target/release/panicbot"
74+
FINDINGS_DIR="shared-context/findings"
75+
SESSION_ID="$(date +%Y%m%d-%H%M%S)"
76+
77+
mkdir -p "$FINDINGS_DIR"
78+
79+
echo "::group::Panicbot Sweep ($PANICBOT_SCOPE)"
80+
echo "Mode: $PANICBOT_MODE"
81+
echo "Session: $SESSION_ID"
82+
83+
if [[ "$PANICBOT_SCOPE" == "all" ]]; then
84+
# Scan the repos we have access to (gitbot-fleet itself + test fixtures)
85+
echo "Scanning gitbot-fleet repository..."
86+
$PANICBOT fleet . --mode "$PANICBOT_MODE" --format json \
87+
> "$FINDINGS_DIR/gitbot-fleet-${SESSION_ID}.json" 2>&1 || true
88+
else
89+
# Scan a specific repo
90+
echo "Scanning $PANICBOT_SCOPE..."
91+
$PANICBOT fleet "$PANICBOT_SCOPE" --mode "$PANICBOT_MODE" --format json \
92+
> "$FINDINGS_DIR/${PANICBOT_SCOPE}-${SESSION_ID}.json" 2>&1 || true
93+
fi
94+
95+
echo "::endgroup::"
96+
97+
- name: Process findings
98+
if: always()
99+
run: |
100+
FINDINGS_DIR="shared-context/findings"
101+
TOTAL=$(find "$FINDINGS_DIR" -name "*.json" -newer "$FINDINGS_DIR" 2>/dev/null | wc -l)
102+
103+
echo "## Panicbot Sweep Results" >> "$GITHUB_STEP_SUMMARY"
104+
echo "" >> "$GITHUB_STEP_SUMMARY"
105+
echo "- **Findings files**: $TOTAL" >> "$GITHUB_STEP_SUMMARY"
106+
echo "- **Mode**: ${{ inputs.mode || 'advisor' }}" >> "$GITHUB_STEP_SUMMARY"
107+
echo "- **Scope**: ${{ inputs.scope || 'all' }}" >> "$GITHUB_STEP_SUMMARY"
108+
109+
- name: Upload findings artifact
110+
if: always()
111+
uses: actions/upload-artifact@v4
112+
with:
113+
name: panicbot-sweep-findings
114+
path: shared-context/findings/
115+
retention-days: 90
116+
if-no-files-found: ignore

bots/panicbot/Cargo.toml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
[package]
3+
name = "panicbot"
4+
version = "0.1.0"
5+
edition = "2021"
6+
license = "PMPL-1.0-or-later"
7+
authors = ["Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"]
8+
description = "Targeted audit bot wrapping panic-attack static analysis for gitbot-fleet"
9+
repository = "https://github.com/hyperpolymath/gitbot-fleet"
10+
keywords = ["static-analysis", "security", "audit", "gitbot-fleet"]
11+
categories = ["development-tools"]
12+
13+
[[bin]]
14+
name = "panicbot"
15+
path = "src/main.rs"
16+
17+
[dependencies]
18+
# Fleet integration
19+
gitbot-shared-context = { path = "../../shared-context" }
20+
21+
# CLI
22+
clap = { version = "4", features = ["derive"] }
23+
24+
# Serialization
25+
serde = { version = "1", features = ["derive"] }
26+
serde_json = "1"
27+
28+
# Error handling
29+
anyhow = "1"
30+
31+
# Logging
32+
tracing = "0.1"
33+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
34+
35+
# Unique IDs
36+
uuid = { version = "1", features = ["v4"] }
37+
38+
# Date/time
39+
chrono = { version = "0.4", features = ["serde"] }
40+
41+
[dev-dependencies]
42+
tempfile = "3"

0 commit comments

Comments
 (0)