Skip to content

feat(security): add security diff engine - #23

Open
shuvonsec wants to merge 3 commits into
mainfrom
feat/axguard-security-diff
Open

shuvonsec wants to merge 3 commits into
mainfrom
feat/axguard-security-diff

Conversation

@shuvonsec

@shuvonsec shuvonsec commented Sep 16, 2026

Copy link
Copy Markdown
Member

Summary

  • Add shared Security Diff engine (engines/security_diff) that orchestrates Application Model, Data Flow, Attack Graph, Twin, Memory, and Predictive — not a new scanner
  • Wire axguard diff CLI, MCP tool axguard_security_diff, API /security-diff, GitHub PR summary consumption, and Pre-Ship integration
  • Document baselines, CI --fail-on, JSON/HTML output; add fixtures + tests (including hard negatives and authz regression)

Test plan

  • pytest tests/test_security_diff.py tests/test_preship.py
  • axguard diff HEAD~1 in a git repo
  • axguard diff --json / --verbose / --fail-on high
  • axguard diff baseline save then axguard diff baseline
  • MCP: tool listed via axguard mcp tools / catalog includes axguard_security_diff
  • Confirm GPG re-sign if required (git commit --amend -S --no-edit after unlocking pinentry)

if not text:
return None
p = Path(text)
if p.exists():
return None
p = Path(text)
if p.exists():
return p.resolve()
if value in {".", "./"}:
return False
p = Path(value)
if p.exists():
notes: list[str] = []

# --- resolve baseline -------------------------------------------------
if base_path is not None and base_path.is_dir():


def _load_json(path: Path) -> dict[str, Any] | None:
if not path.is_file():
if not path.is_file():
return None
try:
data = json.loads(path.read_text(encoding="utf-8"))
Soft-imports existing engines. Never invents missing analysis.
"""
opts = dict(options or {})
root = Path(target).resolve()
name: str = "default",
) -> dict[str, Any] | None:
path = resolve_baseline_dir(project_root) / f"{_safe_name(name)}.json"
if not path.is_file():
if not path.is_file():
return None
try:
data = json.loads(path.read_text(encoding="utf-8"))
result.setdefault("resolved_findings", [])
result.setdefault("security_posture_delta", result.get("security_impact") or {})
result["github_summary"] = format_github_pr_summary(result)
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants