agent_governance_toolkit 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Agent Governance - Unified installer and runtime policy enforcement.
5
+
6
+ Install the full stack:
7
+ pip install agent-governance-toolkit[full]
8
+
9
+ Note: The package was previously published as ``ai-agent-compliance``.
10
+ That name is deprecated and will redirect here for 6 months.
11
+
12
+ Components:
13
+ - agent-os-kernel: Governance kernel with policy enforcement
14
+ - agentmesh-platform: Zero-trust agent communication (SSL for AI Agents)
15
+ - agentmesh-runtime: Runtime supervisor with execution rings
16
+ - agent-sre: Site reliability engineering for AI agents
17
+ - agentmesh-marketplace: Plugin lifecycle management
18
+ - agent-lightning: RL training governance
19
+ """
20
+
21
+ __version__ = "3.1.0"
22
+
23
+ # Re-export core components for convenience
24
+ try:
25
+ from agent_os import StatelessKernel, ExecutionContext # noqa: F401
26
+ except ImportError:
27
+ pass
28
+
29
+ try:
30
+ from agentmesh import TrustManager # noqa: F401
31
+ except ImportError:
32
+ pass
33
+
34
+ from agent_compliance.supply_chain import ( # noqa: F401
35
+ SupplyChainGuard,
36
+ SupplyChainFinding,
37
+ SupplyChainConfig,
38
+ )
39
+ from agent_compliance.prompt_defense import ( # noqa: F401
40
+ PromptDefenseEvaluator,
41
+ PromptDefenseConfig,
42
+ PromptDefenseFinding,
43
+ PromptDefenseReport,
44
+ )
@@ -0,0 +1,2 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
@@ -0,0 +1,448 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ AGT ΓÇö Unified CLI for the Agent Governance Toolkit.
5
+
6
+ Single entry point that namespaces all governance commands:
7
+ agt verify OWASP ASI compliance verification
8
+ agt integrity Module integrity checks
9
+ agt lint-policy Policy file linting
10
+ agt doctor Diagnose installation health
11
+ agt version Show installed package versions
12
+
13
+ Plugin subcommands from other AGT packages are discovered
14
+ via the ``agt.commands`` entry-point group.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import sys
20
+ from typing import Any, Dict, Optional
21
+
22
+ import click
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # Optional rich ΓÇö degrade gracefully if not installed
26
+ # ---------------------------------------------------------------------------
27
+
28
+ try:
29
+ from rich.console import Console as _RichConsole
30
+ from rich.table import Table as _RichTable
31
+ from rich import box as _rich_box
32
+
33
+ _console = _RichConsole()
34
+ _console_err = _RichConsole(stderr=True)
35
+ _HAS_RICH = True
36
+ except ImportError: # pragma: no cover
37
+ _HAS_RICH = False
38
+ _console = None # type: ignore[assignment]
39
+ _console_err = None # type: ignore[assignment]
40
+
41
+
42
+ def _print(msg: str, *, style: str = "", err: bool = False) -> None:
43
+ """Print with optional rich styling; falls back to plain print."""
44
+ if _HAS_RICH and style:
45
+ target = _console_err if err else _console
46
+ target.print(msg, style=style) # type: ignore[union-attr]
47
+ else:
48
+ print(msg, file=sys.stderr if err else sys.stdout)
49
+
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Helpers
53
+ # ---------------------------------------------------------------------------
54
+
55
+
56
+ def _get_package_version(package_name: str) -> Optional[str]:
57
+ """Return installed version via importlib.metadata, or None."""
58
+ try:
59
+ from importlib.metadata import version
60
+
61
+ return version(package_name)
62
+ except Exception:
63
+ return None
64
+
65
+
66
+ def _discover_plugins() -> Dict[str, click.Command]:
67
+ """Discover plugin commands from the ``agt.commands`` entry-point group."""
68
+ plugins: Dict[str, click.Command] = {}
69
+ try:
70
+ if sys.version_info >= (3, 10):
71
+ from importlib.metadata import entry_points
72
+
73
+ eps = entry_points(group="agt.commands")
74
+ else:
75
+ from importlib.metadata import entry_points
76
+
77
+ all_eps = entry_points()
78
+ eps = all_eps.get("agt.commands", [])
79
+
80
+ for ep in eps:
81
+ try:
82
+ obj = ep.load()
83
+ if isinstance(obj, click.Command):
84
+ plugins[ep.name] = obj
85
+ elif callable(obj):
86
+ # Adapter: callable that returns a click command
87
+ result = obj()
88
+ if isinstance(result, click.Command):
89
+ plugins[ep.name] = result
90
+ except Exception:
91
+ # Plugin failed to load ΓÇö silently skip; `doctor` will report it
92
+ pass
93
+ except Exception:
94
+ pass
95
+ return plugins
96
+
97
+
98
+ # ---------------------------------------------------------------------------
99
+ # Global context object
100
+ # ---------------------------------------------------------------------------
101
+
102
+
103
+ class AgtContext:
104
+ """Shared context passed to all subcommands via ``click.Context.obj``."""
105
+
106
+ def __init__(
107
+ self,
108
+ output_json: bool = False,
109
+ verbose: bool = False,
110
+ quiet: bool = False,
111
+ no_color: bool = False,
112
+ ):
113
+ self.output_json = output_json
114
+ self.verbose = verbose
115
+ self.quiet = quiet
116
+ self.no_color = no_color
117
+
118
+
119
+ # ---------------------------------------------------------------------------
120
+ # Root group
121
+ # ---------------------------------------------------------------------------
122
+
123
+
124
+ class AgtGroup(click.Group):
125
+ """Custom group that merges built-in and plugin commands."""
126
+
127
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
128
+ super().__init__(*args, **kwargs)
129
+ self._plugins_loaded = False
130
+
131
+ def _ensure_plugins(self) -> None:
132
+ if self._plugins_loaded:
133
+ return
134
+ self._plugins_loaded = True
135
+ for name, cmd in _discover_plugins().items():
136
+ if name not in self.commands:
137
+ self.add_command(cmd, name)
138
+
139
+ def list_commands(self, ctx: click.Context) -> list[str]:
140
+ self._ensure_plugins()
141
+ return sorted(super().list_commands(ctx))
142
+
143
+ def get_command(self, ctx: click.Context, cmd_name: str) -> Optional[click.Command]:
144
+ self._ensure_plugins()
145
+ return super().get_command(ctx, cmd_name)
146
+
147
+
148
+ @click.group(cls=AgtGroup)
149
+ @click.option("--json", "output_json", is_flag=True, default=False, help="Output in JSON format.")
150
+ @click.option("--verbose", "-v", is_flag=True, default=False, help="Increase output verbosity.")
151
+ @click.option("--quiet", "-q", is_flag=True, default=False, help="Suppress non-essential output.")
152
+ @click.option("--no-color", is_flag=True, default=False, help="Disable colored output.")
153
+ @click.version_option(
154
+ version=_get_package_version("agent_governance_toolkit") or "unknown",
155
+ prog_name="agt",
156
+ )
157
+ @click.pass_context
158
+ def cli(ctx: click.Context, output_json: bool, verbose: bool, quiet: bool, no_color: bool) -> None:
159
+ """
160
+ AGT ΓÇö Agent Governance Toolkit CLI.
161
+
162
+ Unified command-line interface for governing AI agents.
163
+
164
+ \b
165
+ Quick start:
166
+ agt verify Check OWASP ASI compliance
167
+ agt doctor Diagnose installation health
168
+ agt lint-policy ./dir Lint policy files
169
+ agt integrity Verify module integrity
170
+
171
+ \b
172
+ Plugin commands from installed AGT packages (mesh, sre, etc.)
173
+ are auto-discovered and appear below when installed.
174
+ """
175
+ ctx.ensure_object(dict)
176
+ ctx.obj = AgtContext(
177
+ output_json=output_json,
178
+ verbose=verbose,
179
+ quiet=quiet,
180
+ no_color=no_color,
181
+ )
182
+
183
+
184
+ # ---------------------------------------------------------------------------
185
+ # Built-in commands
186
+ # ---------------------------------------------------------------------------
187
+
188
+
189
+ @cli.command()
190
+ @click.option("--badge", is_flag=True, default=False, help="Output markdown badge only.")
191
+ @click.pass_obj
192
+ def verify(ctx_obj: AgtContext, badge: bool) -> None:
193
+ """Run OWASP ASI 2026 governance verification."""
194
+ try:
195
+ from agent_compliance.verify import GovernanceVerifier
196
+
197
+ verifier = GovernanceVerifier()
198
+ attestation = verifier.verify()
199
+
200
+ if ctx_obj.output_json:
201
+ click.echo(attestation.to_json())
202
+ elif badge:
203
+ click.echo(attestation.badge_markdown())
204
+ else:
205
+ click.echo(attestation.summary())
206
+
207
+ if not attestation.passed:
208
+ raise SystemExit(1)
209
+ except SystemExit:
210
+ raise
211
+ except Exception as e:
212
+ _handle_error(e, ctx_obj.output_json)
213
+ raise SystemExit(1)
214
+
215
+
216
+ @cli.command()
217
+ @click.option("--manifest", type=click.Path(), default=None, help="Path to integrity.json manifest.")
218
+ @click.option("--generate", type=click.Path(), default=None, metavar="OUTPUT_PATH", help="Generate manifest at path.")
219
+ @click.pass_obj
220
+ def integrity(ctx_obj: AgtContext, manifest: Optional[str], generate: Optional[str]) -> None:
221
+ """Verify or generate module integrity manifest."""
222
+ import json as json_mod
223
+
224
+ try:
225
+ if generate and manifest:
226
+ _print("Error: --manifest and --generate are mutually exclusive", style="red", err=True)
227
+ raise SystemExit(1)
228
+
229
+ from agent_compliance.integrity import IntegrityVerifier
230
+
231
+ if generate:
232
+ verifier = IntegrityVerifier()
233
+ result = verifier.generate_manifest(generate)
234
+ if ctx_obj.output_json:
235
+ click.echo(json_mod.dumps({"status": "ok", "path": generate, "files": len(result["files"]), "functions": len(result["functions"])}, indent=2))
236
+ else:
237
+ click.echo(f"Manifest written to {generate}")
238
+ click.echo(f" Files hashed: {len(result['files'])}")
239
+ click.echo(f" Functions hashed: {len(result['functions'])}")
240
+ return
241
+
242
+ import os
243
+
244
+ if manifest and not os.path.exists(manifest):
245
+ _print(f"Error: manifest file not found: {manifest}", style="red", err=True)
246
+ raise SystemExit(1)
247
+
248
+ verifier = IntegrityVerifier(manifest_path=manifest)
249
+ report = verifier.verify()
250
+
251
+ if ctx_obj.output_json:
252
+ click.echo(json_mod.dumps(report.to_dict(), indent=2))
253
+ else:
254
+ click.echo(report.summary())
255
+
256
+ if not report.passed:
257
+ raise SystemExit(1)
258
+ except SystemExit:
259
+ raise
260
+ except Exception as e:
261
+ _handle_error(e, ctx_obj.output_json)
262
+ raise SystemExit(1)
263
+
264
+
265
+ @cli.command("lint-policy")
266
+ @click.argument("path", type=click.Path(exists=True))
267
+ @click.option("--strict", is_flag=True, default=False, help="Treat warnings as errors.")
268
+ @click.pass_obj
269
+ def lint_policy(ctx_obj: AgtContext, path: str, strict: bool) -> None:
270
+ """Lint YAML policy files for common mistakes."""
271
+ import json as json_mod
272
+
273
+ try:
274
+ from agent_compliance.lint_policy import lint_path
275
+
276
+ result = lint_path(path)
277
+
278
+ if ctx_obj.output_json:
279
+ click.echo(json_mod.dumps(result.to_dict(), indent=2))
280
+ else:
281
+ for msg in result.messages:
282
+ click.echo(msg)
283
+ if result.messages:
284
+ click.echo()
285
+ click.echo(result.summary())
286
+
287
+ if strict and result.warnings:
288
+ raise SystemExit(1)
289
+ if not result.passed:
290
+ raise SystemExit(1)
291
+ except SystemExit:
292
+ raise
293
+ except Exception as e:
294
+ _handle_error(e, ctx_obj.output_json)
295
+ raise SystemExit(1)
296
+
297
+
298
+ # ---------------------------------------------------------------------------
299
+ # Doctor command
300
+ # ---------------------------------------------------------------------------
301
+
302
+ _AGT_PACKAGES = [
303
+ ("agent_governance_toolkit", "Agent Governance Toolkit", "Meta-package & compliance CLI"),
304
+ ("agent_os_kernel", "Agent OS Kernel", "Policy engine & framework integrations"),
305
+ ("agentmesh_platform", "AgentMesh Platform", "Zero-trust identity & trust scoring"),
306
+ ("agentmesh_runtime", "AgentMesh Runtime", "Execution supervisor & privilege rings"),
307
+ ("agent_sre", "Agent SRE", "SLOs, error budgets & chaos testing"),
308
+ ("agentmesh_marketplace", "AgentMesh Marketplace", "Plugin lifecycle management"),
309
+ ("agentmesh_lightning", "AgentMesh Lightning", "RL training governance"),
310
+ ("agent_hypervisor", "Agent Hypervisor", "Session management & kill switch"),
311
+ ]
312
+
313
+
314
+ @cli.command()
315
+ @click.pass_obj
316
+ def doctor(ctx_obj: AgtContext) -> None:
317
+ """Diagnose AGT installation health.
318
+
319
+ Checks installed packages, versions, Python compatibility,
320
+ and plugin registration status.
321
+ """
322
+ import json as json_mod
323
+ import platform
324
+
325
+ py_version = platform.python_version()
326
+ results: list[Dict[str, Any]] = []
327
+
328
+ for pkg_name, display_name, description in _AGT_PACKAGES:
329
+ ver = _get_package_version(pkg_name)
330
+ results.append({
331
+ "package": pkg_name,
332
+ "name": display_name,
333
+ "description": description,
334
+ "installed": ver is not None,
335
+ "version": ver,
336
+ })
337
+
338
+ # Check for plugin registrations
339
+ plugins = _discover_plugins()
340
+
341
+ # Check config files
342
+ from pathlib import Path
343
+
344
+ config_locations = [
345
+ Path.cwd() / "agentmesh.yaml",
346
+ Path.cwd() / "policies",
347
+ Path.cwd() / "integrity.json",
348
+ ]
349
+ config_found = {str(p): p.exists() for p in config_locations}
350
+
351
+ if ctx_obj.output_json:
352
+ report = {
353
+ "python_version": py_version,
354
+ "packages": results,
355
+ "plugins": list(plugins.keys()),
356
+ "config_files": config_found,
357
+ }
358
+ click.echo(json_mod.dumps(report, indent=2))
359
+ return
360
+
361
+ # Rich table output
362
+ _print(f"\n🩺 AGT Doctor — Python {py_version}", style="bold blue")
363
+ _print("")
364
+
365
+ installed_count = sum(1 for r in results if r["installed"])
366
+ total_count = len(results)
367
+
368
+ if _HAS_RICH and _console is not None and not ctx_obj.no_color:
369
+ table = _RichTable(
370
+ title="Installed Packages",
371
+ box=_rich_box.ROUNDED,
372
+ show_lines=False,
373
+ )
374
+ table.add_column("Package", style="cyan", no_wrap=True)
375
+ table.add_column("Version", style="green")
376
+ table.add_column("Status")
377
+ table.add_column("Description", style="dim")
378
+
379
+ for r in results:
380
+ status = "[green]Γ£ô installed[/green]" if r["installed"] else "[dim]┬╖ not installed[/dim]"
381
+ ver = r["version"] or "ΓÇö"
382
+ table.add_row(r["package"], ver, status, r["description"])
383
+
384
+ _console.print(table)
385
+ else:
386
+ click.echo("Installed Packages:")
387
+ click.echo("-" * 70)
388
+ for r in results:
389
+ status = "Γ£ô" if r["installed"] else "┬╖"
390
+ ver = r["version"] or "ΓÇö"
391
+ click.echo(f" {status} {r['package']:30s} {ver:12s} {r['description']}")
392
+
393
+ _print(f"\n {installed_count}/{total_count} packages installed", style="bold")
394
+
395
+ # Plugins
396
+ if plugins:
397
+ _print(f"\n Plugin commands: {', '.join(sorted(plugins.keys()))}", style="green")
398
+ else:
399
+ _print("\n No plugin commands registered (install AGT packages with [full] extras)", style="dim")
400
+
401
+ # Config files
402
+ _print("\n Config files:", style="bold")
403
+ for path_str, exists in config_found.items():
404
+ icon = "Γ£ô" if exists else "┬╖"
405
+ _print(f" {icon} {path_str}")
406
+
407
+ _print("")
408
+
409
+
410
+ # ---------------------------------------------------------------------------
411
+ # Error handling
412
+ # ---------------------------------------------------------------------------
413
+
414
+
415
+ def _handle_error(e: Exception, output_json: bool = False) -> None:
416
+ """Centralized error handler."""
417
+ import json as json_mod
418
+
419
+ is_known = isinstance(
420
+ e, (IOError, ValueError, KeyError, PermissionError, FileNotFoundError)
421
+ )
422
+
423
+ if output_json:
424
+ err_type = "ValidationError" if is_known else "InternalError"
425
+ err_msg = str(e) if is_known else "An internal error occurred"
426
+ click.echo(json_mod.dumps({"status": "error", "message": err_msg, "type": err_type}, indent=2))
427
+ else:
428
+ if is_known:
429
+ _print(f"Error: {e}", style="red", err=True)
430
+ else:
431
+ _print("Error: An internal error occurred", style="red", err=True)
432
+ import os
433
+ if os.environ.get("AGENTOS_DEBUG"):
434
+ _print(f" {e}", style="dim", err=True)
435
+
436
+
437
+ # ---------------------------------------------------------------------------
438
+ # Entry point
439
+ # ---------------------------------------------------------------------------
440
+
441
+
442
+ def main() -> None:
443
+ """Console-script entry point."""
444
+ cli(standalone_mode=True)
445
+
446
+
447
+ if __name__ == "__main__":
448
+ main()
@@ -0,0 +1,200 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ #!/usr/bin/env python3
4
+ # Copyright (c) Microsoft Corporation.
5
+ # Licensed under the MIT License.
6
+ """
7
+ Agent Governance Toolkit CLI.
8
+
9
+ Commands:
10
+ verify Run OWASP ASI 2026 governance verification
11
+ integrity Verify or generate module integrity manifest
12
+ lint-policy Lint YAML policy files for common mistakes
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ from typing import Optional
19
+ import os
20
+ import sys
21
+ import json
22
+
23
+
24
+ def handle_error(e: Exception, output_json: bool = False, custom_msg: Optional[str] = None):
25
+ """Centralized error handler for compliance CLI."""
26
+ is_known = isinstance(e, (IOError, ValueError, KeyError, PermissionError, FileNotFoundError))
27
+
28
+ if custom_msg:
29
+ err_msg = custom_msg
30
+ elif is_known:
31
+ err_msg = "A validation or file access error occurred."
32
+ else:
33
+ err_msg = "A governance processing error occurred."
34
+
35
+ if output_json:
36
+ print(json.dumps({"status": "fail" if not is_known else "error", "message": err_msg, "type": "ValidationError" if is_known else "InternalError"}, indent=2))
37
+ else:
38
+ print(f"Error: {err_msg}", file=sys.stderr)
39
+
40
+
41
+ def cmd_verify(args: argparse.Namespace) -> int:
42
+ """Run governance verification."""
43
+ from agent_compliance.verify import GovernanceVerifier
44
+
45
+ try:
46
+ verifier = GovernanceVerifier()
47
+ attestation = verifier.verify()
48
+
49
+ if args.json:
50
+ print(attestation.to_json())
51
+ elif args.badge:
52
+ print(attestation.badge_markdown())
53
+ else:
54
+ print(attestation.summary())
55
+
56
+ return 0 if attestation.passed else 1
57
+ except Exception as e:
58
+ handle_error(e, args.json)
59
+ return 1
60
+
61
+
62
+ def cmd_integrity(args: argparse.Namespace) -> int:
63
+ """Run integrity verification or generate manifest."""
64
+ from agent_compliance.integrity import IntegrityVerifier
65
+
66
+ try:
67
+ if args.generate and args.manifest:
68
+ print(
69
+ "Error: --manifest and --generate are mutually exclusive",
70
+ file=sys.stderr,
71
+ )
72
+ return 1
73
+
74
+ if args.generate:
75
+ verifier = IntegrityVerifier()
76
+ manifest = verifier.generate_manifest(args.generate)
77
+ print(f"Manifest written to {args.generate}")
78
+ print(f" Files hashed: {len(manifest['files'])}")
79
+ print(f" Functions hashed: {len(manifest['functions'])}")
80
+ return 0
81
+
82
+ if args.manifest and not os.path.exists(args.manifest):
83
+ print(
84
+ f"Error: manifest file not found: {args.manifest}",
85
+ file=sys.stderr,
86
+ )
87
+ return 1
88
+
89
+ verifier = IntegrityVerifier(manifest_path=args.manifest)
90
+ report = verifier.verify()
91
+
92
+ if args.json:
93
+ import json
94
+
95
+ print(json.dumps(report.to_dict(), indent=2))
96
+ else:
97
+ print(report.summary())
98
+
99
+ return 0 if report.passed else 1
100
+ except Exception as e:
101
+ handle_error(e, args.json)
102
+ return 1
103
+
104
+
105
+ def cmd_lint_policy(args: argparse.Namespace) -> int:
106
+ """Lint YAML policy files for common mistakes."""
107
+ from agent_compliance.lint_policy import lint_path
108
+
109
+ try:
110
+ result = lint_path(args.path)
111
+
112
+ if args.json:
113
+ import json
114
+
115
+ print(json.dumps(result.to_dict(), indent=2))
116
+ else:
117
+ for msg in result.messages:
118
+ print(msg)
119
+ if result.messages:
120
+ print()
121
+ print(result.summary())
122
+
123
+ if args.strict and result.warnings:
124
+ return 1
125
+ return 0 if result.passed else 1
126
+ except Exception as e:
127
+ handle_error(e, args.json)
128
+ return 1
129
+
130
+
131
+ def main() -> int:
132
+ """CLI entry point."""
133
+ parser = argparse.ArgumentParser(
134
+ prog="agent-compliance",
135
+ description="Agent Governance Toolkit — Compliance & Verification CLI",
136
+ )
137
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
138
+
139
+ # verify command
140
+ verify_parser = subparsers.add_parser(
141
+ "verify",
142
+ help="Run OWASP ASI 2026 governance verification",
143
+ )
144
+ verify_parser.add_argument(
145
+ "--json", action="store_true", help="Output JSON attestation"
146
+ )
147
+ verify_parser.add_argument(
148
+ "--badge", action="store_true", help="Output markdown badge only"
149
+ )
150
+
151
+ # integrity command
152
+ integrity_parser = subparsers.add_parser(
153
+ "integrity",
154
+ help="Verify or generate module integrity manifest",
155
+ )
156
+ integrity_parser.add_argument(
157
+ "--manifest", type=str, help="Path to integrity.json manifest to verify against"
158
+ )
159
+ integrity_parser.add_argument(
160
+ "--generate",
161
+ type=str,
162
+ metavar="OUTPUT_PATH",
163
+ help="Generate integrity manifest at the given path",
164
+ )
165
+ integrity_parser.add_argument(
166
+ "--json", action="store_true", help="Output JSON report"
167
+ )
168
+
169
+ # lint-policy command
170
+ lint_parser = subparsers.add_parser(
171
+ "lint-policy",
172
+ help="Lint YAML policy files for common mistakes",
173
+ )
174
+ lint_parser.add_argument(
175
+ "path", type=str, help="Path to a YAML policy file or directory"
176
+ )
177
+ lint_parser.add_argument(
178
+ "--json", action="store_true", help="Output JSON report"
179
+ )
180
+ lint_parser.add_argument(
181
+ "--strict",
182
+ action="store_true",
183
+ help="Treat warnings as errors (exit 1 if any warnings)",
184
+ )
185
+
186
+ args = parser.parse_args()
187
+
188
+ if args.command == "verify":
189
+ return cmd_verify(args)
190
+ elif args.command == "integrity":
191
+ return cmd_integrity(args)
192
+ elif args.command == "lint-policy":
193
+ return cmd_lint_policy(args)
194
+ else:
195
+ parser.print_help()
196
+ return 0
197
+
198
+
199
+ if __name__ == "__main__":
200
+ sys.exit(main())