Skip to content

Commit 4b3e0d0

Browse files
committed
feat(cli): standardize and harden secure JSON output across all ecosystem tools
1 parent c79b764 commit 4b3e0d0

File tree

3 files changed

+91
-42
lines changed
  • packages
    • agent-compliance/src/agent_compliance/cli
    • agent-os/modules
      • iatp/iatp
      • mcp-kernel-server/src/mcp_kernel_server

3 files changed

+91
-42
lines changed

packages/agent-compliance/src/agent_compliance/cli/main.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,25 @@ def cmd_verify(args: argparse.Namespace) -> int:
2121
"""Run governance verification."""
2222
from agent_compliance.verify import GovernanceVerifier
2323

24-
verifier = GovernanceVerifier()
25-
attestation = verifier.verify()
24+
try:
25+
verifier = GovernanceVerifier()
26+
attestation = verifier.verify()
2627

27-
if args.json:
28-
print(attestation.to_json())
29-
elif args.badge:
30-
print(attestation.badge_markdown())
31-
else:
32-
print(attestation.summary())
28+
if args.json:
29+
print(attestation.to_json())
30+
elif args.badge:
31+
print(attestation.badge_markdown())
32+
else:
33+
print(attestation.summary())
3334

34-
return 0 if attestation.passed else 1
35+
return 0 if attestation.passed else 1
36+
except Exception as e:
37+
if args.json:
38+
import json
39+
print(json.dumps({"status": "fail", "error": "Governance verification failed", "type": "InternalError"}, indent=2))
40+
else:
41+
print(f"Error: {e}", file=sys.stderr)
42+
return 1
3543

3644

3745
def cmd_integrity(args: argparse.Namespace) -> int:
@@ -73,7 +81,11 @@ def cmd_integrity(args: argparse.Namespace) -> int:
7381

7482
return 0 if report.passed else 1
7583
except Exception as e:
76-
print(f"Error: {e}", file=sys.stderr)
84+
if args.json:
85+
import json
86+
print(json.dumps({"status": "error", "message": "Integrity manifest processing failed", "type": "InternalError"}, indent=2))
87+
else:
88+
print(f"Error: {e}", file=sys.stderr)
7789
return 1
7890

7991

@@ -99,7 +111,11 @@ def cmd_lint_policy(args: argparse.Namespace) -> int:
99111
return 1
100112
return 0 if result.passed else 1
101113
except Exception as e:
102-
print(f"Error: {e}", file=sys.stderr)
114+
if args.json:
115+
import json
116+
print(json.dumps({"status": "error", "message": "Policy linting failed", "type": "InternalError"}, indent=2))
117+
else:
118+
print(f"Error: {e}", file=sys.stderr)
103119
return 1
104120

105121

packages/agent-os/modules/iatp/iatp/cli.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,20 @@ def verify(manifest_path: str, verbose: bool, output_json: bool):
5757
# Validate using Pydantic model
5858
try:
5959
manifest = CapabilityManifest(**manifest_data)
60-
except Exception as e:
60+
except (ValueError, KeyError, PermissionError) as e:
6161
if output_json:
62-
print(json.dumps({"status": "fail", "error": f"Schema validation failed: {str(e)}"}, indent=2))
62+
print(json.dumps({"status": "fail", "error": f"Manifest validation failed: {str(e)}", "type": e.__class__.__name__}, indent=2))
6363
else:
64-
click.echo("\nSchema validation failed:", err=True)
64+
click.echo("\nValidation failed:", err=True)
6565
click.echo(f" {str(e)}", err=True)
6666
sys.exit(1)
67+
except Exception:
68+
err_msg = "An internal error occurred while validating the manifest."
69+
if output_json:
70+
print(json.dumps({"status": "fail", "error": err_msg, "type": "InternalError"}, indent=2))
71+
else:
72+
click.echo(f"\n❌ Error: {err_msg}", err=True)
73+
sys.exit(1)
6774

6875
# Perform logical contradiction checks
6976
errors = []
@@ -152,10 +159,18 @@ def verify(manifest_path: str, verbose: bool, output_json: bool):
152159
click.echo(f"❌ Invalid JSON: {str(e)}", err=True)
153160
sys.exit(1)
154161
except Exception as e:
162+
# Sanitize exception message to avoid leaking internal details
163+
is_known = isinstance(e, (FileNotFoundError, json.JSONDecodeError, ValueError, PermissionError))
164+
error_msg = str(e) if is_known else "An internal error occurred during verification."
165+
155166
if output_json:
156-
print(json.dumps({"status": "fail", "error": f"Validation error: {str(e)}"}, indent=2))
167+
print(json.dumps({
168+
"status": "fail",
169+
"error": error_msg,
170+
"type": e.__class__.__name__ if is_known else "InternalError"
171+
}, indent=2))
157172
else:
158-
click.echo(f"❌ Validation error: {str(e)}", err=True)
173+
click.echo(f"❌ Error: {error_msg}", err=True)
159174
sys.exit(1)
160175

161176

@@ -261,11 +276,19 @@ def scan(agent_url: str, timeout: int, verbose: bool, output_json: bool):
261276
click.echo(f" SLA Latency: {manifest.capabilities.sla_latency}")
262277

263278
except Exception as e:
279+
# Sanitize error message based on exception type to prevent info leakage
280+
is_known = isinstance(e, (httpx.RequestError, json.JSONDecodeError, ValueError, PermissionError))
281+
err_msg = str(e) if is_known else "An internal error occurred during agent scan"
282+
264283
if output_json:
265-
print(json.dumps({"status": "fail", "error": str(e)}, indent=2))
284+
print(json.dumps({
285+
"status": "fail",
286+
"error": err_msg,
287+
"type": e.__class__.__name__ if is_known else "InternalError"
288+
}, indent=2))
266289
else:
267-
click.echo(f"\n❌ Scan error: {str(e)}", err=True)
268-
if verbose:
290+
click.echo(f"\n❌ Scan error: {err_msg}", err=True)
291+
if verbose and not is_known:
269292
import traceback
270293
click.echo(traceback.format_exc(), err=True)
271294
sys.exit(1)

packages/agent-os/modules/mcp-kernel-server/src/mcp_kernel_server/cli.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -230,32 +230,42 @@ def main():
230230
server = KernelMCPServer(config)
231231

232232
# Run
233-
if args.stdio:
234-
logger.info("Starting MCP Kernel Server with stdio transport")
235-
logger.info(f"Policy mode: {args.policy_mode}")
236-
logger.info("Tools: cmvk_verify, kernel_execute, iatp_sign, iatp_verify, iatp_reputation")
237-
logger.info("Prompts: governed_agent, verify_claim, safe_execution")
238-
239-
try:
233+
try:
234+
if args.stdio:
235+
logger.info("Starting MCP Kernel Server with stdio transport")
236+
logger.info(f"Policy mode: {args.policy_mode}")
237+
logger.info("Tools: cmvk_verify, kernel_execute, iatp_sign, iatp_verify, iatp_reputation")
238+
logger.info("Prompts: governed_agent, verify_claim, safe_execution")
239+
240240
asyncio.run(server.run_stdio())
241-
except KeyboardInterrupt:
242-
logger.info("Shutting down...")
243-
except Exception as e:
244-
logger.exception("Server error")
245-
return 1
246-
else:
247-
# HTTP transport
248-
logger.info(f"Starting MCP Kernel Server on http://{args.host}:{args.port}")
249-
logger.info(f"Policy mode: {args.policy_mode}")
250-
logger.info("Tools: cmvk_verify, kernel_execute, iatp_sign, iatp_verify, iatp_reputation")
251-
logger.info("Prompts: governed_agent, verify_claim, safe_execution")
252-
logger.info("Press Ctrl+C to stop")
253-
254-
try:
241+
else:
242+
# HTTP transport
243+
logger.info(f"Starting MCP Kernel Server on http://{args.host}:{args.port}")
244+
logger.info(f"Policy mode: {args.policy_mode}")
245+
logger.info("Tools: cmvk_verify, kernel_execute, iatp_sign, iatp_verify, iatp_reputation")
246+
logger.info("Prompts: governed_agent, verify_claim, safe_execution")
247+
logger.info("Press Ctrl+C to stop")
248+
255249
asyncio.run(server.start())
256250
asyncio.get_event_loop().run_forever()
257-
except KeyboardInterrupt:
258-
logger.info("Shutting down...")
251+
252+
except KeyboardInterrupt:
253+
logger.info("Shutting down...")
254+
except Exception as e:
255+
# Sanitize startup errors for JSON mode to prevent info leakage
256+
is_known = isinstance(e, (ValueError, PermissionError, OSError))
257+
msg = str(e) if is_known else "An internal error occurred during server startup"
258+
259+
if getattr(args, "json", False):
260+
import json
261+
print(json.dumps({
262+
"status": "error",
263+
"message": msg,
264+
"type": e.__class__.__name__ if is_known else "InternalError"
265+
}, indent=2))
266+
else:
267+
logger.exception(f"Server error: {msg}")
268+
return 1
259269

260270
return 0
261271

0 commit comments

Comments
 (0)