Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `brigade work import dismiss` to close noisy imports without promoting them.
- `brigade work import promote --all` with optional `--source` and `--kind` filters for batch promotion.
- `docs/import-schema.md` documenting the local import JSONL contract for scanners and wrappers.
- Cybersecurity plugin roadmap covering broad agent-workspace security checks plus Brigade-specific scanner, doctor, import, and multi-harness security checks.
- Built-in `security` station and `brigade security scan` for read-only agent workspace security checks.
- `brigade security scan --import-findings` to route security findings into the local work import inbox for review.
- `ROADMAP.md` covering the daily-driver path, scanner-ready inbox, chat-surface scanners, memory-card decay refresh, and portable operator setup.
- `brigade work note` to append timestamped checkpoints to the active work session without ending it.
- `brigade work doctor` to check dogfood config, Codex availability, local artifact paths, handoff inbox, ignore coverage, and latest run context for the daily work loop.
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ The cookbook explains the why. This package gives you the kitchen.
- memory-care staleness checks so durable cards do not quietly rot
- TokenJuice output-compaction guidance for Claude Code and Codex, including wrapper notes and savings expectations
- content-guard publish gates so private infrastructure does not leak into public docs
- built-in agent workspace security scan for secrets, permissions, hooks, MCP configs, supply-chain patterns, and instruction risks
- adapter fragments for OpenClaw (tested), Hermes (stubbed), and generic harnesses
- doctor checks that prove the system is wired before you trust it

Expand Down Expand Up @@ -201,6 +202,8 @@ Inspect a completed run without opening each JSON file:
brigade runs list --cwd /path/to/repo
brigade runs latest --cwd /path/to/repo
brigade runs show .brigade/runs/<run-id>
brigade security scan --target .
brigade security scan --target . --import-findings
```

Use `--handoff` to bridge a completed run back into the memory system. By default it writes a reviewable handoff to `.claude/memory-handoffs/` under `--cwd`; override with `--handoff-inbox <path>` for Codex, OpenCode, GPT, Hermes, OpenClaw, or any other non-Claude writer inbox. The handoff targets `.learnings/LEARNINGS.md` as a `no-card` document update, so the normal `brigade ingest` route can review or ingest it. If handoff writing fails after synthesis, Brigade still prints the final answer and keeps the final artifacts, but exits nonzero and marks `run.json` as `handoff-failed`. `--handoff` is not allowed with `--dry-run` because dry runs have no final answer.
Expand Down Expand Up @@ -284,7 +287,9 @@ brigade add guard # content-guard
brigade add tokens # tokenjuice
```

The four managed tools:
`security` is a built-in station with no external managed tool yet. Run `brigade security scan --target .` for a read-only agent workspace security report, or add `--import-findings` to turn findings into local `brigade work import` review items.

The current managed tools:

| Station | Tool | What it does |
|---|---|---|
Expand Down
34 changes: 34 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,40 @@ Goal: support the common places agent work happens without making any one chat p
- Use promotion gates so only reviewed, durable, or actionable items become tasks or memory handoffs.
- Keep source metadata such as workspace, channel, thread, message range, and confidence local unless explicitly exported.

## Later Phase: Cybersecurity Plugin

Goal: ship a Brigade cybersecurity plugin with broad coverage for agent workspaces, then go deeper on Brigade's multi-harness, memory, scanner, and dogfood workflows.

Baseline coverage targets:

- Scan agent workspace configs for hardcoded secrets, exposed tokens, private keys, database URLs, and unsafe environment-variable handling.
- Audit tool permissions for broad mutable access, wildcard shell access, missing deny lists, dangerous flags, destructive git commands, and unrestricted network commands.
- Analyze hooks and startup automation for command injection, remote execution, data exfiltration, silent failures, package installs, container escape, reverse shells, clipboard access, log tampering, and persistence behaviors.
- Audit MCP server configs for high-risk server types, remote transports, shell metacharacters, unpinned `npx` usage, hardcoded env secrets, sensitive file args, excessive server counts, missing timeouts, and auto-approve behavior.
- Review agent prompts, skills, subagents, slash commands, and workspace instructions for prompt-injection patterns, hidden instructions, URL execution, data harvesting, output suppression, time bombs, and unsafe auto-run language.
- Emit graded reports with severity, category scores, evidence snippets, suggested fixes, JSON output, markdown output, HTML or bundle output, and CI-friendly exit codes.
- Support CLI use, GitHub Action use, and local evidence packs.

Brigade-specific additions:

- Scan Claude Code, Codex, OpenCode, Gemini, Hermes, OpenClaw, VS Code, Zed, dmux, and generic repo-local agent harness surfaces with explicit runtime-confidence labels.
- Understand Brigade installs: `.brigade/`, `.codex/`, `.claude/`, memory handoff inboxes, roster files, dogfood configs, run artifacts, work imports, memory-care decay files, and public template folders.
- Treat public-template findings differently from active runtime findings so docs and starter templates do not score like live credentials or enabled tools.
- Integrate with `brigade doctor` as a security station and with `brigade work import` so findings can become reviewable local tasks instead of only console output.
- Provide safe auto-fix only for narrow cases such as replacing obvious hardcoded sample secrets, tightening generated allow-list examples, or adding missing ignore rules.
- Produce Memory Handoffs for durable security findings while keeping raw secret evidence redacted.
- Add policy packs for personal dogfooding, public-repo release checks, CI gates, and strict enterprise workspaces.
- Include dependency and package-manager hardening checks for agent plugin ecosystems, MCP packages, skills, and local tool wrappers.
- Track false-positive taxonomy, runtime-confidence rules, suppressions, and regression fixtures as first-class project artifacts.

First build slice:

- Create a plugin scaffold and security scan contract. Status: started with built-in `security` station and `brigade security scan`.
- Start with config discovery and read-only reporting for Brigade, Claude Code, Codex, and MCP config files. Status: started.
- Add core rule categories for secrets, permissions, hooks, MCP servers, supply-chain patterns, and agent instructions. Status: started.
- Output JSON plus readable text, then route selected findings into `brigade work import`. Status: started with `--import-findings`.
- Keep all raw findings local and gitignored unless the operator explicitly exports an evidence pack. Status: current default.

## Later Phase: Memory Card Decay And Refresh

Goal: prevent durable memory from silently rotting.
Expand Down
31 changes: 31 additions & 0 deletions src/brigade/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,25 @@ def _build_parser() -> argparse.ArgumentParser:
)
p_scrub.add_argument("--dry-run", action="store_true")

# security
p_security = sub.add_parser("security", help="Scan agent workspace security posture.")
security_sub = p_security.add_subparsers(dest="security_command", metavar="<security-command>")
security_sub.required = True
p_security_scan = security_sub.add_parser("scan", help="Run a read-only agent workspace security scan.")
p_security_scan.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to scan.")
p_security_scan.add_argument("--json", action="store_true", help="Print machine-readable JSON.")
p_security_scan.add_argument(
"--fail-on",
choices=["none", "low", "medium", "high", "critical"],
default="critical",
help="Return nonzero when a finding at or above this severity exists.",
)
p_security_scan.add_argument(
"--import-findings",
action="store_true",
help="Append findings to the local Brigade work import inbox.",
)

# handoff-template
p_ht = sub.add_parser("handoff-template", help="Print the handoff TEMPLATE.md.")
p_ht.add_argument(
Expand Down Expand Up @@ -739,6 +758,18 @@ def main(argv=None) -> int:
from . import scrub as scrub_mod

return scrub_mod.run(target=args.target, policy=args.policy, dry_run=args.dry_run)
if cmd == "security":
from . import security_cmd

if args.security_command == "scan":
return security_cmd.scan(
target=args.target,
json_output=args.json,
fail_on=args.fail_on,
import_findings=args.import_findings,
)
parser.error(f"unknown security command: {args.security_command}")
return 2
if cmd == "handoff-template":
from . import handoff as handoff_mod

Expand Down
4 changes: 4 additions & 0 deletions src/brigade/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ def tokens_station_checks(ctx: DoctorContext) -> List[CheckResult]:
return []


def security_station_checks(ctx: DoctorContext) -> List[CheckResult]:
return [(OK, "security: built-in scanner", "run `brigade security scan --target .`")]


def run(target: Path, harness: str = "generic") -> int:
from .registry import all_stations
from . import managed
Expand Down
8 changes: 7 additions & 1 deletion src/brigade/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@
doctor=_doctor.tokens_station_checks,
tools=("tokenjuice",),
)
SECURITY = Station(
name="security",
summary="agent workspace security scanning",
aliases=("sec",),
doctor=_doctor.security_station_checks,
)

_BUILTIN: Tuple[Station, ...] = (CORE, MEMORY, GUARD, TOKENS)
_BUILTIN: Tuple[Station, ...] = (CORE, MEMORY, GUARD, TOKENS, SECURITY)


def all_stations() -> Tuple[Station, ...]:
Expand Down
Loading
Loading