1515
1616from agentsniff .baseline import NetworkBaseline
1717from agentsniff .config import ScanConfig , default_config_yaml
18+ from agentsniff .signatures import get_signature_data , VERIFIED , INVALID , UNVERIFIED
1819from agentsniff .notifier import should_alert , send_alerts
1920from agentsniff .scanner import run_scan
2021from 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+
6799def 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