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 MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include policies/gdpr.yaml
include policies/hipaa.yaml
include policies/pci_dss.yaml
12 changes: 12 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[build-system]
requires = ["hatchling>=1.25.0"]
build-backend = "hatchling.build"

[project]
name = "shadowaudit"
version = "0.1.0"
Expand All @@ -6,8 +10,16 @@ requires-python = ">=3.10"
dependencies = [
"PyYAML>=6.0",
"detect-secrets>=1.5.0",
]

[project.optional-dependencies]
ner = [
"chromadb>=0.5.0",
"sentence-transformers>=3.0.0",
"spacy-transformers>=1.3.5",
]
siem = [
"datadog-api-client>=2.23.0",
]

[project.scripts]
Expand Down
12 changes: 12 additions & 0 deletions shadowaudit/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import argparse
import json
from dataclasses import asdict

from shadowaudit.core.policy import PolicyEngine
from shadowaudit.core.scanner import PIIScanner
from shadowaudit.reports.gdpr_report import generate_gdpr_report


Expand All @@ -28,6 +30,9 @@ def _build_parser() -> argparse.ArgumentParser:
proxy_parser.add_argument("--port", type=int, default=8080, help="Local listening port")
proxy_parser.add_argument("--target", default="https://api.openai.com", help="Upstream API base URL")

scan_parser = subparsers.add_parser("scan", help="Scan input text for PII entities")
scan_parser.add_argument("text", nargs="+", help="Text to scan")

return parser


Expand Down Expand Up @@ -56,6 +61,13 @@ def main() -> int:
run_proxy_server(port=args.port, target=args.target)
return 0

if args.command == "scan":
scanner = PIIScanner(fast_mode=True)
result = scanner.scan(" ".join(args.text))
payload = result.model_dump() if hasattr(result, "model_dump") else asdict(result)
print(json.dumps(payload, indent=2, ensure_ascii=False))
return 0

parser.print_help()
return 2

Expand Down
23 changes: 23 additions & 0 deletions tests/test_cli_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""CLI tests for scan command."""

from __future__ import annotations

import json
import sys

from shadowaudit.cli import main


def test_scan_command_outputs_detected_entities(capsys) -> None:
old_argv = sys.argv
sys.argv = ["shadowaudit", "scan", "Email", "alice@example.com"]
try:
code = main()
finally:
sys.argv = old_argv

captured = capsys.readouterr()
payload = json.loads(captured.out)

assert code == 0
assert "EMAIL" in payload["detected_entities"]
Loading