SafeAI-Static-Analyzer 2.1.1__tar.gz → 2.2.0__tar.gz

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.
Files changed (213) hide show
  1. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/PKG-INFO +5 -3
  2. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/README.md +4 -2
  3. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/SafeAI_Static_Analyzer.egg-info/PKG-INFO +5 -3
  4. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/SafeAI_Static_Analyzer.egg-info/SOURCES.txt +9 -0
  5. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/escalation.py +3 -0
  6. safeai_static_analyzer-2.2.0/safeai/analysis/escalation_remediation.py +354 -0
  7. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/cmd/cli.py +17 -0
  8. safeai_static_analyzer-2.2.0/safeai/cmd/manifest_cli.py +44 -0
  9. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/cmd/registry_cli.py +2 -1
  10. safeai_static_analyzer-2.2.0/safeai/kya/contract.py +190 -0
  11. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/exporter.py +5 -1
  12. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/importer.py +13 -2
  13. safeai_static_analyzer-2.2.0/safeai/kya/integrity.py +131 -0
  14. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/manifest.py +28 -1
  15. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/html.py +28 -1
  16. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/pr_comment.py +22 -1
  17. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/terminal.py +12 -0
  18. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/scorecard.py +29 -0
  19. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/version.py +1 -1
  20. safeai_static_analyzer-2.2.0/tests/test_benchmarks.py +91 -0
  21. safeai_static_analyzer-2.2.0/tests/test_dco.py +48 -0
  22. safeai_static_analyzer-2.2.0/tests/test_escalation_remediation.py +275 -0
  23. safeai_static_analyzer-2.2.0/tests/test_manifest_contract.py +156 -0
  24. safeai_static_analyzer-2.2.0/tests/test_manifest_integrity.py +139 -0
  25. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/LICENSE +0 -0
  26. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/SafeAI_Static_Analyzer.egg-info/dependency_links.txt +0 -0
  27. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/SafeAI_Static_Analyzer.egg-info/entry_points.txt +0 -0
  28. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/SafeAI_Static_Analyzer.egg-info/requires.txt +0 -0
  29. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/SafeAI_Static_Analyzer.egg-info/top_level.txt +0 -0
  30. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/pyproject.toml +0 -0
  31. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/__init__.py +0 -0
  32. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/__main__.py +0 -0
  33. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/__init__.py +0 -0
  34. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/aggregation.py +0 -0
  35. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/capabilities.py +0 -0
  36. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/capability_diff.py +0 -0
  37. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/component_diff.py +0 -0
  38. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/component_graph.py +0 -0
  39. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/components.py +0 -0
  40. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/dependency_correlation.py +0 -0
  41. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/import_graph.py +0 -0
  42. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/project_graph.py +0 -0
  43. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/semantic.py +0 -0
  44. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/target_taxonomy.py +0 -0
  45. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/tool_identity.py +0 -0
  46. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/tool_implementation.py +0 -0
  47. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analysis/tool_surface.py +0 -0
  48. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/__init__.py +0 -0
  49. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/capability/__init__.py +0 -0
  50. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/capability/analyzer.py +0 -0
  51. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/claude_code/__init__.py +0 -0
  52. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/claude_code/analyzer.py +0 -0
  53. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/data_leakage/__init__.py +0 -0
  54. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/data_leakage/analyzer.py +0 -0
  55. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/dataflow/__init__.py +0 -0
  56. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/dataflow/analyzer.py +0 -0
  57. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/env_dependency/__init__.py +0 -0
  58. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/env_dependency/analyzer.py +0 -0
  59. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/governance/__init__.py +0 -0
  60. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/governance/analyzer.py +0 -0
  61. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/mcp/__init__.py +0 -0
  62. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/mcp/analyzer.py +0 -0
  63. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/mcp/compatibility.py +0 -0
  64. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/mcp/schema.py +0 -0
  65. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/mcp/validators.py +0 -0
  66. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/model_config/__init__.py +0 -0
  67. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/model_config/analyzer.py +0 -0
  68. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/prompt/__init__.py +0 -0
  69. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/prompt/analyzer.py +0 -0
  70. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/prompt_file/__init__.py +0 -0
  71. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/prompt_file/analyzer.py +0 -0
  72. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/skill/__init__.py +0 -0
  73. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/skill/analyzer.py +0 -0
  74. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/tool_def/__init__.py +0 -0
  75. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/tool_def/analyzer.py +0 -0
  76. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/workflow/__init__.py +0 -0
  77. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/analyzers/workflow/analyzer.py +0 -0
  78. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/cmd/__init__.py +0 -0
  79. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/cmd/postprocess.py +0 -0
  80. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/controls/__init__.py +0 -0
  81. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/controls/catalogs.py +0 -0
  82. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/controls/mappings.py +0 -0
  83. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/engine/__init__.py +0 -0
  84. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/engine/file_discovery.py +0 -0
  85. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/engine/metadata.py +0 -0
  86. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/engine/orchestrator.py +0 -0
  87. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/engine/scan.py +0 -0
  88. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/__init__.py +0 -0
  89. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/autogen/parser.py +0 -0
  90. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/azure_foundry/__init__.py +0 -0
  91. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/azure_foundry/parser.py +0 -0
  92. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/bedrock_agent/__init__.py +0 -0
  93. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/bedrock_agent/parser.py +0 -0
  94. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/claude_code/__init__.py +0 -0
  95. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/claude_code/commands.py +0 -0
  96. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/claude_code/parser.py +0 -0
  97. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/claude_code/permissions.py +0 -0
  98. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/claude_code/settings.py +0 -0
  99. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/crewai/__init__.py +0 -0
  100. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/crewai/parser.py +0 -0
  101. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/cursorrules/__init__.py +0 -0
  102. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/cursorrules/parser.py +0 -0
  103. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/dify/__init__.py +0 -0
  104. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/dify/parser.py +0 -0
  105. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/google_adk/__init__.py +0 -0
  106. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/google_adk/parser.py +0 -0
  107. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/haystack/__init__.py +0 -0
  108. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/haystack/parser.py +0 -0
  109. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/langchain/__init__.py +0 -0
  110. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/langchain/parser.py +0 -0
  111. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/langgraph/__init__.py +0 -0
  112. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/langgraph/parser.py +0 -0
  113. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/llamaindex/__init__.py +0 -0
  114. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/llamaindex/parser.py +0 -0
  115. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/mastra/__init__.py +0 -0
  116. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/mastra/parser.py +0 -0
  117. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/microsoft_agent/__init__.py +0 -0
  118. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/microsoft_agent/parser.py +0 -0
  119. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/n8n/__init__.py +0 -0
  120. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/n8n/parser.py +0 -0
  121. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/openai_agents/__init__.py +0 -0
  122. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/openai_agents/parser.py +0 -0
  123. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/semantic_kernel/__init__.py +0 -0
  124. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/semantic_kernel/parser.py +0 -0
  125. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/windsurf/__init__.py +0 -0
  126. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/frameworks/windsurf/parser.py +0 -0
  127. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/__init__.py +0 -0
  128. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/assurance.py +0 -0
  129. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/baseline.py +0 -0
  130. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/ci_context.py +0 -0
  131. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/enrich.py +0 -0
  132. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/fingerprints.py +0 -0
  133. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/identity.py +0 -0
  134. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/policy.py +0 -0
  135. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/registry/__init__.py +0 -0
  136. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/registry/connection.py +0 -0
  137. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/registry/persist.py +0 -0
  138. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/registry/queries.py +0 -0
  139. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/registry/schema.py +0 -0
  140. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/suppressions.py +0 -0
  141. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/kya/util.py +0 -0
  142. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/__init__.py +0 -0
  143. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/failure_matrix.py +0 -0
  144. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/html_kit.py +0 -0
  145. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/json_report.py +0 -0
  146. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/registry_html.py +0 -0
  147. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/report/sarif.py +0 -0
  148. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/rules/__init__.py +0 -0
  149. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/rules/base_rules.yaml +0 -0
  150. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/rules/loader.py +0 -0
  151. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/scoring/__init__.py +0 -0
  152. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/scoring/engine.py +0 -0
  153. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/severity.py +0 -0
  154. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/telemetry/__init__.py +0 -0
  155. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/telemetry/client.py +0 -0
  156. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/telemetry/config.py +0 -0
  157. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/safeai/telemetry/schema.py +0 -0
  158. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/setup.cfg +0 -0
  159. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_adapter_dataflow.py +0 -0
  160. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_assurance.py +0 -0
  161. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_baseline.py +0 -0
  162. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_capability_detection.py +0 -0
  163. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_capability_diff_v2.py +0 -0
  164. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_ci_context.py +0 -0
  165. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_claude_code_deep.py +0 -0
  166. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_compatibility.py +0 -0
  167. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_component_graph.py +0 -0
  168. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_component_hash.py +0 -0
  169. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_confidence_arbitration.py +0 -0
  170. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_control_mappings.py +0 -0
  171. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_crewai_framework.py +0 -0
  172. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_cursorrules_framework.py +0 -0
  173. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_env_dependency.py +0 -0
  174. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_escalation.py +0 -0
  175. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_evidence_type.py +0 -0
  176. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_fingerprints.py +0 -0
  177. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_github_action.py +0 -0
  178. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_governance_analyzer.py +0 -0
  179. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_html_report.py +0 -0
  180. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_init_and_rules.py +0 -0
  181. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_kya_integration.py +0 -0
  182. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_kya_manifest.py +0 -0
  183. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_langgraph_framework.py +0 -0
  184. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_llamaindex_framework.py +0 -0
  185. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_mcp_tool_poisoning.py +0 -0
  186. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_mcp_validation.py +0 -0
  187. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_n8n_workflow.py +0 -0
  188. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_parser_aggregation.py +0 -0
  189. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_phase15.py +0 -0
  190. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_policy.py +0 -0
  191. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_pr_comment.py +0 -0
  192. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_pr_comment_cli.py +0 -0
  193. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_quality_gates.py +0 -0
  194. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_registry.py +0 -0
  195. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_registry_cli.py +0 -0
  196. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_registry_html.py +0 -0
  197. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_regression_fixtures.py +0 -0
  198. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_release_fixes.py +0 -0
  199. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_release_validation.py +0 -0
  200. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_rules_loader_determinism.py +0 -0
  201. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_sarif.py +0 -0
  202. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_scan_phase11.py +0 -0
  203. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_scorecard.py +0 -0
  204. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_scoring.py +0 -0
  205. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_semantic.py +0 -0
  206. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_severity.py +0 -0
  207. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_suppressions.py +0 -0
  208. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_target_taxonomy_engine.py +0 -0
  209. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_telemetry.py +0 -0
  210. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_tool_identity.py +0 -0
  211. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_tool_implementation.py +0 -0
  212. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_version.py +0 -0
  213. {safeai_static_analyzer-2.1.1 → safeai_static_analyzer-2.2.0}/tests/test_windsurf_framework.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SafeAI-Static-Analyzer
3
- Version: 2.1.1
3
+ Version: 2.2.0
4
4
  Summary: The lightweight, open-source Static AI Capability & Risk Analyzer for CI/CD pipelines.
5
5
  Author: IkarusCareer
6
6
  License-Expression: Apache-2.0
@@ -519,8 +519,10 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
519
519
  | [Roadmap](./ROADMAP.md) | Future plans and feature requests |
520
520
  | [Contributing](./CONTRIBUTING.md) | How to get involved |
521
521
  | [Security](./SECURITY.md) | Vulnerability reporting and response |
522
- | [Privacy](./PRIVACY.md) | Telemetry and data handling |
523
- | [Release Notes](./docs/release/RELEASE_NOTES.md) | Changelog for all versions |
522
+ | [Privacy](./PRIVACY.md) | Telemetry and data handling |
523
+ | [Release Notes](./docs/release/RELEASE_NOTES.md) | Changelog for all versions |
524
+ | [Governance & Editions](./docs/GOVERNANCE_AND_EDITIONS.md) | Community vs Corporate boundary and non-negotiables |
525
+ | [DCO](./DCO.md) | Contribution sign-off (Developer Certificate of Origin) |
524
526
  | [Upgrade Guide](./docs/release/UPGRADE.md) | v1.x → v2.0.0 migration |
525
527
  | [CI/CD Integration](./docs/ci-integration.md) | GitHub Actions, GitLab CI, Azure DevOps examples |
526
528
 
@@ -486,8 +486,10 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
486
486
  | [Roadmap](./ROADMAP.md) | Future plans and feature requests |
487
487
  | [Contributing](./CONTRIBUTING.md) | How to get involved |
488
488
  | [Security](./SECURITY.md) | Vulnerability reporting and response |
489
- | [Privacy](./PRIVACY.md) | Telemetry and data handling |
490
- | [Release Notes](./docs/release/RELEASE_NOTES.md) | Changelog for all versions |
489
+ | [Privacy](./PRIVACY.md) | Telemetry and data handling |
490
+ | [Release Notes](./docs/release/RELEASE_NOTES.md) | Changelog for all versions |
491
+ | [Governance & Editions](./docs/GOVERNANCE_AND_EDITIONS.md) | Community vs Corporate boundary and non-negotiables |
492
+ | [DCO](./DCO.md) | Contribution sign-off (Developer Certificate of Origin) |
491
493
  | [Upgrade Guide](./docs/release/UPGRADE.md) | v1.x → v2.0.0 migration |
492
494
  | [CI/CD Integration](./docs/ci-integration.md) | GitHub Actions, GitLab CI, Azure DevOps examples |
493
495
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SafeAI-Static-Analyzer
3
- Version: 2.1.1
3
+ Version: 2.2.0
4
4
  Summary: The lightweight, open-source Static AI Capability & Risk Analyzer for CI/CD pipelines.
5
5
  Author: IkarusCareer
6
6
  License-Expression: Apache-2.0
@@ -519,8 +519,10 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
519
519
  | [Roadmap](./ROADMAP.md) | Future plans and feature requests |
520
520
  | [Contributing](./CONTRIBUTING.md) | How to get involved |
521
521
  | [Security](./SECURITY.md) | Vulnerability reporting and response |
522
- | [Privacy](./PRIVACY.md) | Telemetry and data handling |
523
- | [Release Notes](./docs/release/RELEASE_NOTES.md) | Changelog for all versions |
522
+ | [Privacy](./PRIVACY.md) | Telemetry and data handling |
523
+ | [Release Notes](./docs/release/RELEASE_NOTES.md) | Changelog for all versions |
524
+ | [Governance & Editions](./docs/GOVERNANCE_AND_EDITIONS.md) | Community vs Corporate boundary and non-negotiables |
525
+ | [DCO](./DCO.md) | Contribution sign-off (Developer Certificate of Origin) |
524
526
  | [Upgrade Guide](./docs/release/UPGRADE.md) | v1.x → v2.0.0 migration |
525
527
  | [CI/CD Integration](./docs/ci-integration.md) | GitHub Actions, GitLab CI, Azure DevOps examples |
526
528
 
@@ -21,6 +21,7 @@ safeai/analysis/component_graph.py
21
21
  safeai/analysis/components.py
22
22
  safeai/analysis/dependency_correlation.py
23
23
  safeai/analysis/escalation.py
24
+ safeai/analysis/escalation_remediation.py
24
25
  safeai/analysis/import_graph.py
25
26
  safeai/analysis/project_graph.py
26
27
  safeai/analysis/semantic.py
@@ -60,6 +61,7 @@ safeai/analyzers/workflow/__init__.py
60
61
  safeai/analyzers/workflow/analyzer.py
61
62
  safeai/cmd/__init__.py
62
63
  safeai/cmd/cli.py
64
+ safeai/cmd/manifest_cli.py
63
65
  safeai/cmd/postprocess.py
64
66
  safeai/cmd/registry_cli.py
65
67
  safeai/controls/__init__.py
@@ -113,11 +115,13 @@ safeai/kya/__init__.py
113
115
  safeai/kya/assurance.py
114
116
  safeai/kya/baseline.py
115
117
  safeai/kya/ci_context.py
118
+ safeai/kya/contract.py
116
119
  safeai/kya/enrich.py
117
120
  safeai/kya/exporter.py
118
121
  safeai/kya/fingerprints.py
119
122
  safeai/kya/identity.py
120
123
  safeai/kya/importer.py
124
+ safeai/kya/integrity.py
121
125
  safeai/kya/manifest.py
122
126
  safeai/kya/policy.py
123
127
  safeai/kya/suppressions.py
@@ -148,6 +152,7 @@ safeai/telemetry/schema.py
148
152
  tests/test_adapter_dataflow.py
149
153
  tests/test_assurance.py
150
154
  tests/test_baseline.py
155
+ tests/test_benchmarks.py
151
156
  tests/test_capability_detection.py
152
157
  tests/test_capability_diff_v2.py
153
158
  tests/test_ci_context.py
@@ -159,8 +164,10 @@ tests/test_confidence_arbitration.py
159
164
  tests/test_control_mappings.py
160
165
  tests/test_crewai_framework.py
161
166
  tests/test_cursorrules_framework.py
167
+ tests/test_dco.py
162
168
  tests/test_env_dependency.py
163
169
  tests/test_escalation.py
170
+ tests/test_escalation_remediation.py
164
171
  tests/test_evidence_type.py
165
172
  tests/test_fingerprints.py
166
173
  tests/test_github_action.py
@@ -171,6 +178,8 @@ tests/test_kya_integration.py
171
178
  tests/test_kya_manifest.py
172
179
  tests/test_langgraph_framework.py
173
180
  tests/test_llamaindex_framework.py
181
+ tests/test_manifest_contract.py
182
+ tests/test_manifest_integrity.py
174
183
  tests/test_mcp_tool_poisoning.py
175
184
  tests/test_mcp_validation.py
176
185
  tests/test_n8n_workflow.py
@@ -20,6 +20,7 @@ from safeai.analysis.capabilities import (
20
20
  is_escalation,
21
21
  max_access_mode,
22
22
  )
23
+ from safeai.analysis.escalation_remediation import remediation_for
23
24
  from safeai.severity import ESCALATION_SEVERITIES
24
25
  from safeai.severity import rank as severity_rank
25
26
 
@@ -471,6 +472,7 @@ def classify_escalations(before_state, after_state, status, evaluate_combination
471
472
  "evidence": match["evidence"],
472
473
  "confidence": match["confidence"],
473
474
  "inferred": bool(match["inferred"]),
475
+ "remediation": remediation_for(rule["id"]),
474
476
  })
475
477
 
476
478
  for rule in generic_rules:
@@ -492,6 +494,7 @@ def classify_escalations(before_state, after_state, status, evaluate_combination
492
494
  "evidence": match["evidence"],
493
495
  "confidence": match["confidence"],
494
496
  "inferred": bool(match["inferred"]),
497
+ "remediation": remediation_for(rule["id"]),
495
498
  })
496
499
 
497
500
  escalations.sort(key=lambda e: (-severity_rank(e["severity"]), e["id"]))
@@ -0,0 +1,354 @@
1
+ """Structured remediation for authority escalations (ChangeGuard).
2
+
3
+ Every ``ESC_*`` rule in :mod:`safeai.analysis.escalation` gets one entry:
4
+
5
+ * ``summary`` — one line, safe to render in PR comments.
6
+ * ``why_it_matters`` — the authority implication in plain language.
7
+ * ``review_questions`` — what a reviewer must answer before approving.
8
+ * ``recommended_actions`` — minimum safer actions (review/restrict/verify
9
+ language; never auto-fix instructions, never patch diffs).
10
+ * ``safe_configuration_patterns`` — deterministic, framework-neutral
11
+ patterns a reviewer can recognize (not code to paste).
12
+ * ``limitations`` — what static analysis did and did not verify.
13
+
14
+ SafeAI proposes remediation; it never modifies code, opens pull requests,
15
+ calls APIs, or claims a suggestion is universally correct. No source
16
+ values or secret values appear here — all strings are static prose.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ _STATIC_LIMIT = (
22
+ "Static analysis cannot confirm the runtime identity, IAM role, "
23
+ "deployed network policy, or actual tool execution."
24
+ )
25
+
26
+ REMEDIATION = {
27
+ "ESC_SHELL_ADDED": {
28
+ "summary": "Remove shell execution or gate it behind approval.",
29
+ "why_it_matters": (
30
+ "A tool that previously could not run commands can now execute "
31
+ "arbitrary shell or code. A compromised instruction path can turn "
32
+ "this into full host control."
33
+ ),
34
+ "review_questions": [
35
+ "Is shell execution required for this tool's intended purpose?",
36
+ "Which commands must it run — can they be an explicit allowlist?",
37
+ "Is a human approval step required before execution?",
38
+ ],
39
+ "recommended_actions": [
40
+ "Remove shell execution if the tool can work without it.",
41
+ "Restrict to an explicit command allowlist with argument validation.",
42
+ "Require human approval before execution in production profiles.",
43
+ ],
44
+ "safe_configuration_patterns": [
45
+ "No shell capability; or allowlisted commands with validated arguments and an approval gate.",
46
+ ],
47
+ "limitations": [_STATIC_LIMIT],
48
+ },
49
+ "ESC_ACCESS_MODE_INCREASED": {
50
+ "summary": "Confirm the widened access is intended and scoped.",
51
+ "why_it_matters": (
52
+ "A capability moved up the access ladder "
53
+ "(none < read < write < mutate < execute). Broader authority means "
54
+ "a misdirected plan can change more state."
55
+ ),
56
+ "review_questions": [
57
+ "Which change required the wider access mode?",
58
+ "Is the widened mode the minimum the task needs?",
59
+ ],
60
+ "recommended_actions": [
61
+ "Confirm the wider mode is intentional and scoped to the task.",
62
+ "Split the tool if one operation needs write while others need read.",
63
+ "Record the justification in the PR or policy exception.",
64
+ ],
65
+ "safe_configuration_patterns": [
66
+ "Each tool holds the minimum access mode its documented purpose needs.",
67
+ ],
68
+ "limitations": [_STATIC_LIMIT],
69
+ },
70
+ "ESC_FILESYSTEM_WRITE_ADDED": {
71
+ "summary": "Scope filesystem writes to explicit paths.",
72
+ "why_it_matters": (
73
+ "The agent can now modify files. Unscoped writes risk config "
74
+ "corruption, log tampering, or planting executable content."
75
+ ),
76
+ "review_questions": [
77
+ "Which directories must the agent write to?",
78
+ "Are read-only paths separated from writable ones?",
79
+ ],
80
+ "recommended_actions": [
81
+ "Restrict writes to explicit directories.",
82
+ "Keep credentials, configs, and code paths read-only.",
83
+ "Add an approval step before writes outside the sandbox.",
84
+ ],
85
+ "safe_configuration_patterns": [
86
+ "Writable paths enumerated; everything else read-only or unreachable.",
87
+ ],
88
+ "limitations": [_STATIC_LIMIT],
89
+ },
90
+ "ESC_EXTERNAL_ACCESS_ADDED": {
91
+ "summary": "Confirm each new external endpoint is intended.",
92
+ "why_it_matters": (
93
+ "New HTTP/API reach expands the exfiltration and supply-chain "
94
+ "surface: data can now leave to a destination it could not reach "
95
+ "before."
96
+ ),
97
+ "review_questions": [
98
+ "Which endpoints were added and why?",
99
+ "What data may be sent to each endpoint?",
100
+ ],
101
+ "recommended_actions": [
102
+ "Allowlist the required endpoints; deny the rest.",
103
+ "Verify request payloads carry no secrets or PII beyond necessity.",
104
+ "Add timeouts and retry bounds to new external calls.",
105
+ ],
106
+ "safe_configuration_patterns": [
107
+ "Explicit endpoint allowlist with bounded retries and timeouts.",
108
+ ],
109
+ "limitations": [_STATIC_LIMIT],
110
+ },
111
+ "ESC_MCP_SERVER_ADDED": {
112
+ "summary": "Review the new MCP server's identity and permissions.",
113
+ "why_it_matters": (
114
+ "A new MCP server extends the agent's authority to a new service. "
115
+ "Its transport, authentication, and tool permissions are now part "
116
+ "of the trust boundary."
117
+ ),
118
+ "review_questions": [
119
+ "Is the server's transport (stdio vs remote) appropriate?",
120
+ "Is authentication configured and least-privilege?",
121
+ "Which tools does it expose, and are all of them needed?",
122
+ ],
123
+ "recommended_actions": [
124
+ "Pin the server identity (command path or endpoint) explicitly.",
125
+ "Configure authentication; remove wildcard permissions.",
126
+ "Disable unneeded tools or resources on the server.",
127
+ ],
128
+ "safe_configuration_patterns": [
129
+ "Pinned server identity, authenticated transport, least-privilege tool set.",
130
+ ],
131
+ "limitations": [_STATIC_LIMIT],
132
+ },
133
+ "ESC_MCP_READ_TO_MUTATE": {
134
+ "summary": "Restrict the new mutating operations or add approval.",
135
+ "why_it_matters": (
136
+ "A previously read-only MCP server now exposes mutating "
137
+ "operations. A compromised instruction path or overly broad plan "
138
+ "can now change external state."
139
+ ),
140
+ "review_questions": [
141
+ "Are the mutating operations required for this agent's purpose?",
142
+ "Is a human approval boundary required before mutation?",
143
+ "Are server identity, transport, and auth constraints explicit?",
144
+ ],
145
+ "recommended_actions": [
146
+ "Restrict the tool allowlist to the minimum mutating operations.",
147
+ "Require approval before destructive or financial mutations.",
148
+ "Bind authentication and destination scope to the specific service.",
149
+ ],
150
+ "safe_configuration_patterns": [
151
+ "Read-only by default; mutating tools individually allowlisted with approval.",
152
+ ],
153
+ "limitations": [_STATIC_LIMIT],
154
+ },
155
+ "ESC_APPROVAL_GATE_REMOVED": {
156
+ "summary": "Restore the human-approval gate or document its replacement.",
157
+ "why_it_matters": (
158
+ "The last human checkpoint before a side effect is gone. The "
159
+ "agent can now act on its own judgment where a person used to "
160
+ "confirm."
161
+ ),
162
+ "review_questions": [
163
+ "What replaces the removed gate, if anything?",
164
+ "Which side effects are now ungated?",
165
+ ],
166
+ "recommended_actions": [
167
+ "Restore the approval gate, or record an accepted-exception with owner and expiry.",
168
+ "Verify remaining gates still cover destructive operations.",
169
+ "Add audit logging for ungated actions if the removal stands.",
170
+ ],
171
+ "safe_configuration_patterns": [
172
+ "Every mutating/executing tool path passes an approval checkpoint or a recorded exception.",
173
+ ],
174
+ "limitations": [_STATIC_LIMIT],
175
+ },
176
+ "ESC_MEMORY_SCOPE_EXPANDED": {
177
+ "summary": "Confirm the broadened memory scope and retention.",
178
+ "why_it_matters": (
179
+ "Wider memory/RAG scope means more data — possibly sensitive — is "
180
+ "retrievable into future prompts, increasing leakage and "
181
+ "poisoning surface."
182
+ ),
183
+ "review_questions": [
184
+ "What new data sources entered the memory scope?",
185
+ "What is the retention and redaction policy for stored content?",
186
+ ],
187
+ "recommended_actions": [
188
+ "Limit retrieval scope to the task's data sources.",
189
+ "Confirm secrets and PII are excluded or redacted.",
190
+ "Review retention windows for stored conversation and documents.",
191
+ ],
192
+ "safe_configuration_patterns": [
193
+ "Scoped retrieval sources with redaction and bounded retention.",
194
+ ],
195
+ "limitations": [_STATIC_LIMIT],
196
+ },
197
+ "ESC_WRITE_TOOL_ADDED": {
198
+ "summary": "Review the new write-capable tool's necessity and scope.",
199
+ "why_it_matters": (
200
+ "A brand-new tool with write-level authority appeared. New tools "
201
+ "have no review history, so their scope deserves explicit scrutiny."
202
+ ),
203
+ "review_questions": [
204
+ "What task requires this new tool?",
205
+ "What is the blast radius of its write operations?",
206
+ ],
207
+ "recommended_actions": [
208
+ "Confirm the tool is necessary; remove it otherwise.",
209
+ "Scope its inputs and destinations to the documented task.",
210
+ "Add the tool to the appropriate policy profile.",
211
+ ],
212
+ "safe_configuration_patterns": [
213
+ "New tools start narrowly scoped and gain authority only by reviewed change.",
214
+ ],
215
+ "limitations": [_STATIC_LIMIT],
216
+ },
217
+ "ESC_NEW_EXTERNAL_DESTINATION": {
218
+ "summary": "Verify the new write destination and what may flow to it.",
219
+ "why_it_matters": (
220
+ "Agent output can now reach a new external destination. Each new "
221
+ "sink is a potential exfiltration path."
222
+ ),
223
+ "review_questions": [
224
+ "Who operates the destination and under what terms?",
225
+ "What data categories may be written there?",
226
+ ],
227
+ "recommended_actions": [
228
+ "Confirm the destination is intended and documented.",
229
+ "Restrict payload to the minimum data the task needs.",
230
+ "Ensure audit logging covers writes to the new destination.",
231
+ ],
232
+ "safe_configuration_patterns": [
233
+ "Enumerated destinations with payload minimization and audit coverage.",
234
+ ],
235
+ "limitations": [_STATIC_LIMIT],
236
+ },
237
+ "ESC_AUTONOMY_INCREASED": {
238
+ "summary": "Bound the new autonomous planning with limits and checkpoints.",
239
+ "why_it_matters": (
240
+ "Planner/delegation capability joined a tool with side effects. "
241
+ "The agent can now chain actions toward goals with less oversight."
242
+ ),
243
+ "review_questions": [
244
+ "What bounds the planner: iterations, depth, timeouts?",
245
+ "Where are the human checkpoints in multi-step plans?",
246
+ ],
247
+ "recommended_actions": [
248
+ "Add iteration/depth/timeout bounds to autonomous loops.",
249
+ "Require approval before high-impact plan steps.",
250
+ "Log plans and tool calls for post-hoc review.",
251
+ ],
252
+ "safe_configuration_patterns": [
253
+ "Bounded autonomy: limits plus checkpoints plus audit trail.",
254
+ ],
255
+ "limitations": [_STATIC_LIMIT],
256
+ },
257
+ "ESC_COMBO_UNTRUSTED_INPUT_SHELL": {
258
+ "summary": "Break the untrusted-input-to-shell path or sandbox it.",
259
+ "why_it_matters": (
260
+ "Untrusted input can reach shell execution in the current state. "
261
+ "This is the classic injection-to-compromise chain."
262
+ ),
263
+ "review_questions": [
264
+ "Which input source is untrusted, and can it be validated?",
265
+ "Is there any sanitization between input and shell?",
266
+ ],
267
+ "recommended_actions": [
268
+ "Validate and sanitize all untrusted input before shell use.",
269
+ "Prefer argument arrays over shell strings; avoid shell=True.",
270
+ "Sandbox execution and require approval for shell steps.",
271
+ ],
272
+ "safe_configuration_patterns": [
273
+ "No untrusted bytes reach a shell without validation and an approval boundary.",
274
+ ],
275
+ "limitations": [_STATIC_LIMIT],
276
+ },
277
+ "ESC_COMBO_AUTONOMY_BROAD_DATA": {
278
+ "summary": "Scope data access for the autonomous planner.",
279
+ "why_it_matters": (
280
+ "An autonomous planner combined with broad data access can "
281
+ "exfiltrate or corrupt far more than a single-step tool — and do "
282
+ "it without asking."
283
+ ),
284
+ "review_questions": [
285
+ "Does the planner need all reachable data sources?",
286
+ "What stops a misdirected plan from reading sensitive stores?",
287
+ ],
288
+ "recommended_actions": [
289
+ "Restrict the planner's data sources to the task at hand.",
290
+ "Separate sensitive stores from planner-reachable retrieval.",
291
+ "Add approval before plans touch sensitive data.",
292
+ ],
293
+ "safe_configuration_patterns": [
294
+ "Planners see task-scoped data; sensitive stores need explicit approval.",
295
+ ],
296
+ "limitations": [_STATIC_LIMIT],
297
+ },
298
+ "ESC_COMBO_DELEGATION_EXTERNAL_SIDE_EFFECT": {
299
+ "summary": "Constrain delegated authority over external effects.",
300
+ "why_it_matters": (
301
+ "Delegation combined with external writes lets subagents act on "
302
+ "outside systems with the parent's authority — a confused-deputy "
303
+ "shape."
304
+ ),
305
+ "review_questions": [
306
+ "What authority does each delegate actually need?",
307
+ "Can a delegate trigger external effects the parent never reviewed?",
308
+ ],
309
+ "recommended_actions": [
310
+ "Give delegates the minimum authority for their subtask.",
311
+ "Require parent or human approval for external side effects.",
312
+ "Log delegation chains with the originating intent.",
313
+ ],
314
+ "safe_configuration_patterns": [
315
+ "Least-privilege delegates; external effects approved at the parent level.",
316
+ ],
317
+ "limitations": [_STATIC_LIMIT],
318
+ },
319
+ }
320
+
321
+ #: Rules covered — must equal the rule table in escalation.py.
322
+ COVERED_RULE_IDS = frozenset(REMEDIATION)
323
+
324
+
325
+ def remediation_for(rule_id):
326
+ """Return the structured remediation dict for an escalation rule ID.
327
+
328
+ Returns a copy so renderers cannot mutate the catalog. Unknown IDs
329
+ yield a generic least-privilege entry (never ``None``) so every
330
+ escalation renders *something* actionable.
331
+ """
332
+ entry = REMEDIATION.get(str(rule_id))
333
+ if entry is None:
334
+ return {
335
+ "summary": "Review this authority change before approving.",
336
+ "why_it_matters": (
337
+ "An authority change was detected that has no specific "
338
+ "guidance entry."
339
+ ),
340
+ "review_questions": ["Is this authority change intended?"],
341
+ "recommended_actions": [
342
+ "Confirm the change is intentional and scoped to the task.",
343
+ ],
344
+ "safe_configuration_patterns": [],
345
+ "limitations": [_STATIC_LIMIT],
346
+ }
347
+ return {
348
+ "summary": entry["summary"],
349
+ "why_it_matters": entry["why_it_matters"],
350
+ "review_questions": list(entry["review_questions"]),
351
+ "recommended_actions": list(entry["recommended_actions"]),
352
+ "safe_configuration_patterns": list(entry["safe_configuration_patterns"]),
353
+ "limitations": list(entry["limitations"]),
354
+ }
@@ -12,6 +12,7 @@ Usage::
12
12
  [--fail-on-rule <pattern>] [--fail-on-category <name>]
13
13
  safeai init [--profile <name>] [--force]
14
14
  safeai registry list|show|history|diff|export|import|components ...
15
+ safeai manifest validate|verify <file>
15
16
 
16
17
  KYA (Know Your Agent) behavior:
17
18
  * Every scan produces normalized findings (stable fingerprints,
@@ -173,6 +174,10 @@ def _build_parser():
173
174
  help="Preview rows that would be imported without writing")
174
175
  reg_import.add_argument("--force", action="store_true",
175
176
  help="Overwrite existing agent metadata with imported values")
177
+ reg_import.add_argument("--require-integrity", action="store_true",
178
+ help="Reject inventories whose integrity digest is "
179
+ "missing or invalid (default: accept, for "
180
+ "backward compatibility)")
176
181
 
177
182
  reg_meta = reg_sub.add_parser("metadata", help="View or set agent metadata (owner, environment)")
178
183
  _common(reg_meta)
@@ -190,6 +195,13 @@ def _build_parser():
190
195
 
191
196
  sub.add_parser("welcome", help="Guided first-run experience for new users")
192
197
 
198
+ manifest = sub.add_parser("manifest", help="Validate or verify a KYA manifest (offline)")
199
+ manifest_sub = manifest.add_subparsers(dest="manifest_command")
200
+ man_validate = manifest_sub.add_parser("validate", help="Validate a manifest against Contract v1")
201
+ man_validate.add_argument("file", help="Path to safeai-manifest.json")
202
+ man_verify = manifest_sub.add_parser("verify", help="Verify a manifest integrity digest (offline)")
203
+ man_verify.add_argument("file", help="Path to safeai-manifest.json")
204
+
193
205
  telemetry = sub.add_parser("telemetry", help="Manage opt-in usage telemetry")
194
206
  telemetry.add_argument(
195
207
  "telemetry_command",
@@ -483,6 +495,11 @@ def main(argv=None):
483
495
  exit_code = run_registry_command(args)
484
496
  elif args.command == "welcome":
485
497
  exit_code = _run_welcome()
498
+ elif args.command == "manifest":
499
+ if not getattr(args, "manifest_command", None):
500
+ parser.error("manifest requires a subcommand: validate|verify")
501
+ from safeai.cmd.manifest_cli import run_manifest_command
502
+ exit_code = run_manifest_command(args)
486
503
  elif args.command == "telemetry":
487
504
  exit_code = _run_telemetry(args)
488
505
  else:
@@ -0,0 +1,44 @@
1
+ """``safeai manifest`` subcommands — local manifest contract operations.
2
+
3
+ All operations are offline: read a JSON file, validate or verify it
4
+ against the local contract, print deterministic results. No network,
5
+ no execution of scanned code.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+
12
+ from safeai.kya.contract import validate_manifest
13
+
14
+
15
+ def run_manifest_command(args):
16
+ """Dispatch ``safeai manifest <validate|verify>``. Returns exit code."""
17
+ sub = getattr(args, "manifest_command", None)
18
+ if sub == "validate":
19
+ return _validate(args.file)
20
+ if sub == "verify":
21
+ from safeai.kya.integrity import verify_manifest_file
22
+ return verify_manifest_file(args.file)
23
+ print("Usage: safeai manifest {validate|verify} <file>")
24
+ return 2
25
+
26
+
27
+ def _validate(path):
28
+ try:
29
+ with open(path, encoding="utf-8") as fh:
30
+ document = json.load(fh)
31
+ except (OSError, json.JSONDecodeError) as exc:
32
+ print(f"invalid: unable to read {path}: {exc}")
33
+ return 1
34
+ errors, warnings = validate_manifest(document)
35
+ for warning in warnings:
36
+ print(f"warning: {warning}")
37
+ if errors:
38
+ print(f"invalid: {path} ({len(errors)} error(s))")
39
+ for error in errors:
40
+ print(f" - {error}")
41
+ return 1
42
+ print(f"valid: {path} (contract safeai-manifest v1, "
43
+ f"schema_version {document.get('schema_version')})")
44
+ return 0
@@ -339,7 +339,8 @@ def cmd_import(args):
339
339
  from safeai.kya.importer import import_inventory, load_inventory, plan_import
340
340
  from safeai.kya.registry import init_registry, migrate
341
341
 
342
- document = load_inventory(args.file)
342
+ document = load_inventory(args.file,
343
+ require_integrity=getattr(args, "require_integrity", False))
343
344
  if args.dry_run and not registry_exists(args.registry_path):
344
345
  conn = sqlite3.connect(":memory:")
345
346
  conn.row_factory = sqlite3.Row