Skip to content

Commit 4f45ea5

Browse files
authored
Merge pull request #2 from ThirdKeyAI/feature/externalize-signatures
Feature/externalize signatures
2 parents d5b68c6 + 8036963 commit 4f45ea5

13 files changed

Lines changed: 1107 additions & 479 deletions

agentsniff/cli.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from agentsniff.baseline import NetworkBaseline
1717
from agentsniff.config import ScanConfig, default_config_yaml
18+
from agentsniff.signatures import get_signature_data, VERIFIED, INVALID, UNVERIFIED
1819
from agentsniff.notifier import should_alert, send_alerts
1920
from agentsniff.scanner import run_scan
2021
from agentsniff.storage import ScanStore
@@ -64,6 +65,37 @@ class Colors:
6465
}
6566

6667

68+
def _print_signature_status():
69+
"""Print signature verification status summary."""
70+
sigs = get_signature_data()
71+
status = sigs.verification_status
72+
73+
invalid = [k for k, v in status.items() if v == INVALID]
74+
verified = [k for k, v in status.items() if v == VERIFIED]
75+
unverified = [k for k, v in status.items() if v == UNVERIFIED]
76+
77+
if invalid:
78+
print(
79+
f" {Colors.BG_RED}{Colors.WHITE} WARNING {Colors.RESET} "
80+
f"{Colors.RED}Invalid signatures: {', '.join(invalid)}{Colors.RESET}"
81+
)
82+
print(
83+
f" {Colors.RED}Detection signatures may have been tampered with!{Colors.RESET}"
84+
)
85+
print(
86+
f" {Colors.DIM}Run 'agentsniff update-signatures' to restore.{Colors.RESET}"
87+
)
88+
print()
89+
elif verified:
90+
count = len(verified)
91+
total = len(status)
92+
print(
93+
f" {Colors.GREEN}Signatures verified ({count}/{total}){Colors.RESET}"
94+
)
95+
print()
96+
# Unverified (no .sig files) — silent, not an error
97+
98+
6799
def setup_logging(verbose: bool = False, quiet: bool = False, log_file: str = ""):
68100
level = logging.DEBUG if verbose else (logging.WARNING if quiet else logging.INFO)
69101
handler = logging.StreamHandler()
@@ -327,6 +359,20 @@ def build_parser() -> argparse.ArgumentParser:
327359
# ── init-config command ──────────────────────────────────────────
328360
subparsers.add_parser("init-config", help="Generate default configuration file")
329361

362+
# ── update-signatures command ─────────────────────────────────────
363+
update_parser = subparsers.add_parser(
364+
"update-signatures",
365+
help="Update detection signatures from GitHub",
366+
)
367+
update_parser.add_argument(
368+
"--verify", action="store_true", default=True,
369+
help="Verify SchemaPin signatures after update (default: true)",
370+
)
371+
update_parser.add_argument(
372+
"--no-verify", action="store_true", default=False,
373+
help="Skip signature verification",
374+
)
375+
330376
return parser
331377

332378

@@ -345,6 +391,12 @@ def main():
345391
print(f"Generated default config: {config_path}")
346392
sys.exit(0)
347393

394+
if args.command == "update-signatures":
395+
from agentsniff.signatures.updater import update_signatures
396+
verify = not args.no_verify
397+
success = update_signatures(verify=verify)
398+
sys.exit(0 if success else 1)
399+
348400
if args.command == "serve":
349401
setup_logging(verbose=args.verbose, log_file=args.log_file)
350402
from agentsniff.server import start_server
@@ -361,6 +413,7 @@ def main():
361413

362414
if not args.quiet:
363415
print(BANNER)
416+
_print_signature_status()
364417

365418
# Build config
366419
if args.config:

0 commit comments

Comments
 (0)