Skip to content

Commit ad427b1

Browse files
authored
Merge pull request #48 from escoffier-labs/feat/security-enrichment
feat: add security enrichment
2 parents 1fea146 + fd4558a commit ad427b1

9 files changed

Lines changed: 901 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5656
- Built-in `security` station and `brigade security scan` for read-only agent workspace security checks.
5757
- 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.
5858
- Supply-chain security checks for package scripts, GitHub Actions permissions and action refs, Python URL dependencies, and legacy install hooks.
59+
- `brigade security enrich` for explicit post-scan enrichment artifacts, with an offline local provider and opt-in MISP provider config.
5960
- `brigade security scan --import-findings` to route security findings into the local work import inbox for review.
6061
- `brigade security init` to write gitignored local defaults to `.brigade/security.toml`.
6162
- `brigade security fix` to create the local security artifact directory and refresh the managed `.gitignore` block.

README.md

Lines changed: 232 additions & 23 deletions
Large diffs are not rendered by default.

ROADMAP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Baseline coverage targets:
5454
- 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.
5555
- 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.
5656
- Support CLI use, GitHub Action use, and local evidence packs.
57-
- Add optional threat-intel enrichment, including MISP as an opt-in provider, without changing the default no-network local scan behavior.
57+
- 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.
5858

5959
Brigade-specific additions:
6060

@@ -66,7 +66,7 @@ Brigade-specific additions:
6666
- Produce Memory Handoffs for durable security findings while keeping raw secret evidence redacted.
6767
- Add policy packs for personal dogfooding, public-repo release checks, CI gates, and strict enterprise workspaces. Status: started with `personal`, `public-repo`, and `strict`.
6868
- 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.
69-
- 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.
69+
- 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.
7070
- 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.
7171

7272
## Later Phase: Issue And TDD Work Loop

src/brigade/cli.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,23 @@ def _build_parser() -> argparse.ArgumentParser:
398398
p_security_review.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to review.")
399399
p_security_review.add_argument("--output-dir", type=Path, default=None, help="Security evidence bundle directory.")
400400
p_security_review.add_argument("--json", action="store_true", help="Print machine-readable JSON.")
401+
p_security_enrich = security_sub.add_parser("enrich", help="Enrich an existing security report.")
402+
p_security_enrich.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to enrich.")
403+
p_security_enrich.add_argument(
404+
"--output-dir",
405+
type=Path,
406+
default=None,
407+
help="Security evidence bundle directory. Defaults to .brigade/security/latest.",
408+
)
409+
p_security_enrich.add_argument(
410+
"--report",
411+
dest="report_path",
412+
type=Path,
413+
default=None,
414+
help="Explicit security-report.json path. Defaults to --output-dir/security-report.json.",
415+
)
416+
p_security_enrich.add_argument("--provider", choices=["local", "misp"], default=None, help="Override configured provider.")
417+
p_security_enrich.add_argument("--json", action="store_true", help="Print machine-readable JSON.")
401418
p_security_suppress = security_sub.add_parser("suppress", help="Suppress a reviewed security finding fingerprint.")
402419
p_security_suppress.add_argument("fingerprint", help="Finding fingerprint to suppress.")
403420
p_security_suppress.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
@@ -809,6 +826,14 @@ def main(argv=None) -> int:
809826
return security_cmd.fix(target=args.target, dry_run=args.dry_run)
810827
if args.security_command == "review":
811828
return security_cmd.review(target=args.target, output_dir=args.output_dir, json_output=args.json)
829+
if args.security_command == "enrich":
830+
return security_cmd.enrich(
831+
target=args.target,
832+
output_dir=args.output_dir,
833+
report_path=args.report_path,
834+
provider=args.provider,
835+
json_output=args.json,
836+
)
812837
if args.security_command == "suppress":
813838
return security_cmd.suppress(target=args.target, fingerprint=args.fingerprint, reason=args.reason)
814839
if args.security_command == "unsuppress":

src/brigade/doctor.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ def security_station_checks(ctx: DoctorContext) -> List[CheckResult]:
9696
results.append((FAIL, "security: config", f"invalid {config}: {exc}"))
9797
else:
9898
results.append((OK, "security: config", f"{config} (policy={loaded.policy if loaded else 'personal'})"))
99+
enrichment = security_cmd.enrichment_health(ctx.target)
100+
if enrichment.get("configured"):
101+
results.append((OK, "security: enrichment", f"{enrichment.get('provider')} ({enrichment.get('status')})"))
102+
else:
103+
results.append((WARN, "security: enrichment", str(enrichment.get("status"))))
99104
else:
100105
results.append((WARN, "security: config", f"missing at {config}; run `brigade security init --target .`"))
101106

0 commit comments

Comments
 (0)