SafeAI-Static-Analyzer 1.9.0__tar.gz → 2.0.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.
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/PKG-INFO +29 -8
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/README.md +28 -7
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/SafeAI_Static_Analyzer.egg-info/PKG-INFO +29 -8
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/SafeAI_Static_Analyzer.egg-info/SOURCES.txt +15 -1
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/capability/analyzer.py +3 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/claude_code/analyzer.py +31 -10
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/data_leakage/analyzer.py +1 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/dataflow/analyzer.py +155 -6
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/env_dependency/analyzer.py +1 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/governance/analyzer.py +21 -1
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/mcp/analyzer.py +75 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/model_config/analyzer.py +1 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/prompt/analyzer.py +9 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/prompt_file/analyzer.py +1 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/skill/analyzer.py +1 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/tool_def/analyzer.py +1 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/workflow/analyzer.py +1 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/cmd/cli.py +55 -11
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/cmd/postprocess.py +4 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/controls/mappings.py +54 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/engine/orchestrator.py +3 -1
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/__init__.py +2 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/claude_code/permissions.py +130 -4
- safeai_static_analyzer-2.0.0/safeai/frameworks/cursorrules/parser.py +156 -0
- safeai_static_analyzer-2.0.0/safeai/frameworks/windsurf/parser.py +143 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/assurance.py +34 -0
- safeai_static_analyzer-2.0.0/safeai/report/failure_matrix.py +76 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/report/html.py +16 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/report/sarif.py +1 -0
- safeai_static_analyzer-2.0.0/safeai/rules/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/rules/base_rules.yaml +15 -0
- safeai_static_analyzer-2.0.0/safeai/scoring/__init__.py +0 -0
- safeai_static_analyzer-2.0.0/safeai/telemetry/__init__.py +8 -0
- safeai_static_analyzer-2.0.0/safeai/telemetry/client.py +57 -0
- safeai_static_analyzer-2.0.0/safeai/telemetry/config.py +150 -0
- safeai_static_analyzer-2.0.0/safeai/telemetry/schema.py +49 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/version.py +1 -1
- safeai_static_analyzer-2.0.0/tests/test_adapter_dataflow.py +378 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_claude_code_deep.py +127 -5
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_control_mappings.py +43 -0
- safeai_static_analyzer-2.0.0/tests/test_cursorrules_framework.py +112 -0
- safeai_static_analyzer-2.0.0/tests/test_evidence_type.py +86 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_governance_analyzer.py +80 -1
- safeai_static_analyzer-2.0.0/tests/test_mcp_tool_poisoning.py +147 -0
- safeai_static_analyzer-2.0.0/tests/test_telemetry.py +386 -0
- safeai_static_analyzer-2.0.0/tests/test_windsurf_framework.py +112 -0
- safeai_static_analyzer-1.9.0/tests/test_adapter_dataflow.py +0 -183
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/LICENSE +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/SafeAI_Static_Analyzer.egg-info/dependency_links.txt +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/SafeAI_Static_Analyzer.egg-info/entry_points.txt +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/SafeAI_Static_Analyzer.egg-info/requires.txt +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/SafeAI_Static_Analyzer.egg-info/top_level.txt +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/pyproject.toml +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/__main__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/aggregation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/capabilities.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/capability_diff.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/component_diff.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/component_graph.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/components.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/dependency_correlation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/escalation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/import_graph.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/project_graph.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/semantic.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/target_taxonomy.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/tool_identity.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/tool_implementation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analysis/tool_surface.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/capability/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/claude_code/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/data_leakage/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/dataflow/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/env_dependency/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/governance/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/mcp/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/mcp/compatibility.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/mcp/schema.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/mcp/validators.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/model_config/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/prompt/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/prompt_file/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/skill/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/tool_def/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/analyzers/workflow/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/cmd/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/cmd/registry_cli.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/controls/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/controls/catalogs.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/engine/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/engine/scan.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/autogen/parser.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/azure_foundry/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/azure_foundry/parser.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/bedrock_agent/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/bedrock_agent/parser.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/claude_code/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/claude_code/commands.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/claude_code/parser.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/claude_code/settings.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/crewai/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/crewai/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/dify → safeai_static_analyzer-2.0.0/safeai/frameworks/cursorrules}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/google_adk → safeai_static_analyzer-2.0.0/safeai/frameworks/dify}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/dify/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/haystack → safeai_static_analyzer-2.0.0/safeai/frameworks/google_adk}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/google_adk/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/langchain → safeai_static_analyzer-2.0.0/safeai/frameworks/haystack}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/haystack/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/langgraph → safeai_static_analyzer-2.0.0/safeai/frameworks/langchain}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/langchain/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/llamaindex → safeai_static_analyzer-2.0.0/safeai/frameworks/langgraph}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/langgraph/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/mastra → safeai_static_analyzer-2.0.0/safeai/frameworks/llamaindex}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/llamaindex/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/microsoft_agent → safeai_static_analyzer-2.0.0/safeai/frameworks/mastra}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/mastra/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/n8n → safeai_static_analyzer-2.0.0/safeai/frameworks/microsoft_agent}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/microsoft_agent/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/openai_agents → safeai_static_analyzer-2.0.0/safeai/frameworks/n8n}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/n8n/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/frameworks/semantic_kernel → safeai_static_analyzer-2.0.0/safeai/frameworks/openai_agents}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/openai_agents/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/report → safeai_static_analyzer-2.0.0/safeai/frameworks/semantic_kernel}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/frameworks/semantic_kernel/parser.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/rules → safeai_static_analyzer-2.0.0/safeai/frameworks/windsurf}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/baseline.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/ci_context.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/enrich.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/exporter.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/fingerprints.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/identity.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/manifest.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/policy.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/registry/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/registry/connection.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/registry/persist.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/registry/queries.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/registry/schema.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/suppressions.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/kya/util.py +0 -0
- {safeai_static_analyzer-1.9.0/safeai/scoring → safeai_static_analyzer-2.0.0/safeai/report}/__init__.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/report/html_kit.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/report/json_report.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/report/pr_comment.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/report/registry_html.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/report/terminal.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/rules/loader.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/scorecard.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/scoring/engine.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/safeai/severity.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/setup.cfg +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_assurance.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_baseline.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_capability_detection.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_capability_diff_v2.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_ci_context.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_component_graph.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_component_hash.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_confidence_arbitration.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_crewai_framework.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_env_dependency.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_escalation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_fingerprints.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_github_action.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_html_report.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_init_and_rules.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_kya_integration.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_kya_manifest.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_langgraph_framework.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_llamaindex_framework.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_mcp_validation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_n8n_workflow.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_parser_aggregation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_phase15.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_policy.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_pr_comment.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_pr_comment_cli.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_registry.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_registry_cli.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_registry_html.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_release_fixes.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_release_validation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_rules_loader_determinism.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_sarif.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_scan_phase11.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_scorecard.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_scoring.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_semantic.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_severity.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_suppressions.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_target_taxonomy_engine.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_tool_identity.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_tool_implementation.py +0 -0
- {safeai_static_analyzer-1.9.0 → safeai_static_analyzer-2.0.0}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SafeAI-Static-Analyzer
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.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
|
|
@@ -37,6 +37,8 @@ Dynamic: license-file
|
|
|
37
37
|
[](https://github.com/ikaruscareer/SafeAI/releases/tag/v1.9.0)
|
|
38
38
|
[](https://www.bestpractices.dev/en/projects/14126)
|
|
39
39
|
|
|
40
|
+
Enjoying SafeAI? A ⭐ on [GitHub](https://github.com/ikaruscareer/SafeAI) helps more security teams find it.
|
|
41
|
+
|
|
40
42
|
**SafeAI** is a static analysis tool that scans AI application source code for security risks, capability exposure, and governance gaps. It runs entirely offline, never executes agents or calls LLMs, and integrates into CI/CD pipelines.
|
|
41
43
|
|
|
42
44
|
> 🌐 [safeai-analyzer.ikaruscareer.com](https://safeai-analyzer.ikaruscareer.com) — project landing page
|
|
@@ -80,7 +82,7 @@ SafeAI sits before runtime guardrails and red-teaming tools in the security life
|
|
|
80
82
|
|
|
81
83
|
| Feature | Description |
|
|
82
84
|
|---------|-------------|
|
|
83
|
-
| **Framework Detection** | Detects and parses
|
|
85
|
+
| **Framework Detection** | Detects and parses 16 AI agent frameworks (AST + config + regex, no mutual exclusion) |
|
|
84
86
|
| **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 |
|
|
85
87
|
| **Capability Discovery** | Maps 19 capability categories (shell, filesystem, network, database, memory, MCP, ...) with evidence, confidence, and provenance |
|
|
86
88
|
| **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 |
|
|
@@ -116,7 +118,7 @@ File Collection — Python, YAML, JSON, .prompt, and .claude configs;
|
|
|
116
118
|
prunes VCS, caches, oversized files, and SafeAI's own artifacts
|
|
117
119
|
│
|
|
118
120
|
▼
|
|
119
|
-
Framework Detection —
|
|
121
|
+
Framework Detection — 16 parsers (AST + config + regex), all run on all files;
|
|
120
122
|
import graph and dependency manifests
|
|
121
123
|
│
|
|
122
124
|
▼
|
|
@@ -165,13 +167,14 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
|
|
|
165
167
|
| LlamaIndex | ✔ | Partial | Minimal | Minimal | Experimental |
|
|
166
168
|
| Dify | ✔ | Minimal | Minimal | Minimal | Experimental |
|
|
167
169
|
| n8n | ✔ | Partial | Minimal | Minimal | Experimental |
|
|
170
|
+
| Cursor (.cursorrules) | ✔ | Minimal | Minimal | Minimal | Experimental |
|
|
168
171
|
|
|
169
172
|
|
|
170
173
|
### Framework Support Details
|
|
171
174
|
|
|
172
175
|
- **LangGraph** — detects `StateGraph`, `add_edge`, `bind_tools`, nodes, models
|
|
173
176
|
- **CrewAI** — detects `Agent`, `Task`, tools, models
|
|
174
|
-
- **AutoGen** — detects `AssistantAgent`, `UserProxyAgent`, `register_for_llm`,
|
|
177
|
+
- **AutoGen** — detects `AssistantAgent`, `UserProxyAgent`, `register_for_llm`, `register_function`, models
|
|
175
178
|
- **LangChain** — detects `AgentExecutor`, `Chain`, `Tool`, `PromptTemplate`, models
|
|
176
179
|
- **Semantic Kernel** — detects `Kernel.invoke`, plugins, functions, skills, memory
|
|
177
180
|
- **OpenAI Agents SDK** — detects `Agent`, tools, handoffs, MCP references
|
|
@@ -186,6 +189,9 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
|
|
|
186
189
|
- **LlamaIndex** — detects agents, tools, indexes, and model references
|
|
187
190
|
- **Dify** — detects Dify workflow and agent configuration files
|
|
188
191
|
- **n8n** — detects n8n workflow exports, nodes, and connections
|
|
192
|
+
- **Cursor (.cursorrules)** — detects declared tools/permissions and
|
|
193
|
+
capability-relevant keywords (shell, filesystem, HTTP, database) in the
|
|
194
|
+
IDE's rules config, JSON, YAML, or free text
|
|
189
195
|
|
|
190
196
|
Maturity is on the scale defined in [`FRAMEWORK_SUPPORT.md`](FRAMEWORK_SUPPORT.md):
|
|
191
197
|
**Partial** = reliable detection and discovery with capability/risk analysis over
|
|
@@ -307,6 +313,12 @@ pip install -e ".[dev]"
|
|
|
307
313
|
|
|
308
314
|
---
|
|
309
315
|
|
|
316
|
+
## Privacy & Telemetry
|
|
317
|
+
|
|
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.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
310
322
|
## CLI Usage
|
|
311
323
|
|
|
312
324
|
```bash
|
|
@@ -755,10 +767,19 @@ See [ROADMAP.md](./ROADMAP.md) for the detailed roadmap.
|
|
|
755
767
|
SafeAI is built by and for the AI security community. Thank you to all
|
|
756
768
|
contributors who have helped make AI safer:
|
|
757
769
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
770
|
+
| Contributor | Key Contributions |
|
|
771
|
+
|-------------|-------------------|
|
|
772
|
+
| [@i-safonoff](https://github.com/i-safonoff) | `.cursorrules` framework adapter, `rule_coverage_summary()`, RULES_REFERENCE.md, dataflow casing fix |
|
|
773
|
+
| [@ARAVIND281](https://github.com/ARAVIND281) | Claude Code permission evaluation order, interprocedural data-flow tracking |
|
|
774
|
+
| [@Solarthis](https://github.com/Solarthis) | MCP tool description injection detection |
|
|
775
|
+
| [@Aming9303](https://github.com/Aming9303) | `safeai registry components` CLI, `safeai init` command, GitHub Actions example |
|
|
776
|
+
| [@adnqcr7-code](https://github.com/adnqcr7-code) | Framework detection tests (LangGraph, CrewAI, LlamaIndex, n8n, Claude Code), CI/SARIF docs |
|
|
777
|
+
| [@hadbiaghiles](https://github.com/hadbiaghiles) | AutoGen framework documentation |
|
|
778
|
+
| [@D05TL3](https://github.com/D05TL3) | GitHub Actions scanning example |
|
|
779
|
+
| [@mikemikimike](https://github.com/mikemikimike) | Adapter negative detection tests |
|
|
780
|
+
| [@mah](https://github.com/mahirhir) | Claude Code deep analysis documentation |
|
|
781
|
+
| [@asarakhatun17-lgtm](https://github.com/asarakhatun17-lgtm) | Supported frameworks consistency fix |
|
|
782
|
+
| [@yugaaank](https://github.com/yugaaank) | Capability detectors (Docker, Kubernetes, Redis, S3, GCP, Slack, Jira, browser) |
|
|
762
783
|
|
|
763
784
|
See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
|
|
764
785
|
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
[](https://github.com/ikaruscareer/SafeAI/releases/tag/v1.9.0)
|
|
7
7
|
[](https://www.bestpractices.dev/en/projects/14126)
|
|
8
8
|
|
|
9
|
+
Enjoying SafeAI? A ⭐ on [GitHub](https://github.com/ikaruscareer/SafeAI) helps more security teams find it.
|
|
10
|
+
|
|
9
11
|
**SafeAI** is a static analysis tool that scans AI application source code for security risks, capability exposure, and governance gaps. It runs entirely offline, never executes agents or calls LLMs, and integrates into CI/CD pipelines.
|
|
10
12
|
|
|
11
13
|
> 🌐 [safeai-analyzer.ikaruscareer.com](https://safeai-analyzer.ikaruscareer.com) — project landing page
|
|
@@ -49,7 +51,7 @@ SafeAI sits before runtime guardrails and red-teaming tools in the security life
|
|
|
49
51
|
|
|
50
52
|
| Feature | Description |
|
|
51
53
|
|---------|-------------|
|
|
52
|
-
| **Framework Detection** | Detects and parses
|
|
54
|
+
| **Framework Detection** | Detects and parses 16 AI agent frameworks (AST + config + regex, no mutual exclusion) |
|
|
53
55
|
| **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 |
|
|
54
56
|
| **Capability Discovery** | Maps 19 capability categories (shell, filesystem, network, database, memory, MCP, ...) with evidence, confidence, and provenance |
|
|
55
57
|
| **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 |
|
|
@@ -85,7 +87,7 @@ File Collection — Python, YAML, JSON, .prompt, and .claude configs;
|
|
|
85
87
|
prunes VCS, caches, oversized files, and SafeAI's own artifacts
|
|
86
88
|
│
|
|
87
89
|
▼
|
|
88
|
-
Framework Detection —
|
|
90
|
+
Framework Detection — 16 parsers (AST + config + regex), all run on all files;
|
|
89
91
|
import graph and dependency manifests
|
|
90
92
|
│
|
|
91
93
|
▼
|
|
@@ -134,13 +136,14 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
|
|
|
134
136
|
| LlamaIndex | ✔ | Partial | Minimal | Minimal | Experimental |
|
|
135
137
|
| Dify | ✔ | Minimal | Minimal | Minimal | Experimental |
|
|
136
138
|
| n8n | ✔ | Partial | Minimal | Minimal | Experimental |
|
|
139
|
+
| Cursor (.cursorrules) | ✔ | Minimal | Minimal | Minimal | Experimental |
|
|
137
140
|
|
|
138
141
|
|
|
139
142
|
### Framework Support Details
|
|
140
143
|
|
|
141
144
|
- **LangGraph** — detects `StateGraph`, `add_edge`, `bind_tools`, nodes, models
|
|
142
145
|
- **CrewAI** — detects `Agent`, `Task`, tools, models
|
|
143
|
-
- **AutoGen** — detects `AssistantAgent`, `UserProxyAgent`, `register_for_llm`,
|
|
146
|
+
- **AutoGen** — detects `AssistantAgent`, `UserProxyAgent`, `register_for_llm`, `register_function`, models
|
|
144
147
|
- **LangChain** — detects `AgentExecutor`, `Chain`, `Tool`, `PromptTemplate`, models
|
|
145
148
|
- **Semantic Kernel** — detects `Kernel.invoke`, plugins, functions, skills, memory
|
|
146
149
|
- **OpenAI Agents SDK** — detects `Agent`, tools, handoffs, MCP references
|
|
@@ -155,6 +158,9 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
|
|
|
155
158
|
- **LlamaIndex** — detects agents, tools, indexes, and model references
|
|
156
159
|
- **Dify** — detects Dify workflow and agent configuration files
|
|
157
160
|
- **n8n** — detects n8n workflow exports, nodes, and connections
|
|
161
|
+
- **Cursor (.cursorrules)** — detects declared tools/permissions and
|
|
162
|
+
capability-relevant keywords (shell, filesystem, HTTP, database) in the
|
|
163
|
+
IDE's rules config, JSON, YAML, or free text
|
|
158
164
|
|
|
159
165
|
Maturity is on the scale defined in [`FRAMEWORK_SUPPORT.md`](FRAMEWORK_SUPPORT.md):
|
|
160
166
|
**Partial** = reliable detection and discovery with capability/risk analysis over
|
|
@@ -276,6 +282,12 @@ pip install -e ".[dev]"
|
|
|
276
282
|
|
|
277
283
|
---
|
|
278
284
|
|
|
285
|
+
## Privacy & Telemetry
|
|
286
|
+
|
|
287
|
+
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.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
279
291
|
## CLI Usage
|
|
280
292
|
|
|
281
293
|
```bash
|
|
@@ -724,10 +736,19 @@ See [ROADMAP.md](./ROADMAP.md) for the detailed roadmap.
|
|
|
724
736
|
SafeAI is built by and for the AI security community. Thank you to all
|
|
725
737
|
contributors who have helped make AI safer:
|
|
726
738
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
739
|
+
| Contributor | Key Contributions |
|
|
740
|
+
|-------------|-------------------|
|
|
741
|
+
| [@i-safonoff](https://github.com/i-safonoff) | `.cursorrules` framework adapter, `rule_coverage_summary()`, RULES_REFERENCE.md, dataflow casing fix |
|
|
742
|
+
| [@ARAVIND281](https://github.com/ARAVIND281) | Claude Code permission evaluation order, interprocedural data-flow tracking |
|
|
743
|
+
| [@Solarthis](https://github.com/Solarthis) | MCP tool description injection detection |
|
|
744
|
+
| [@Aming9303](https://github.com/Aming9303) | `safeai registry components` CLI, `safeai init` command, GitHub Actions example |
|
|
745
|
+
| [@adnqcr7-code](https://github.com/adnqcr7-code) | Framework detection tests (LangGraph, CrewAI, LlamaIndex, n8n, Claude Code), CI/SARIF docs |
|
|
746
|
+
| [@hadbiaghiles](https://github.com/hadbiaghiles) | AutoGen framework documentation |
|
|
747
|
+
| [@D05TL3](https://github.com/D05TL3) | GitHub Actions scanning example |
|
|
748
|
+
| [@mikemikimike](https://github.com/mikemikimike) | Adapter negative detection tests |
|
|
749
|
+
| [@mah](https://github.com/mahirhir) | Claude Code deep analysis documentation |
|
|
750
|
+
| [@asarakhatun17-lgtm](https://github.com/asarakhatun17-lgtm) | Supported frameworks consistency fix |
|
|
751
|
+
| [@yugaaank](https://github.com/yugaaank) | Capability detectors (Docker, Kubernetes, Redis, S3, GCP, Slack, Jira, browser) |
|
|
731
752
|
|
|
732
753
|
See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
|
|
733
754
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SafeAI-Static-Analyzer
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.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
|
|
@@ -37,6 +37,8 @@ Dynamic: license-file
|
|
|
37
37
|
[](https://github.com/ikaruscareer/SafeAI/releases/tag/v1.9.0)
|
|
38
38
|
[](https://www.bestpractices.dev/en/projects/14126)
|
|
39
39
|
|
|
40
|
+
Enjoying SafeAI? A ⭐ on [GitHub](https://github.com/ikaruscareer/SafeAI) helps more security teams find it.
|
|
41
|
+
|
|
40
42
|
**SafeAI** is a static analysis tool that scans AI application source code for security risks, capability exposure, and governance gaps. It runs entirely offline, never executes agents or calls LLMs, and integrates into CI/CD pipelines.
|
|
41
43
|
|
|
42
44
|
> 🌐 [safeai-analyzer.ikaruscareer.com](https://safeai-analyzer.ikaruscareer.com) — project landing page
|
|
@@ -80,7 +82,7 @@ SafeAI sits before runtime guardrails and red-teaming tools in the security life
|
|
|
80
82
|
|
|
81
83
|
| Feature | Description |
|
|
82
84
|
|---------|-------------|
|
|
83
|
-
| **Framework Detection** | Detects and parses
|
|
85
|
+
| **Framework Detection** | Detects and parses 16 AI agent frameworks (AST + config + regex, no mutual exclusion) |
|
|
84
86
|
| **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 |
|
|
85
87
|
| **Capability Discovery** | Maps 19 capability categories (shell, filesystem, network, database, memory, MCP, ...) with evidence, confidence, and provenance |
|
|
86
88
|
| **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 |
|
|
@@ -116,7 +118,7 @@ File Collection — Python, YAML, JSON, .prompt, and .claude configs;
|
|
|
116
118
|
prunes VCS, caches, oversized files, and SafeAI's own artifacts
|
|
117
119
|
│
|
|
118
120
|
▼
|
|
119
|
-
Framework Detection —
|
|
121
|
+
Framework Detection — 16 parsers (AST + config + regex), all run on all files;
|
|
120
122
|
import graph and dependency manifests
|
|
121
123
|
│
|
|
122
124
|
▼
|
|
@@ -165,13 +167,14 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
|
|
|
165
167
|
| LlamaIndex | ✔ | Partial | Minimal | Minimal | Experimental |
|
|
166
168
|
| Dify | ✔ | Minimal | Minimal | Minimal | Experimental |
|
|
167
169
|
| n8n | ✔ | Partial | Minimal | Minimal | Experimental |
|
|
170
|
+
| Cursor (.cursorrules) | ✔ | Minimal | Minimal | Minimal | Experimental |
|
|
168
171
|
|
|
169
172
|
|
|
170
173
|
### Framework Support Details
|
|
171
174
|
|
|
172
175
|
- **LangGraph** — detects `StateGraph`, `add_edge`, `bind_tools`, nodes, models
|
|
173
176
|
- **CrewAI** — detects `Agent`, `Task`, tools, models
|
|
174
|
-
- **AutoGen** — detects `AssistantAgent`, `UserProxyAgent`, `register_for_llm`,
|
|
177
|
+
- **AutoGen** — detects `AssistantAgent`, `UserProxyAgent`, `register_for_llm`, `register_function`, models
|
|
175
178
|
- **LangChain** — detects `AgentExecutor`, `Chain`, `Tool`, `PromptTemplate`, models
|
|
176
179
|
- **Semantic Kernel** — detects `Kernel.invoke`, plugins, functions, skills, memory
|
|
177
180
|
- **OpenAI Agents SDK** — detects `Agent`, tools, handoffs, MCP references
|
|
@@ -186,6 +189,9 @@ Registry & Reports — shared SQLite registry; terminal, JSON, SARIF 2.1.0, HTML
|
|
|
186
189
|
- **LlamaIndex** — detects agents, tools, indexes, and model references
|
|
187
190
|
- **Dify** — detects Dify workflow and agent configuration files
|
|
188
191
|
- **n8n** — detects n8n workflow exports, nodes, and connections
|
|
192
|
+
- **Cursor (.cursorrules)** — detects declared tools/permissions and
|
|
193
|
+
capability-relevant keywords (shell, filesystem, HTTP, database) in the
|
|
194
|
+
IDE's rules config, JSON, YAML, or free text
|
|
189
195
|
|
|
190
196
|
Maturity is on the scale defined in [`FRAMEWORK_SUPPORT.md`](FRAMEWORK_SUPPORT.md):
|
|
191
197
|
**Partial** = reliable detection and discovery with capability/risk analysis over
|
|
@@ -307,6 +313,12 @@ pip install -e ".[dev]"
|
|
|
307
313
|
|
|
308
314
|
---
|
|
309
315
|
|
|
316
|
+
## Privacy & Telemetry
|
|
317
|
+
|
|
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.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
310
322
|
## CLI Usage
|
|
311
323
|
|
|
312
324
|
```bash
|
|
@@ -755,10 +767,19 @@ See [ROADMAP.md](./ROADMAP.md) for the detailed roadmap.
|
|
|
755
767
|
SafeAI is built by and for the AI security community. Thank you to all
|
|
756
768
|
contributors who have helped make AI safer:
|
|
757
769
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
770
|
+
| Contributor | Key Contributions |
|
|
771
|
+
|-------------|-------------------|
|
|
772
|
+
| [@i-safonoff](https://github.com/i-safonoff) | `.cursorrules` framework adapter, `rule_coverage_summary()`, RULES_REFERENCE.md, dataflow casing fix |
|
|
773
|
+
| [@ARAVIND281](https://github.com/ARAVIND281) | Claude Code permission evaluation order, interprocedural data-flow tracking |
|
|
774
|
+
| [@Solarthis](https://github.com/Solarthis) | MCP tool description injection detection |
|
|
775
|
+
| [@Aming9303](https://github.com/Aming9303) | `safeai registry components` CLI, `safeai init` command, GitHub Actions example |
|
|
776
|
+
| [@adnqcr7-code](https://github.com/adnqcr7-code) | Framework detection tests (LangGraph, CrewAI, LlamaIndex, n8n, Claude Code), CI/SARIF docs |
|
|
777
|
+
| [@hadbiaghiles](https://github.com/hadbiaghiles) | AutoGen framework documentation |
|
|
778
|
+
| [@D05TL3](https://github.com/D05TL3) | GitHub Actions scanning example |
|
|
779
|
+
| [@mikemikimike](https://github.com/mikemikimike) | Adapter negative detection tests |
|
|
780
|
+
| [@mah](https://github.com/mahirhir) | Claude Code deep analysis documentation |
|
|
781
|
+
| [@asarakhatun17-lgtm](https://github.com/asarakhatun17-lgtm) | Supported frameworks consistency fix |
|
|
782
|
+
| [@yugaaank](https://github.com/yugaaank) | Capability detectors (Docker, Kubernetes, Redis, S3, GCP, Slack, Jira, browser) |
|
|
762
783
|
|
|
763
784
|
See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
|
|
764
785
|
|
|
@@ -81,6 +81,8 @@ safeai/frameworks/claude_code/permissions.py
|
|
|
81
81
|
safeai/frameworks/claude_code/settings.py
|
|
82
82
|
safeai/frameworks/crewai/__init__.py
|
|
83
83
|
safeai/frameworks/crewai/parser.py
|
|
84
|
+
safeai/frameworks/cursorrules/__init__.py
|
|
85
|
+
safeai/frameworks/cursorrules/parser.py
|
|
84
86
|
safeai/frameworks/dify/__init__.py
|
|
85
87
|
safeai/frameworks/dify/parser.py
|
|
86
88
|
safeai/frameworks/google_adk/__init__.py
|
|
@@ -103,6 +105,8 @@ safeai/frameworks/openai_agents/__init__.py
|
|
|
103
105
|
safeai/frameworks/openai_agents/parser.py
|
|
104
106
|
safeai/frameworks/semantic_kernel/__init__.py
|
|
105
107
|
safeai/frameworks/semantic_kernel/parser.py
|
|
108
|
+
safeai/frameworks/windsurf/__init__.py
|
|
109
|
+
safeai/frameworks/windsurf/parser.py
|
|
106
110
|
safeai/kya/__init__.py
|
|
107
111
|
safeai/kya/assurance.py
|
|
108
112
|
safeai/kya/baseline.py
|
|
@@ -121,6 +125,7 @@ safeai/kya/registry/persist.py
|
|
|
121
125
|
safeai/kya/registry/queries.py
|
|
122
126
|
safeai/kya/registry/schema.py
|
|
123
127
|
safeai/report/__init__.py
|
|
128
|
+
safeai/report/failure_matrix.py
|
|
124
129
|
safeai/report/html.py
|
|
125
130
|
safeai/report/html_kit.py
|
|
126
131
|
safeai/report/json_report.py
|
|
@@ -133,6 +138,10 @@ safeai/rules/base_rules.yaml
|
|
|
133
138
|
safeai/rules/loader.py
|
|
134
139
|
safeai/scoring/__init__.py
|
|
135
140
|
safeai/scoring/engine.py
|
|
141
|
+
safeai/telemetry/__init__.py
|
|
142
|
+
safeai/telemetry/client.py
|
|
143
|
+
safeai/telemetry/config.py
|
|
144
|
+
safeai/telemetry/schema.py
|
|
136
145
|
tests/test_adapter_dataflow.py
|
|
137
146
|
tests/test_assurance.py
|
|
138
147
|
tests/test_baseline.py
|
|
@@ -145,8 +154,10 @@ tests/test_component_hash.py
|
|
|
145
154
|
tests/test_confidence_arbitration.py
|
|
146
155
|
tests/test_control_mappings.py
|
|
147
156
|
tests/test_crewai_framework.py
|
|
157
|
+
tests/test_cursorrules_framework.py
|
|
148
158
|
tests/test_env_dependency.py
|
|
149
159
|
tests/test_escalation.py
|
|
160
|
+
tests/test_evidence_type.py
|
|
150
161
|
tests/test_fingerprints.py
|
|
151
162
|
tests/test_github_action.py
|
|
152
163
|
tests/test_governance_analyzer.py
|
|
@@ -156,6 +167,7 @@ tests/test_kya_integration.py
|
|
|
156
167
|
tests/test_kya_manifest.py
|
|
157
168
|
tests/test_langgraph_framework.py
|
|
158
169
|
tests/test_llamaindex_framework.py
|
|
170
|
+
tests/test_mcp_tool_poisoning.py
|
|
159
171
|
tests/test_mcp_validation.py
|
|
160
172
|
tests/test_n8n_workflow.py
|
|
161
173
|
tests/test_parser_aggregation.py
|
|
@@ -177,6 +189,8 @@ tests/test_semantic.py
|
|
|
177
189
|
tests/test_severity.py
|
|
178
190
|
tests/test_suppressions.py
|
|
179
191
|
tests/test_target_taxonomy_engine.py
|
|
192
|
+
tests/test_telemetry.py
|
|
180
193
|
tests/test_tool_identity.py
|
|
181
194
|
tests/test_tool_implementation.py
|
|
182
|
-
tests/test_version.py
|
|
195
|
+
tests/test_version.py
|
|
196
|
+
tests/test_windsurf_framework.py
|
|
@@ -72,6 +72,7 @@ CATEGORY_BY_CAP = {
|
|
|
72
72
|
def _finding(rule_id, rule, message, path, line, capability, framework="generic", evidence=None, confidence=0.6, score_contribution=8):
|
|
73
73
|
return {
|
|
74
74
|
"rule_id": rule_id,
|
|
75
|
+
"evidence_type": "static-pattern", # #94 - regex fallback pass over raw file content
|
|
75
76
|
"severity": rule.get("severity", "medium"),
|
|
76
77
|
"message": message,
|
|
77
78
|
"file": path,
|
|
@@ -160,6 +161,7 @@ class CapabilityAnalyzer:
|
|
|
160
161
|
|
|
161
162
|
findings.append({
|
|
162
163
|
"rule_id": rule_id,
|
|
164
|
+
"evidence_type": "static-pattern", # #94 - regex fallback pass over raw file content
|
|
163
165
|
"severity": rule.get("severity", "medium"),
|
|
164
166
|
"message": f"Capability discovered: {cap_name}",
|
|
165
167
|
"file": path,
|
|
@@ -249,6 +251,7 @@ class CapabilityAnalyzer:
|
|
|
249
251
|
rule = rule_map.get("CAP_AUTONOMY", {})
|
|
250
252
|
findings.append({
|
|
251
253
|
"rule_id": "CAP_AUTONOMY",
|
|
254
|
+
"evidence_type": "static-pattern", # #94 - regex fallback pass over raw file content
|
|
252
255
|
"severity": rule.get("severity", "high"),
|
|
253
256
|
"message": "Potential autonomous agent loop detected",
|
|
254
257
|
"file": path,
|
|
@@ -22,8 +22,9 @@ _REMEDIATION = {
|
|
|
22
22
|
"command or path pattern the workflow needs.",
|
|
23
23
|
"CC_BYPASS_PERMISSIONS": "Remove the bypass/auto-approve setting and keep the "
|
|
24
24
|
"human approval gate enabled in committed settings.",
|
|
25
|
-
"CC_DENY_SHADOWED": "
|
|
26
|
-
"
|
|
25
|
+
"CC_DENY_SHADOWED": "Remove the allow entry that cannot apply, or narrow the "
|
|
26
|
+
"deny entry if the allow was the intended behaviour. The "
|
|
27
|
+
"deny is what takes effect.",
|
|
27
28
|
"CC_FS_WRITE_OUTSIDE_ROOT": "Constrain write grants to paths inside the project root.",
|
|
28
29
|
"CC_SLASH_COMMAND_SHELL": "Pin the command, avoid inline shell in stored "
|
|
29
30
|
"instructions, and review who can invoke it.",
|
|
@@ -98,6 +99,7 @@ def _finding(rule_id, rule_map, message, path, line, evidence, reason, severity=
|
|
|
98
99
|
resolved = severity or rule.get("severity") or _DEFAULT_SEVERITY.get(rule_id, "medium")
|
|
99
100
|
return {
|
|
100
101
|
"rule_id": rule_id,
|
|
102
|
+
"evidence_type": "static-config", # #94 - reads declared permission/hook/settings entries
|
|
101
103
|
"severity": resolved,
|
|
102
104
|
"message": message,
|
|
103
105
|
"file": path,
|
|
@@ -204,15 +206,27 @@ class ClaudeCodeAnalyzer:
|
|
|
204
206
|
|
|
205
207
|
def _permission_findings(self, records, rule_map):
|
|
206
208
|
findings = []
|
|
209
|
+
effective = cc_permissions.resolve_effective_rules(records)
|
|
207
210
|
for record in records:
|
|
208
211
|
if record["decision"] == "allow" and record["wildcard"] and record["tool"]:
|
|
212
|
+
# #93 - a wildcard allow grants nothing the tool's denies do not
|
|
213
|
+
# already take back, at any scope. Report it, but not as though
|
|
214
|
+
# the surface were unbounded when it demonstrably is not.
|
|
215
|
+
constrained = effective.get(str(record["tool"]).lower(), {}).get("decision") == "deny"
|
|
209
216
|
findings.append(_finding(
|
|
210
217
|
"CC_WILDCARD_PERMISSION", rule_map,
|
|
211
218
|
f"Unconstrained Claude Code permission: {record['entry']}",
|
|
212
219
|
record["path"], record["line"],
|
|
213
220
|
evidence=record["entry"],
|
|
214
|
-
reason=
|
|
215
|
-
|
|
221
|
+
reason=(
|
|
222
|
+
f"{record['tool']} is allowed with no argument constraint, but a deny "
|
|
223
|
+
f"rule for the same tool is evaluated first, so the granted surface is "
|
|
224
|
+
f"bounded by that deny."
|
|
225
|
+
if constrained else
|
|
226
|
+
f"{record['tool']} is allowed with no argument constraint, granting "
|
|
227
|
+
f"{record['access_mode']} authority over its entire surface."
|
|
228
|
+
),
|
|
229
|
+
severity="medium" if constrained else None,
|
|
216
230
|
))
|
|
217
231
|
if cc_permissions.writes_outside_root(record):
|
|
218
232
|
findings.append(_finding(
|
|
@@ -225,14 +239,21 @@ class ClaudeCodeAnalyzer:
|
|
|
225
239
|
capability="Filesystem",
|
|
226
240
|
))
|
|
227
241
|
|
|
228
|
-
|
|
242
|
+
# #93 - this finding used to be stated the wrong way round. Claude Code
|
|
243
|
+
# evaluates deny, then ask, then allow, and "rule specificity doesn't
|
|
244
|
+
# change the order", so a matching deny ALWAYS decides the call. It is
|
|
245
|
+
# the allow that is dead configuration, not the deny, and the severity
|
|
246
|
+
# follows: contradictory rules are a maintenance problem, not a hole.
|
|
247
|
+
for allow, deny in cc_permissions.ineffective_allows(records):
|
|
229
248
|
findings.append(_finding(
|
|
230
249
|
"CC_DENY_SHADOWED", rule_map,
|
|
231
|
-
f"
|
|
232
|
-
|
|
233
|
-
evidence=f"
|
|
234
|
-
reason="
|
|
235
|
-
"
|
|
250
|
+
f"Allow entry can never apply, a deny covers it: {allow['entry']}",
|
|
251
|
+
allow["path"], allow["line"],
|
|
252
|
+
evidence=f"allow {allow['entry']} overridden by deny {deny['entry']}",
|
|
253
|
+
reason="Claude Code evaluates deny before allow and specificity does not change "
|
|
254
|
+
"that, so the deny decides every matching call and this allow widens "
|
|
255
|
+
"nothing. The deny is effective; the allow is dead configuration.",
|
|
256
|
+
severity="low",
|
|
236
257
|
))
|
|
237
258
|
return findings
|
|
238
259
|
|