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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Built-in `security` station and `brigade security scan` for read-only agent workspace security checks.
- Deeper MCP security checks for unpinned `npx`, shell metacharacters, secret-looking env values, sensitive or broad file args, high-risk local commands, large server sets, and missing timeouts.
- Supply-chain security checks for package scripts, GitHub Actions permissions and action refs, Python URL dependencies, and legacy install hooks.
- `brigade security enrich` for explicit post-scan enrichment artifacts, with an offline local provider and opt-in MISP provider config.
- `brigade security scan --import-findings` to route security findings into the local work import inbox for review.
- `brigade security init` to write gitignored local defaults to `.brigade/security.toml`.
- `brigade security fix` to create the local security artifact directory and refresh the managed `.gitignore` block.
Expand Down
255 changes: 232 additions & 23 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Baseline coverage targets:
- 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. Status: started with redacted JSON and Markdown evidence bundles.
- Support CLI use, GitHub Action use, and local evidence packs.
- Add optional threat-intel enrichment, including MISP as an opt-in provider, without changing the default no-network local scan behavior.
- Add optional threat-intel enrichment, including MISP as an opt-in provider, without changing the default no-network local scan behavior. Status: started with explicit `brigade security enrich`, offline local enrichment, MISP provider config, and separate enrichment artifacts.

Brigade-specific additions:

Expand All @@ -66,7 +66,7 @@ Brigade-specific additions:
- 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. Status: started with `personal`, `public-repo`, and `strict`.
- Include dependency and package-manager hardening checks for agent plugin ecosystems, MCP packages, skills, and local tool wrappers. Status: started with package scripts, GitHub Actions refs and permissions, Python URL dependencies, and legacy install hooks.
- Enrich reviewed indicators and suspicious package or domain findings through optional providers such as MISP, then route enriched findings into local evidence bundles and work imports.
- Enrich reviewed indicators and suspicious package or domain findings through optional providers such as MISP, then route enriched findings into local evidence bundles and work imports. Status: started with `security-enrichment.json`, `security-enrichment.md`, and review/doctor visibility.
- Track false-positive taxonomy, runtime-confidence rules, suppressions, and regression fixtures as first-class project artifacts. Status: started with `brigade security review`, reasoned suppressions, unsuppress, and stale-suppression doctor warnings.

## Later Phase: Issue And TDD Work Loop
Expand Down
25 changes: 25 additions & 0 deletions src/brigade/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,23 @@ def _build_parser() -> argparse.ArgumentParser:
p_security_review.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to review.")
p_security_review.add_argument("--output-dir", type=Path, default=None, help="Security evidence bundle directory.")
p_security_review.add_argument("--json", action="store_true", help="Print machine-readable JSON.")
p_security_enrich = security_sub.add_parser("enrich", help="Enrich an existing security report.")
p_security_enrich.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to enrich.")
p_security_enrich.add_argument(
"--output-dir",
type=Path,
default=None,
help="Security evidence bundle directory. Defaults to .brigade/security/latest.",
)
p_security_enrich.add_argument(
"--report",
dest="report_path",
type=Path,
default=None,
help="Explicit security-report.json path. Defaults to --output-dir/security-report.json.",
)
p_security_enrich.add_argument("--provider", choices=["local", "misp"], default=None, help="Override configured provider.")
p_security_enrich.add_argument("--json", action="store_true", help="Print machine-readable JSON.")
p_security_suppress = security_sub.add_parser("suppress", help="Suppress a reviewed security finding fingerprint.")
p_security_suppress.add_argument("fingerprint", help="Finding fingerprint to suppress.")
p_security_suppress.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
Expand Down Expand Up @@ -809,6 +826,14 @@ def main(argv=None) -> int:
return security_cmd.fix(target=args.target, dry_run=args.dry_run)
if args.security_command == "review":
return security_cmd.review(target=args.target, output_dir=args.output_dir, json_output=args.json)
if args.security_command == "enrich":
return security_cmd.enrich(
target=args.target,
output_dir=args.output_dir,
report_path=args.report_path,
provider=args.provider,
json_output=args.json,
)
if args.security_command == "suppress":
return security_cmd.suppress(target=args.target, fingerprint=args.fingerprint, reason=args.reason)
if args.security_command == "unsuppress":
Expand Down
5 changes: 5 additions & 0 deletions src/brigade/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ def security_station_checks(ctx: DoctorContext) -> List[CheckResult]:
results.append((FAIL, "security: config", f"invalid {config}: {exc}"))
else:
results.append((OK, "security: config", f"{config} (policy={loaded.policy if loaded else 'personal'})"))
enrichment = security_cmd.enrichment_health(ctx.target)
if enrichment.get("configured"):
results.append((OK, "security: enrichment", f"{enrichment.get('provider')} ({enrichment.get('status')})"))
else:
results.append((WARN, "security: enrichment", str(enrichment.get("status"))))
else:
results.append((WARN, "security: config", f"missing at {config}; run `brigade security init --target .`"))

Expand Down
Loading
Loading