SafeAI-Static-Analyzer 2.0.0__tar.gz → 2.1.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 (204) hide show
  1. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/PKG-INFO +38 -297
  2. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/README.md +35 -296
  3. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/SafeAI_Static_Analyzer.egg-info/PKG-INFO +38 -297
  4. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/SafeAI_Static_Analyzer.egg-info/SOURCES.txt +6 -0
  5. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/SafeAI_Static_Analyzer.egg-info/requires.txt +3 -0
  6. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/pyproject.toml +3 -0
  7. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/mcp/analyzer.py +110 -0
  8. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/cmd/cli.py +24 -2
  9. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/cmd/postprocess.py +54 -2
  10. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/cmd/registry_cli.py +31 -0
  11. safeai_static_analyzer-2.1.0/safeai/engine/file_discovery.py +185 -0
  12. safeai_static_analyzer-2.1.0/safeai/engine/metadata.py +91 -0
  13. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/engine/orchestrator.py +7 -0
  14. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/exporter.py +45 -1
  15. safeai_static_analyzer-2.1.0/safeai/kya/importer.py +481 -0
  16. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/registry/persist.py +2 -1
  17. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/pr_comment.py +102 -0
  18. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/scoring/engine.py +7 -7
  19. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/version.py +1 -1
  20. safeai_static_analyzer-2.1.0/tests/test_compatibility.py +634 -0
  21. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_github_action.py +1 -0
  22. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_mcp_tool_poisoning.py +105 -0
  23. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_pr_comment.py +21 -0
  24. safeai_static_analyzer-2.1.0/tests/test_quality_gates.py +51 -0
  25. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_registry_cli.py +164 -1
  26. safeai_static_analyzer-2.1.0/tests/test_regression_fixtures.py +177 -0
  27. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/LICENSE +0 -0
  28. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/SafeAI_Static_Analyzer.egg-info/dependency_links.txt +0 -0
  29. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/SafeAI_Static_Analyzer.egg-info/entry_points.txt +0 -0
  30. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/SafeAI_Static_Analyzer.egg-info/top_level.txt +0 -0
  31. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/__init__.py +0 -0
  32. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/__main__.py +0 -0
  33. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/__init__.py +0 -0
  34. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/aggregation.py +0 -0
  35. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/capabilities.py +0 -0
  36. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/capability_diff.py +0 -0
  37. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/component_diff.py +0 -0
  38. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/component_graph.py +0 -0
  39. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/components.py +0 -0
  40. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/dependency_correlation.py +0 -0
  41. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/escalation.py +0 -0
  42. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/import_graph.py +0 -0
  43. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/project_graph.py +0 -0
  44. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/semantic.py +0 -0
  45. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/target_taxonomy.py +0 -0
  46. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/tool_identity.py +0 -0
  47. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/tool_implementation.py +0 -0
  48. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analysis/tool_surface.py +0 -0
  49. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/__init__.py +0 -0
  50. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/capability/__init__.py +0 -0
  51. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/capability/analyzer.py +0 -0
  52. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/claude_code/__init__.py +0 -0
  53. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/claude_code/analyzer.py +0 -0
  54. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/data_leakage/__init__.py +0 -0
  55. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/data_leakage/analyzer.py +0 -0
  56. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/dataflow/__init__.py +0 -0
  57. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/dataflow/analyzer.py +0 -0
  58. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/env_dependency/__init__.py +0 -0
  59. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/env_dependency/analyzer.py +0 -0
  60. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/governance/__init__.py +0 -0
  61. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/governance/analyzer.py +0 -0
  62. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/mcp/__init__.py +0 -0
  63. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/mcp/compatibility.py +0 -0
  64. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/mcp/schema.py +0 -0
  65. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/mcp/validators.py +0 -0
  66. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/model_config/__init__.py +0 -0
  67. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/model_config/analyzer.py +0 -0
  68. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/prompt/__init__.py +0 -0
  69. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/prompt/analyzer.py +0 -0
  70. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/prompt_file/__init__.py +0 -0
  71. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/prompt_file/analyzer.py +0 -0
  72. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/skill/__init__.py +0 -0
  73. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/skill/analyzer.py +0 -0
  74. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/tool_def/__init__.py +0 -0
  75. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/tool_def/analyzer.py +0 -0
  76. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/workflow/__init__.py +0 -0
  77. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/analyzers/workflow/analyzer.py +0 -0
  78. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/cmd/__init__.py +0 -0
  79. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/controls/__init__.py +0 -0
  80. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/controls/catalogs.py +0 -0
  81. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/controls/mappings.py +0 -0
  82. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/engine/__init__.py +0 -0
  83. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/engine/scan.py +0 -0
  84. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/__init__.py +0 -0
  85. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/autogen/parser.py +0 -0
  86. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/azure_foundry/__init__.py +0 -0
  87. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/azure_foundry/parser.py +0 -0
  88. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/bedrock_agent/__init__.py +0 -0
  89. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/bedrock_agent/parser.py +0 -0
  90. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/claude_code/__init__.py +0 -0
  91. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/claude_code/commands.py +0 -0
  92. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/claude_code/parser.py +0 -0
  93. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/claude_code/permissions.py +0 -0
  94. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/claude_code/settings.py +0 -0
  95. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/crewai/__init__.py +0 -0
  96. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/crewai/parser.py +0 -0
  97. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/cursorrules/__init__.py +0 -0
  98. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/cursorrules/parser.py +0 -0
  99. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/dify/__init__.py +0 -0
  100. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/dify/parser.py +0 -0
  101. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/google_adk/__init__.py +0 -0
  102. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/google_adk/parser.py +0 -0
  103. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/haystack/__init__.py +0 -0
  104. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/haystack/parser.py +0 -0
  105. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/langchain/__init__.py +0 -0
  106. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/langchain/parser.py +0 -0
  107. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/langgraph/__init__.py +0 -0
  108. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/langgraph/parser.py +0 -0
  109. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/llamaindex/__init__.py +0 -0
  110. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/llamaindex/parser.py +0 -0
  111. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/mastra/__init__.py +0 -0
  112. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/mastra/parser.py +0 -0
  113. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/microsoft_agent/__init__.py +0 -0
  114. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/microsoft_agent/parser.py +0 -0
  115. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/n8n/__init__.py +0 -0
  116. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/n8n/parser.py +0 -0
  117. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/openai_agents/__init__.py +0 -0
  118. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/openai_agents/parser.py +0 -0
  119. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/semantic_kernel/__init__.py +0 -0
  120. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/semantic_kernel/parser.py +0 -0
  121. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/windsurf/__init__.py +0 -0
  122. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/frameworks/windsurf/parser.py +0 -0
  123. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/__init__.py +0 -0
  124. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/assurance.py +0 -0
  125. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/baseline.py +0 -0
  126. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/ci_context.py +0 -0
  127. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/enrich.py +0 -0
  128. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/fingerprints.py +0 -0
  129. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/identity.py +0 -0
  130. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/manifest.py +0 -0
  131. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/policy.py +0 -0
  132. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/registry/__init__.py +0 -0
  133. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/registry/connection.py +0 -0
  134. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/registry/queries.py +0 -0
  135. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/registry/schema.py +0 -0
  136. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/suppressions.py +0 -0
  137. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/kya/util.py +0 -0
  138. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/__init__.py +0 -0
  139. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/failure_matrix.py +0 -0
  140. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/html.py +0 -0
  141. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/html_kit.py +0 -0
  142. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/json_report.py +0 -0
  143. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/registry_html.py +0 -0
  144. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/sarif.py +0 -0
  145. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/report/terminal.py +0 -0
  146. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/rules/__init__.py +0 -0
  147. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/rules/base_rules.yaml +0 -0
  148. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/rules/loader.py +0 -0
  149. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/scorecard.py +0 -0
  150. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/scoring/__init__.py +0 -0
  151. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/severity.py +0 -0
  152. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/telemetry/__init__.py +0 -0
  153. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/telemetry/client.py +0 -0
  154. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/telemetry/config.py +0 -0
  155. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/safeai/telemetry/schema.py +0 -0
  156. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/setup.cfg +0 -0
  157. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_adapter_dataflow.py +0 -0
  158. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_assurance.py +0 -0
  159. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_baseline.py +0 -0
  160. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_capability_detection.py +0 -0
  161. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_capability_diff_v2.py +0 -0
  162. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_ci_context.py +0 -0
  163. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_claude_code_deep.py +0 -0
  164. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_component_graph.py +0 -0
  165. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_component_hash.py +0 -0
  166. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_confidence_arbitration.py +0 -0
  167. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_control_mappings.py +0 -0
  168. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_crewai_framework.py +0 -0
  169. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_cursorrules_framework.py +0 -0
  170. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_env_dependency.py +0 -0
  171. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_escalation.py +0 -0
  172. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_evidence_type.py +0 -0
  173. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_fingerprints.py +0 -0
  174. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_governance_analyzer.py +0 -0
  175. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_html_report.py +0 -0
  176. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_init_and_rules.py +0 -0
  177. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_kya_integration.py +0 -0
  178. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_kya_manifest.py +0 -0
  179. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_langgraph_framework.py +0 -0
  180. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_llamaindex_framework.py +0 -0
  181. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_mcp_validation.py +0 -0
  182. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_n8n_workflow.py +0 -0
  183. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_parser_aggregation.py +0 -0
  184. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_phase15.py +0 -0
  185. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_policy.py +0 -0
  186. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_pr_comment_cli.py +0 -0
  187. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_registry.py +0 -0
  188. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_registry_html.py +0 -0
  189. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_release_fixes.py +0 -0
  190. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_release_validation.py +0 -0
  191. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_rules_loader_determinism.py +0 -0
  192. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_sarif.py +0 -0
  193. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_scan_phase11.py +0 -0
  194. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_scorecard.py +0 -0
  195. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_scoring.py +0 -0
  196. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_semantic.py +0 -0
  197. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_severity.py +0 -0
  198. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_suppressions.py +0 -0
  199. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_target_taxonomy_engine.py +0 -0
  200. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_telemetry.py +0 -0
  201. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_tool_identity.py +0 -0
  202. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_tool_implementation.py +0 -0
  203. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.0}/tests/test_version.py +0 -0
  204. {safeai_static_analyzer-2.0.0 → safeai_static_analyzer-2.1.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.0.0
3
+ Version: 2.1.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
@@ -27,6 +27,8 @@ Requires-Dist: ruff<0.17,>=0.16.1; extra == "dev"
27
27
  Requires-Dist: jinja2>=3.1.4; extra == "dev"
28
28
  Requires-Dist: jsonschema>=4.22.0; extra == "dev"
29
29
  Requires-Dist: typing-extensions>=4.4.0; extra == "dev"
30
+ Provides-Extra: standalone
31
+ Requires-Dist: pyinstaller>=6.0; extra == "standalone"
30
32
  Dynamic: license-file
31
33
 
32
34
  # SafeAI — Static AI Capability & Risk Analyzer
@@ -34,7 +36,7 @@ Dynamic: license-file
34
36
  [![CI](https://github.com/ikaruscareer/SafeAI/actions/workflows/ci.yml/badge.svg)](https://github.com/ikaruscareer/SafeAI/actions/workflows/ci.yml)
35
37
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/ikaruscareer/SafeAI/badge)](https://scorecard.dev/viewer/?uri=github.com/ikaruscareer/SafeAI)
36
38
  [![Website](https://img.shields.io/badge/web-safeai--analyzer.ikaruscareer.com-0f766e)](https://safeai-analyzer.ikaruscareer.com)
37
- [![Latest Release](https://img.shields.io/badge/latest-v1.9.0-0f766e)](https://github.com/ikaruscareer/SafeAI/releases/tag/v1.9.0)
39
+ [![Latest Release](https://img.shields.io/badge/latest-v2.0.1-0f766e)](https://github.com/ikaruscareer/SafeAI/releases/tag/v2.0.1)
38
40
  [![Best Practices](https://bestpractices.dev/projects/14126/badge)](https://www.bestpractices.dev/en/projects/14126)
39
41
 
40
42
  Enjoying SafeAI? A ⭐ on [GitHub](https://github.com/ikaruscareer/SafeAI) helps more security teams find it.
@@ -82,7 +84,7 @@ SafeAI sits before runtime guardrails and red-teaming tools in the security life
82
84
 
83
85
  | Feature | Description |
84
86
  |---------|-------------|
85
- | **Framework Detection** | Detects and parses 16 AI agent frameworks (AST + config + regex, no mutual exclusion) |
87
+ | **Framework Detection** | Detects and parses 17 AI agent frameworks (AST + config + regex, no mutual exclusion) |
86
88
  | **Tool Identity & Access Modes** | Capabilities attributed to named tools (agent / MCP server / skill / tool / workflow node) on an access scale `none < read < write < mutate < execute`; inferred modes are flagged, never overstated |
87
89
  | **Capability Discovery** | Maps 19 capability categories (shell, filesystem, network, database, memory, MCP, ...) with evidence, confidence, and provenance |
88
90
  | **Capability Escalation Detection** | Per-tool authority diffs between scans (new shell, read→write widening, new MCP server, removed approval gate, ...) — 14 rules, including gating-aware subsumption |
@@ -153,7 +155,6 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
153
155
  |-----------|-----------|-----------|-------------------|---------------|--------|
154
156
  | LangGraph | ✔ | Partial | Partial | Partial | Partial |
155
157
  | CrewAI | ✔ | Partial | Partial | Partial | Partial |
156
- | AutoGen | ✔ | Partial | Minimal | Minimal | Experimental |
157
158
  | LangChain | ✔ | Partial | Partial | Partial | Partial |
158
159
  | Semantic Kernel | ✔ | Partial | Partial | Partial | Partial |
159
160
  | OpenAI Agents SDK | ✔ | Partial | Partial | Partial | Partial |
@@ -168,6 +169,7 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
168
169
  | Dify | ✔ | Minimal | Minimal | Minimal | Experimental |
169
170
  | n8n | ✔ | Partial | Minimal | Minimal | Experimental |
170
171
  | Cursor (.cursorrules) | ✔ | Minimal | Minimal | Minimal | Experimental |
172
+ | Windsurf (.windsurfrules) | ✔ | Minimal | Minimal | Minimal | Experimental |
171
173
 
172
174
 
173
175
  ### Framework Support Details
@@ -193,7 +195,7 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
193
195
  capability-relevant keywords (shell, filesystem, HTTP, database) in the
194
196
  IDE's rules config, JSON, YAML, or free text
195
197
 
196
- Maturity is on the scale defined in [`FRAMEWORK_SUPPORT.md`](FRAMEWORK_SUPPORT.md):
198
+ Maturity is on the scale defined in [`docs/reference/FRAMEWORK_SUPPORT.md`](docs/reference/FRAMEWORK_SUPPORT.md):
197
199
  **Partial** = reliable detection and discovery with capability/risk analysis over
198
200
  common patterns; **Experimental** = detection and basic artifact discovery with
199
201
  limited framework-specific analysis. No framework is rated fully **Supported**
@@ -266,6 +268,9 @@ safeai registry list --format html > registry.html # shareable HTML inventory
266
268
  safeai registry show <agent-id> # latest KYA record
267
269
  safeai registry history <agent-id> # all scans for an agent
268
270
  safeai registry diff <agent-id> --from previous --to latest
271
+ safeai registry export --output inventory.json
272
+ safeai registry import inventory.json --dry-run
273
+ safeai registry import inventory.json # atomic, idempotent merge
269
274
  safeai registry export --format json --output inventory.json
270
275
  safeai registry export --format html --output inventory.html
271
276
  ```
@@ -281,8 +286,8 @@ What you get on the first run:
281
286
 
282
287
  **KYA records static evidence, not runtime truth.** It answers "what does the
283
288
  source/configuration say this agent can do?" — never "what is this agent doing
284
- in production?" See [REGISTRY.md](REGISTRY.md), [KYA_MANIFEST.md](KYA_MANIFEST.md),
285
- and [LIMITATIONS.md](LIMITATIONS.md).
289
+ in production?" See [docs/reference/REGISTRY.md](docs/reference/REGISTRY.md), [docs/reference/KYA_MANIFEST.md](docs/reference/KYA_MANIFEST.md),
290
+ and [docs/reference/LIMITATIONS.md](docs/reference/LIMITATIONS.md).
286
291
 
287
292
  CI note: registry persistence is auto-disabled for bare CI jobs (the `CI`
288
293
  env var). Use `--registry "$RUNNER_TEMP/registry.db"`, set `SAFEAI_REGISTRY`
@@ -315,7 +320,7 @@ pip install -e ".[dev]"
315
320
 
316
321
  ## Privacy & Telemetry
317
322
 
318
- SafeAI collects no data by default. Usage telemetry is opt-in, anonymous, and fully documented in [`PRIVACY.md`](PRIVACY.md). If you do nothing, nothing is ever sent. See `PRIVACY.md` for the complete data contract, what is never collected, and how to disable telemetry.
323
+ SafeAI collects no data by default. Usage telemetry is opt-in, anonymous, and fully documented in [`PRIVACY.md`](./PRIVACY.md). If you do nothing, nothing is ever sent. See [`PRIVACY.md`](./PRIVACY.md) for the complete data contract, what is never collected, and how to disable telemetry.
319
324
 
320
325
  ---
321
326
 
@@ -392,7 +397,7 @@ python -m safeai registry export --format json --output safeai-kya-inventory.jso
392
397
 
393
398
  ## Example Output
394
399
 
395
- > See [REPORTING_GUIDE.md](./REPORTING_GUIDE.md) for a complete guide to
400
+ > See [docs/guides/REPORTING_GUIDE.md](docs/guides/REPORTING_GUIDE.md) for a complete guide to
396
401
  > interpreting each output format (HTML, JSON, SARIF, PR comments, scorecard,
397
402
  > registry) and triaging findings.
398
403
 
@@ -430,307 +435,29 @@ Findings:
430
435
 
431
436
  ## CI/CD Integration
432
437
 
433
- ### GitHub Actions — SafeAI Static Analysis
434
-
435
- [![SafeAI Static Analysis](https://img.shields.io/badge/Available%20on-GitHub%20Marketplace-2088FF?logo=github)](https://github.com/marketplace/actions/safeai-static-analysis)
436
-
437
- SafeAI ships a ready-to-use composite action for GitHub-hosted runners. The
438
- action is a thin, pure-Python driver: it installs the `SafeAI-Static-Analyzer`
439
- PyPI distribution into the runner's Python, runs `python -m safeai scan` on
440
- your repository, preserves the tool's native exit codes, and always writes a
441
- SARIF 2.1.0 artifact (even when the scan fails). It never evaluates any input
442
- through a shell, never executes your agent code, and makes no network calls
443
- beyond installing the PyPI package.
444
-
445
- Use it with `uses: ikaruscareer/SafeAI@<ref>` (see [Version pinning](#version-pinning)).
438
+ SafeAI ships a [GitHub Actions Marketplace action](https://github.com/marketplace/actions/safeai-static-analysis) and supports all major CI platforms.
446
439
 
447
440
  ```yaml
441
+ # GitHub Actions — minimal workflow
448
442
  name: safeai-scan
449
- on:
450
- push:
451
- pull_request:
452
-
453
- permissions:
454
- contents: read
455
-
456
- jobs:
457
- safeai-scan:
458
- runs-on: ubuntu-latest
459
- steps:
460
- - uses: actions/checkout@v4
461
-
462
- - uses: actions/setup-python@v5
463
- with:
464
- python-version: '3.12'
465
-
466
- - name: Scan with SafeAI
467
- id: safeai
468
- uses: ikaruscareer/SafeAI@v1.0.0
469
- with:
470
- path: .
471
- fail-on: critical
472
-
473
- - name: Upload SARIF to GitHub Advanced Security
474
- if: always()
475
- uses: github/codeql-action/upload-sarif@v3
476
- with:
477
- sarif_file: ${{ steps.safeai.outputs.sarif-path }}
478
- ```
479
-
480
- The `if: always()` on the upload step matters: SafeAI fails the job when a
481
- finding meets the `fail-on` threshold, but the SARIF file is still written so
482
- code-scanning alerts are still created. `permissions: contents: read` is the
483
- least privilege the action needs — it only reads your repository and writes
484
- reports inside the workspace.
485
-
486
- #### Inputs
487
-
488
- | Input | Default | Description |
489
- |-------|---------|-------------|
490
- | `path` | `.` | Directory or file to scan. Relative paths are resolved against `GITHUB_WORKSPACE`. |
491
- | `version` | *(latest stable)* | Exact SafeAI PyPI version to install (e.g. `1.5.0`). Empty installs the latest release of `SafeAI-Static-Analyzer`. |
492
- | `fail-on` | `critical` | Minimum severity that fails the job: `critical`, `high`, or `medium`. |
493
- | `sarif` | `safeai-results.sarif` | SARIF 2.1.0 output path, relative to the repo root. Empty string disables SARIF. |
494
- | `rules` | *(none)* | Path to a custom rules directory (`--rules`). |
495
- | `baseline` | *(none)* | Prior `safeai-manifest.json`/JSON report for new/regressed and escalation comparison (`--baseline`). |
496
- | `fail-on-new` | `false` | With `baseline`: fail only on NEW or REGRESSED findings at or above `fail-on` (`--fail-on-new`). |
497
- | `fail-on-escalation` | *(none)* | Minimum capability-escalation severity that fails the job: `critical`, `high`, or `medium`. Requires `baseline`. |
498
- | `no-registry` | `true` | Skip local KYA registry persistence (`--no-registry`), keeping scans ephemeral. |
499
- | `extra-args` | `[]` | Extra scan arguments as a JSON array of strings (e.g. `["--verbose"]`). Never shell-evaluated. |
500
-
501
- #### Outputs
502
-
503
- | Output | Description |
504
- |--------|-------------|
505
- | `sarif-path` | Absolute path to the written SARIF file (empty if SARIF was disabled or the scan did not produce one). |
506
-
507
- #### Exit behavior
508
-
509
- The action passes SafeAI's exit code through unchanged:
510
-
511
- | Code | Condition |
512
- |------|-----------|
513
- | 0 | No findings at or above `fail-on`; policy outcome not `deny`. |
514
- | 1 | Finding at or above threshold, new/regressed finding with `fail-on-new`, escalation with `fail-on-escalation`, or policy `deny`. |
515
- | 2 | Operational error — missing scan path, invalid input, or missing Python 3.11+. |
516
-
517
- Even on exit 1, the SARIF file (and any HTML/JSON reports you request via
518
- `extra-args`) are written so downstream steps can keep working. The action
519
- prints a GitHub `::warning::` if a scan failed without producing SARIF.
520
-
521
- #### More examples
522
-
523
- PR gating on new findings + escalation review:
524
-
525
- ```yaml
526
- - name: Scan with SafeAI
527
- uses: ikaruscareer/SafeAI@v1.0.0
528
- with:
529
- path: .
530
- baseline: safeai-manifest.json
531
- fail-on-new: 'true'
532
- fail-on-escalation: high
533
- sarif: safeai-results.sarif
534
- ```
535
-
536
- Custom rules, verbose logs, and an HTML report (all argv-passed, no shell):
537
-
538
- ```yaml
539
- - name: Scan with SafeAI
540
- uses: ikaruscareer/SafeAI@v1.0.0
541
- with:
542
- path: ./agents
543
- rules: .safeai/rules
544
- extra-args: '["--verbose", "--html", "report.html"]'
545
- ```
546
-
547
- #### Version pinning
548
-
549
- Exact versioning is required for Marketplace-verified actions. Pin to a
550
- release tag:
551
-
552
- ```yaml
553
- uses: ikaruscareer/SafeAI@v1.0.0
554
- ```
555
-
556
- and optionally relax to the major tag `@v1` for bugfix updates. For the
557
- strictest supply-chain posture, pin to a full commit SHA:
558
-
559
- ```yaml
560
- uses: ikaruscareer/SafeAI@<40-char-commit-sha>
561
- ```
562
-
563
- The `version` input is independent: it controls the SafeAI **PyPI** package
564
- installed into the runner, while the `uses:` ref controls which **action**
565
- release you run.
566
-
567
- **Recommended posture — pin both.** The `version` input defaults to the
568
- *latest stable* SafeAI release on PyPI (per the Marketplace design), but
569
- pinning it makes every scan reproducible and avoids surprising tool/action
570
- pairings. Set the `version` input to the exact release the action was
571
- validated against:
572
-
573
- ```yaml
574
- - uses: ikaruscareer/SafeAI@v1.0.0
575
- with:
576
- version: "1.5.0"
577
- ```
578
-
579
- If you rely on the default, know that SafeAI may upgrade underneath you on a
580
- future run; combined with `uses: @v1`, that is two moving parts. For
581
- maximum supply-chain control, pin the action to a commit SHA *and* set an
582
- explicit `version`.
583
-
584
- #### Troubleshooting
585
-
586
- - **`SafeAI requires Python 3.11+`** — the runner's default Python is too old
587
- or missing. Add `actions/setup-python@v5` with `python-version: '3.12'`
588
- before this action.
589
- - **Scan fails but you expected it to pass** — lower the threshold or switch
590
- to baseline-gated `fail-on-new`, which only fails on regressions.
591
- - **No SARIF uploaded despite `if: always()`** — confirm the `sarif` input is
592
- non-empty and that `${{ steps.safeai.outputs.sarif-path }}` is referenced
593
- with the same `id:` you set on the action step.
594
- - **Security scanners flag `${{ inputs.* }}` interpolation** — this is safe:
595
- action inputs are passed to the driver as environment variables with
596
- `env:`, and the driver hands them to the tool as an argv list. No input is
597
- ever interpolated into `run:`.
598
- - **Registry warnings** — `no-registry: true` is the default precisely so
599
- scans on shared runners stay ephemeral and never touch a shared
600
- `~/.safeai/registry.db`.
601
-
602
- The action's own test workflow (`.github/workflows/action-test.yml`) runs the
603
- action against fixture repositories, builds and inspects the wheel, and
604
- validates SARIF output on every commit.
605
-
606
- ### GitHub Actions (manual workflow)
607
-
608
- A self-scan workflow is also included at `.github/workflows/ci.yml`. To use
609
- SafeAI directly in your project:
610
-
611
- ```yaml
612
- jobs:
613
- safeai-scan:
614
- runs-on: ubuntu-latest
615
- steps:
616
- - uses: actions/checkout@v4
617
- - uses: actions/setup-python@v5
618
- with:
619
- python-version: '3.12'
620
- - name: Install SafeAI
621
- run: |
622
- pip install -e .
623
- - name: Run scan
624
- run: |
625
- python -m safeai scan . \
626
- --sarif results.sarif \
627
- --html report.html \
628
- --manifest safeai-manifest.json \
629
- --no-registry
630
- - name: Upload SARIF
631
- uses: github/codeql-action/upload-sarif@v3
632
- with:
633
- sarif_file: results.sarif
634
- ```
635
-
636
- ### GitLab CI
637
-
638
- ```yaml
639
- safeai-scan:
640
- image: python:3.12
641
- script:
642
- - pip install -e .
643
- - python -m safeai scan . --sarif results.sarif --html report.html --no-registry
644
- artifacts:
645
- paths:
646
- - results.sarif
647
- - report.html
648
- ```
649
-
650
- ### Azure DevOps
651
-
652
- ```yaml
653
- - task: PythonScript@0
654
- inputs:
655
- scriptSource: 'inline'
656
- script: |
657
- import subprocess
658
- subprocess.run(["pip", "install", "-e", "."])
659
- subprocess.run(["python", "-m", "safeai", "scan", ".", "--sarif", "$(Build.ArtifactStagingDirectory)/results.sarif", "--no-registry"])
660
- ```
661
-
662
- ### Capability escalation in CI
663
-
664
- A capability *escalation* is a change between two scans where a tool gains
665
- more authority than it had before — a new shell capability, a filesystem
666
- access widening from read to write, a new MCP server, an approval gate
667
- being removed, and so on (see `RULES_REFERENCE.md` and `KYA_MANIFEST.md`
668
- for the full rule list). Reviewing these on every pull request is more
669
- targeted than reviewing every finding, because most findings on a mature
670
- codebase are pre-existing and already accepted; an escalation is new by
671
- definition.
672
-
673
- `--fail-on-escalation` gates the scan on escalation severity, and
674
- `--pr-comment` writes a short Markdown summary you can post as a PR
675
- comment. SafeAI itself never posts anything anywhere and makes no network
676
- calls of any kind — generating the comment and publishing it are two
677
- separate steps, and the second one is entirely up to your CI workflow.
678
-
679
- ```yaml
680
- name: safeai-escalation-check
681
- on:
682
- pull_request:
683
-
443
+ on: [push, pull_request]
684
444
  permissions:
685
445
  contents: read
686
- pull-requests: write
687
-
688
446
  jobs:
689
- safeai-scan:
447
+ scan:
690
448
  runs-on: ubuntu-latest
691
449
  steps:
692
450
  - uses: actions/checkout@v4
693
451
  - uses: actions/setup-python@v5
694
- with:
695
- python-version: '3.12'
696
- - name: Install SafeAI
697
- run: pip install -e .
698
-
699
- - name: Fetch baseline manifest from the base branch
700
- run: |
701
- git fetch origin "${{ github.event.pull_request.base.ref }}" --depth=1
702
- git show "origin/${{ github.event.pull_request.base.ref }}:safeai-manifest.json" \
703
- > safeai-manifest.json || echo '{}' > safeai-manifest.json
704
-
705
- - name: Run scan
706
- run: |
707
- safeai scan . \
708
- --baseline safeai-manifest.json \
709
- --pr-comment comment.md \
710
- --fail-on-escalation high
711
-
712
- - name: Post or update PR comment
452
+ with: { python-version: '3.12' }
453
+ - uses: ikaruscareer/SafeAI@v1
454
+ with: { path: '.', fail-on: critical }
455
+ - uses: github/codeql-action/upload-sarif@v3
713
456
  if: always()
714
- env:
715
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
716
- run: |
717
- gh pr comment "${{ github.event.pull_request.number }}" \
718
- --edit-last --body-file comment.md \
719
- || gh pr comment "${{ github.event.pull_request.number }}" \
720
- --body-file comment.md
457
+ with: { sarif_file: ${{ steps.safeai.outputs.sarif-path }} }
721
458
  ```
722
459
 
723
- The `gh pr comment --edit-last` call updates SafeAI's own previous comment
724
- in place on repeat pushes, rather than adding a new one each time; it fails
725
- when there is no previous comment to edit (for example, on the first push),
726
- so the fallback plain `gh pr comment` handles that case. The `--fail-on-escalation`
727
- step runs before the comment step so the workflow's exit code still reflects
728
- the scan outcome; `if: always()` on the comment step makes sure the comment
729
- is posted even when the scan step fails the job.
730
-
731
- ### SARIF Integration
732
-
733
- SafeAI outputs SARIF 2.1.0 format, compatible with GitHub Advanced Security, Azure DevOps, and other SARIF-compliant tools.
460
+ See [CI/CD Integration Guide](./docs/ci-integration.md) for GitHub Actions, GitLab CI, Azure DevOps, and escalation-gating examples.
734
461
 
735
462
  ---
736
463
 
@@ -785,6 +512,20 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
785
512
 
786
513
  ---
787
514
 
515
+ ## Documentation
516
+
517
+ | Document | Description |
518
+ |----------|-------------|
519
+ | [Roadmap](./ROADMAP.md) | Future plans and feature requests |
520
+ | [Contributing](./CONTRIBUTING.md) | How to get involved |
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 |
524
+ | [Upgrade Guide](./docs/release/UPGRADE.md) | v1.x → v2.0.0 migration |
525
+ | [CI/CD Integration](./docs/ci-integration.md) | GitHub Actions, GitLab CI, Azure DevOps examples |
526
+
527
+ ---
528
+
788
529
  ## License
789
530
 
790
531
  SafeAI is released under the Apache 2.0 License.