actshield 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- actshield/__init__.py +439 -0
- actshield/__main__.py +46 -0
- actshield/agents/__init__.py +12 -0
- actshield/agents/agent.py +200 -0
- actshield/agents/identity.py +114 -0
- actshield/api/__init__.py +34 -0
- actshield/api/models.py +198 -0
- actshield/api/server.py +669 -0
- actshield/api/service.py +599 -0
- actshield/approval/__init__.py +15 -0
- actshield/approval/approval.py +164 -0
- actshield/cli/__init__.py +8 -0
- actshield/cli/graph.py +49 -0
- actshield/cli/main.py +802 -0
- actshield/cli/shell.py +406 -0
- actshield/cli/theme.py +110 -0
- actshield/client.py +757 -0
- actshield/config.py +88 -0
- actshield/context/__init__.py +14 -0
- actshield/context/context.py +161 -0
- actshield/context/provenance.py +108 -0
- actshield/context/taint.py +48 -0
- actshield/decisions/decision.py +74 -0
- actshield/delegation/__init__.py +11 -0
- actshield/delegation/authority.py +63 -0
- actshield/delegation/delegation.py +180 -0
- actshield/demo.py +139 -0
- actshield/doctor.py +94 -0
- actshield/drift/__init__.py +27 -0
- actshield/drift/drift_engine.py +149 -0
- actshield/drift/drift_models.py +63 -0
- actshield/evaluation/__init__.py +1 -0
- actshield/evaluation/cases/__init__.py +1 -0
- actshield/evaluation/eval_suite.py +254 -0
- actshield/forensics/__init__.py +53 -0
- actshield/forensics/access_graph.py +216 -0
- actshield/forensics/authority_graph.py +186 -0
- actshield/forensics/delegation_graph.py +119 -0
- actshield/forensics/explanation.py +254 -0
- actshield/forensics/models.py +488 -0
- actshield/forensics/queries.py +367 -0
- actshield/forensics/serializers.py +68 -0
- actshield/forensics/service.py +310 -0
- actshield/forensics/snapshots.py +174 -0
- actshield/gates/__init__.py +13 -0
- actshield/gates/gate_models.py +46 -0
- actshield/gates/security_gate.py +191 -0
- actshield/gateway/__init__.py +13 -0
- actshield/gateway/http.py +191 -0
- actshield/gateway/mcp.py +292 -0
- actshield/incidents/__init__.py +25 -0
- actshield/incidents/incident.py +94 -0
- actshield/incidents/incident_engine.py +163 -0
- actshield/incidents/incident_rules.py +116 -0
- actshield/incidents/incident_state.py +58 -0
- actshield/integrations/__init__.py +24 -0
- actshield/integrations/ai_secura.py +169 -0
- actshield/integrations/ai_secura_analysis.py +236 -0
- actshield/integrations/apiris.py +122 -0
- actshield/integrations/few_shot.py +104 -0
- actshield/integrations/ollama_adapter.py +538 -0
- actshield/integrations/prompts/__init__.py +1 -0
- actshield/integrations/prompts/examples/__init__.py +1 -0
- actshield/integrations/security_packet.py +82 -0
- actshield/llm_config.py +89 -0
- actshield/offensive/__init__.py +95 -0
- actshield/offensive/adaptive/__init__.py +22 -0
- actshield/offensive/adaptive/adaptive_engine.py +165 -0
- actshield/offensive/adaptive/attack_selector.py +51 -0
- actshield/offensive/adaptive/boundary_search.py +99 -0
- actshield/offensive/adaptive/campaign_memory.py +123 -0
- actshield/offensive/adaptive/feedback.py +84 -0
- actshield/offensive/adaptive/mutation_planner.py +57 -0
- actshield/offensive/attack.py +78 -0
- actshield/offensive/campaign.py +219 -0
- actshield/offensive/corpus.py +155 -0
- actshield/offensive/engine.py +466 -0
- actshield/offensive/evaluator.py +116 -0
- actshield/offensive/evidence.py +63 -0
- actshield/offensive/generator.py +128 -0
- actshield/offensive/mutation.py +101 -0
- actshield/offensive/results.py +77 -0
- actshield/offensive/safety.py +80 -0
- actshield/offensive/strategies/__init__.py +22 -0
- actshield/offensive/strategies/authority_escalation.py +100 -0
- actshield/offensive/strategies/base.py +34 -0
- actshield/offensive/strategies/context_manipulation.py +100 -0
- actshield/offensive/strategies/data_exfiltration.py +100 -0
- actshield/offensive/strategies/delegation_attacks.py +100 -0
- actshield/offensive/strategies/mcp_attacks.py +100 -0
- actshield/offensive/strategies/prompt_injection.py +100 -0
- actshield/offensive/strategies/tool_poisoning.py +100 -0
- actshield/offensive/target.py +113 -0
- actshield/offensive/vulnerable_target.py +121 -0
- actshield/persistence/__init__.py +18 -0
- actshield/persistence/siem.py +102 -0
- actshield/persistence/storage.py +240 -0
- actshield/policy/__init__.py +12 -0
- actshield/policy/evaluator.py +294 -0
- actshield/policy/intent.py +113 -0
- actshield/policy/policy.py +48 -0
- actshield/posture/__init__.py +26 -0
- actshield/posture/posture_engine.py +186 -0
- actshield/posture/posture_models.py +152 -0
- actshield/posture/posture_rules.py +137 -0
- actshield/providers/__init__.py +32 -0
- actshield/providers/anthropic_provider.py +146 -0
- actshield/providers/base.py +160 -0
- actshield/providers/gemini_provider.py +133 -0
- actshield/providers/null_provider.py +40 -0
- actshield/providers/ollama_provider.py +135 -0
- actshield/providers/openai_provider.py +142 -0
- actshield/providers/registry.py +244 -0
- actshield/py.typed +0 -0
- actshield/response/__init__.py +14 -0
- actshield/response/response_actions.py +39 -0
- actshield/response/response_audit.py +32 -0
- actshield/response/response_engine.py +139 -0
- actshield/risk/models.py +104 -0
- actshield/serve.py +117 -0
- actshield/static/404.html +1 -0
- actshield/static/__next.__PAGE__.txt +24 -0
- actshield/static/__next._full.txt +20 -0
- actshield/static/__next._tree.txt +4 -0
- actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_buildManifest.js +11 -0
- actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_clientMiddlewareManifest.js +1 -0
- actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_ssgManifest.js +1 -0
- actshield/static/_next/static/chunks/09kny2eqjc2or.js +1 -0
- actshield/static/_next/static/chunks/0c1zba1u9whdp.js +1 -0
- actshield/static/_next/static/chunks/0cz1d0mv5g_q7.js +1 -0
- actshield/static/_next/static/chunks/0dbjjeg01x25o.js +1 -0
- actshield/static/_next/static/chunks/0duobs55ne238.js +1 -0
- actshield/static/_next/static/chunks/0iaz41l6068e4.js +1 -0
- actshield/static/_next/static/chunks/0mjhyv72x2idp.js +1 -0
- actshield/static/_next/static/chunks/0nelpqfu_ciq6.js +1 -0
- actshield/static/_next/static/chunks/0p1bci9ch797v.js +1 -0
- actshield/static/_next/static/chunks/0tld_ygho5tgm.js +1 -0
- actshield/static/_next/static/chunks/0w1-y7oni66j9.js +1 -0
- actshield/static/_next/static/chunks/10537zyl427zj.js +1 -0
- actshield/static/_next/static/chunks/11pc_jkl3aggn.js +1 -0
- actshield/static/_next/static/chunks/16k7nw0b3t8ys.js +1 -0
- actshield/static/_next/static/chunks/19mx3mg6lkumu.js +1 -0
- actshield/static/_next/static/chunks/1_8p47b-kxg2a.js +1 -0
- actshield/static/_next/static/chunks/1dszjozwfqegx.js +1 -0
- actshield/static/_next/static/chunks/1h43jcb90-m2r.js +22 -0
- actshield/static/_next/static/chunks/1ly04cvt_wh_j.js +1 -0
- actshield/static/_next/static/chunks/1odxrypuwuwp_.js +1 -0
- actshield/static/_next/static/chunks/1oes4c35qz5ku.js +1 -0
- actshield/static/_next/static/chunks/1ow883jl4ln-r.js +16 -0
- actshield/static/_next/static/chunks/1po7bna1as8tc.js +1 -0
- actshield/static/_next/static/chunks/1rsh0og8ifkzx.js +1 -0
- actshield/static/_next/static/chunks/1v0lwzv-859z_.js +1 -0
- actshield/static/_next/static/chunks/25iat2epwx25a.js +1 -0
- actshield/static/_next/static/chunks/25uvt4s2f39a4.js +1 -0
- actshield/static/_next/static/chunks/27t_qfc-3_lzs.js +1 -0
- actshield/static/_next/static/chunks/28bkmy8mez7gm.js +1 -0
- actshield/static/_next/static/chunks/2b6brmw_drw1p.js +1 -0
- actshield/static/_next/static/chunks/2fnhtxi4j6vge.js +1 -0
- actshield/static/_next/static/chunks/2p087eftxemg4.js +6 -0
- actshield/static/_next/static/chunks/2s8pao_z8pgtq.js +1 -0
- actshield/static/_next/static/chunks/2yj7ooc2c-zpg.js +1 -0
- actshield/static/_next/static/chunks/3-mrrr8udt5tk.js +1 -0
- actshield/static/_next/static/chunks/310vm2bl3xxpt.js +31 -0
- actshield/static/_next/static/chunks/35mvsv251jx1r.css +3 -0
- actshield/static/_next/static/chunks/370vf0oetlsx9.js +1 -0
- actshield/static/_next/static/chunks/3e-2m72tyo556.js +1 -0
- actshield/static/_next/static/chunks/3fntmmi971322.js +1 -0
- actshield/static/_next/static/chunks/3fzw-g0hycl2c.js +1 -0
- actshield/static/_next/static/chunks/3lopq3lhmcjxg.js +129 -0
- actshield/static/_next/static/chunks/3mpe2jejel0v2.css +1 -0
- actshield/static/_next/static/chunks/3t8o4f2lzr2sf.js +1 -0
- actshield/static/_next/static/chunks/3y-v1neyllne5.js +1 -0
- actshield/static/_next/static/chunks/43oiwy8mx6cs1.js +1 -0
- actshield/static/_next/static/chunks/turbopack-23wzuebcy_lxm.js +1 -0
- actshield/static/_next/static/media/1bffadaabf893a1e-s.3-6t-g6q0vh0a.woff2 +0 -0
- actshield/static/_next/static/media/2bbe8d2671613f1f-s.0k62hbripvv8p.woff2 +0 -0
- actshield/static/_next/static/media/2c55a0e60120577a-s.0-dom-5bn10r2.woff2 +0 -0
- actshield/static/_next/static/media/5476f68d60460930-s.2uwcyprjm3xu3.woff2 +0 -0
- actshield/static/_next/static/media/83afe278b6a6bb3c-s.p.2bn3s6zvc0dyp.woff2 +0 -0
- actshield/static/_next/static/media/9c72aa0f40e4eef8-s.1y4-pdgsjb-pw.woff2 +0 -0
- actshield/static/_next/static/media/ad66f9afd8947f86-s.3lvt2whj97whp.woff2 +0 -0
- actshield/static/_next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- actshield/static/_not-found/__next._full.txt +17 -0
- actshield/static/_not-found/__next._not-found/__PAGE__.txt +23 -0
- actshield/static/_not-found/__next._tree.txt +3 -0
- actshield/static/_not-found.html +1 -0
- actshield/static/_not-found.txt +17 -0
- actshield/static/access/matrix/__next._full.txt +24 -0
- actshield/static/access/matrix/__next._tree.txt +4 -0
- actshield/static/access/matrix/__next.access/matrix/__PAGE__.txt +30 -0
- actshield/static/access/matrix.html +1 -0
- actshield/static/access/matrix.txt +24 -0
- actshield/static/activity/__next._full.txt +22 -0
- actshield/static/activity/__next._tree.txt +4 -0
- actshield/static/activity/__next.activity/__PAGE__.txt +27 -0
- actshield/static/activity.html +1 -0
- actshield/static/activity.txt +22 -0
- actshield/static/agents/__next._full.txt +22 -0
- actshield/static/agents/__next._tree.txt +4 -0
- actshield/static/agents/__next.agents/__PAGE__.txt +27 -0
- actshield/static/agents.html +1 -0
- actshield/static/agents.txt +22 -0
- actshield/static/ai-secura/__next._full.txt +22 -0
- actshield/static/ai-secura/__next._tree.txt +4 -0
- actshield/static/ai-secura/__next.ai-secura/__PAGE__.txt +27 -0
- actshield/static/ai-secura.html +1 -0
- actshield/static/ai-secura.txt +22 -0
- actshield/static/api/__next._full.txt +22 -0
- actshield/static/api/__next._tree.txt +4 -0
- actshield/static/api/__next.api/__PAGE__.txt +27 -0
- actshield/static/api.html +15 -0
- actshield/static/api.txt +22 -0
- actshield/static/apiris/__next._full.txt +22 -0
- actshield/static/apiris/__next._tree.txt +4 -0
- actshield/static/apiris/__next.apiris/__PAGE__.txt +27 -0
- actshield/static/apiris.html +1 -0
- actshield/static/apiris.txt +22 -0
- actshield/static/attack-graph/__next._full.txt +23 -0
- actshield/static/attack-graph/__next._tree.txt +5 -0
- actshield/static/attack-graph/__next.attack-graph/__PAGE__.txt +28 -0
- actshield/static/attack-graph.html +2 -0
- actshield/static/attack-graph.txt +23 -0
- actshield/static/campaigns/__next._full.txt +22 -0
- actshield/static/campaigns/__next._tree.txt +4 -0
- actshield/static/campaigns/__next.campaigns/__PAGE__.txt +27 -0
- actshield/static/campaigns.html +1 -0
- actshield/static/campaigns.txt +22 -0
- actshield/static/context/__next._full.txt +22 -0
- actshield/static/context/__next._tree.txt +4 -0
- actshield/static/context/__next.context/__PAGE__.txt +27 -0
- actshield/static/context.html +1 -0
- actshield/static/context.txt +22 -0
- actshield/static/dashboard/__next._full.txt +22 -0
- actshield/static/dashboard/__next._tree.txt +4 -0
- actshield/static/dashboard/__next.dashboard/__PAGE__.txt +27 -0
- actshield/static/dashboard.html +1 -0
- actshield/static/dashboard.txt +22 -0
- actshield/static/delegations/__next._full.txt +22 -0
- actshield/static/delegations/__next._tree.txt +4 -0
- actshield/static/delegations/__next.delegations/__PAGE__.txt +27 -0
- actshield/static/delegations.html +1 -0
- actshield/static/delegations.txt +22 -0
- actshield/static/demo/__next._full.txt +22 -0
- actshield/static/demo/__next._tree.txt +4 -0
- actshield/static/demo/__next.demo/__PAGE__.txt +27 -0
- actshield/static/demo.html +1 -0
- actshield/static/demo.txt +22 -0
- actshield/static/drift/__next._full.txt +22 -0
- actshield/static/drift/__next._tree.txt +4 -0
- actshield/static/drift/__next.drift/__PAGE__.txt +27 -0
- actshield/static/drift.html +1 -0
- actshield/static/drift.txt +22 -0
- actshield/static/favicon.ico +0 -0
- actshield/static/file.svg +1 -0
- actshield/static/forensics/__next._full.txt +22 -0
- actshield/static/forensics/__next._tree.txt +4 -0
- actshield/static/forensics/__next.forensics/__PAGE__.txt +27 -0
- actshield/static/forensics.html +1 -0
- actshield/static/forensics.txt +22 -0
- actshield/static/globe.svg +1 -0
- actshield/static/incidents/__next._full.txt +22 -0
- actshield/static/incidents/__next._tree.txt +4 -0
- actshield/static/incidents/__next.incidents/__PAGE__.txt +27 -0
- actshield/static/incidents.html +1 -0
- actshield/static/incidents.txt +22 -0
- actshield/static/index.html +3 -0
- actshield/static/index.txt +20 -0
- actshield/static/logo.png +0 -0
- actshield/static/metrics/__next._full.txt +22 -0
- actshield/static/metrics/__next._tree.txt +4 -0
- actshield/static/metrics/__next.metrics/__PAGE__.txt +27 -0
- actshield/static/metrics.html +1 -0
- actshield/static/metrics.txt +22 -0
- actshield/static/next.svg +1 -0
- actshield/static/offensive/__next._full.txt +22 -0
- actshield/static/offensive/__next._tree.txt +4 -0
- actshield/static/offensive/__next.offensive/__PAGE__.txt +27 -0
- actshield/static/offensive.html +1 -0
- actshield/static/offensive.txt +22 -0
- actshield/static/policies/__next._full.txt +22 -0
- actshield/static/policies/__next._tree.txt +4 -0
- actshield/static/policies/__next.policies/__PAGE__.txt +27 -0
- actshield/static/policies.html +1 -0
- actshield/static/policies.txt +22 -0
- actshield/static/posture/__next._full.txt +22 -0
- actshield/static/posture/__next._tree.txt +4 -0
- actshield/static/posture/__next.posture/__PAGE__.txt +27 -0
- actshield/static/posture.html +1 -0
- actshield/static/posture.txt +22 -0
- actshield/static/regressions/__next._full.txt +22 -0
- actshield/static/regressions/__next._tree.txt +4 -0
- actshield/static/regressions/__next.regressions/__PAGE__.txt +27 -0
- actshield/static/regressions.html +1 -0
- actshield/static/regressions.txt +22 -0
- actshield/static/reports/__next._full.txt +22 -0
- actshield/static/reports/__next._tree.txt +4 -0
- actshield/static/reports/__next.reports/__PAGE__.txt +27 -0
- actshield/static/reports.html +1 -0
- actshield/static/reports.txt +22 -0
- actshield/static/resources/__next._full.txt +22 -0
- actshield/static/resources/__next._tree.txt +4 -0
- actshield/static/resources/__next.resources/__PAGE__.txt +27 -0
- actshield/static/resources.html +1 -0
- actshield/static/resources.txt +22 -0
- actshield/static/security-gates/__next._full.txt +22 -0
- actshield/static/security-gates/__next._tree.txt +4 -0
- actshield/static/security-gates/__next.security-gates/__PAGE__.txt +27 -0
- actshield/static/security-gates.html +1 -0
- actshield/static/security-gates.txt +22 -0
- actshield/static/settings/__next._full.txt +22 -0
- actshield/static/settings/__next._tree.txt +4 -0
- actshield/static/settings/__next.settings/__PAGE__.txt +27 -0
- actshield/static/settings.html +1 -0
- actshield/static/settings.txt +22 -0
- actshield/static/tasks/__next._full.txt +22 -0
- actshield/static/tasks/__next._tree.txt +4 -0
- actshield/static/tasks/__next.tasks/__PAGE__.txt +27 -0
- actshield/static/tasks.html +1 -0
- actshield/static/tasks.txt +22 -0
- actshield/static/threats/__next._full.txt +22 -0
- actshield/static/threats/__next._tree.txt +4 -0
- actshield/static/threats/__next.threats/__PAGE__.txt +27 -0
- actshield/static/threats.html +1 -0
- actshield/static/threats.txt +22 -0
- actshield/static/tools/__next._full.txt +22 -0
- actshield/static/tools/__next._tree.txt +4 -0
- actshield/static/tools/__next.tools/__PAGE__.txt +27 -0
- actshield/static/tools.html +1 -0
- actshield/static/tools.txt +22 -0
- actshield/static/traces/__next._full.txt +22 -0
- actshield/static/traces/__next._tree.txt +4 -0
- actshield/static/traces/__next.traces/__PAGE__.txt +27 -0
- actshield/static/traces.html +1 -0
- actshield/static/traces.txt +22 -0
- actshield/static/vercel.svg +1 -0
- actshield/static/window.svg +1 -0
- actshield/tasks/__init__.py +6 -0
- actshield/tasks/task.py +143 -0
- actshield/threatmodel/__init__.py +70 -0
- actshield/threatmodel/actors.py +210 -0
- actshield/threatmodel/analyzer.py +131 -0
- actshield/threatmodel/assets.py +167 -0
- actshield/threatmodel/boundaries.py +165 -0
- actshield/threatmodel/exporters.py +49 -0
- actshield/threatmodel/mitigations.py +209 -0
- actshield/threatmodel/models.py +80 -0
- actshield/threatmodel/report.py +341 -0
- actshield/threatmodel/scenarios.py +212 -0
- actshield/threatmodel/scoring.py +66 -0
- actshield/threatmodel/threats.py +387 -0
- actshield/tools/__init__.py +20 -0
- actshield/tools/interceptor.py +256 -0
- actshield/tools/tool.py +71 -0
- actshield/tracing/__init__.py +38 -0
- actshield/tracing/correlation.py +173 -0
- actshield/tracing/events.py +75 -0
- actshield/tracing/tracer.py +305 -0
- actshield/watch.py +129 -0
- actshield-0.9.0.dist-info/METADATA +57 -0
- actshield-0.9.0.dist-info/RECORD +366 -0
- actshield-0.9.0.dist-info/WHEEL +5 -0
- actshield-0.9.0.dist-info/entry_points.txt +4 -0
- actshield-0.9.0.dist-info/top_level.txt +2 -0
- agentguard/__init__.py +39 -0
- agentguard/__main__.py +8 -0
- agentguard/py.typed +1 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""Rich AI Secura Analysis output schema (Pydantic v2).
|
|
2
|
+
|
|
3
|
+
This schema is the contract between the OllamaAISecuraAdapter and
|
|
4
|
+
the rest of actshield. The PolicyEvaluator reads structured fields
|
|
5
|
+
from this object but remains the sole enforcement authority.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
import uuid
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ThreatSeverity(str, Enum):
|
|
15
|
+
"""Severity classification for a detected or suspected threat."""
|
|
16
|
+
LOW = "LOW"
|
|
17
|
+
MEDIUM = "MEDIUM"
|
|
18
|
+
HIGH = "HIGH"
|
|
19
|
+
CRITICAL = "CRITICAL"
|
|
20
|
+
UNKNOWN = "UNKNOWN"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class IntentAlignment(str, Enum):
|
|
24
|
+
"""Alignment of the requested action against the original user intent."""
|
|
25
|
+
ALIGNED = "ALIGNED"
|
|
26
|
+
POTENTIALLY_DRIFTING = "POTENTIALLY_DRIFTING"
|
|
27
|
+
VIOLATED = "VIOLATED"
|
|
28
|
+
UNKNOWN = "UNKNOWN"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AIRecommendation(str, Enum):
|
|
32
|
+
"""Non-binding recommendation from AI Secura to the PolicyEvaluator."""
|
|
33
|
+
ALLOW = "ALLOW"
|
|
34
|
+
MONITOR = "MONITOR"
|
|
35
|
+
HUMAN_APPROVAL = "HUMAN_APPROVAL"
|
|
36
|
+
BLOCK = "BLOCK"
|
|
37
|
+
UNKNOWN = "UNKNOWN"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AttackTechnique(str, Enum):
|
|
41
|
+
"""MITRE ATLAS / OWASP LLM Top-10 aligned attack technique labels."""
|
|
42
|
+
PROMPT_INJECTION = "prompt_injection"
|
|
43
|
+
INDIRECT_PROMPT_INJECTION = "indirect_prompt_injection"
|
|
44
|
+
JAILBREAK = "jailbreak"
|
|
45
|
+
SYSTEM_PROMPT_EXTRACTION = "system_prompt_extraction"
|
|
46
|
+
INSTRUCTION_HIJACKING = "instruction_hijacking"
|
|
47
|
+
SENSITIVE_INFORMATION_DISCLOSURE = "sensitive_information_disclosure"
|
|
48
|
+
DATA_EXFILTRATION = "data_exfiltration"
|
|
49
|
+
RAG_POISONING = "RAG_poisoning"
|
|
50
|
+
RAG_DATA_LEAKAGE = "RAG_data_leakage"
|
|
51
|
+
MALICIOUS_DOCUMENT = "malicious_document"
|
|
52
|
+
AGENT_HIJACKING = "agent_hijacking"
|
|
53
|
+
TOOL_ABUSE = "tool_abuse"
|
|
54
|
+
EXCESSIVE_AGENCY = "excessive_agency"
|
|
55
|
+
PRIVILEGE_ESCALATION = "privilege_escalation"
|
|
56
|
+
MCP_SECURITY = "MCP_security"
|
|
57
|
+
TOOL_POISONING = "tool_poisoning"
|
|
58
|
+
MALICIOUS_MCP_SERVER = "malicious_MCP_server"
|
|
59
|
+
AI_API_SECURITY = "AI_API_security"
|
|
60
|
+
AUTHENTICATION_FAILURE = "authentication_failure"
|
|
61
|
+
AUTHORIZATION_FAILURE = "authorization_failure"
|
|
62
|
+
AI_APPLICATION_VULNERABILITY = "AI_application_vulnerability"
|
|
63
|
+
ADVERSARIAL_ATTACK = "adversarial_attack"
|
|
64
|
+
CONTEXT_MANIPULATION = "context_manipulation"
|
|
65
|
+
AI_SUPPLY_CHAIN = "AI_supply_chain"
|
|
66
|
+
MODEL_DEPENDENCY_VULNERABILITY = "model_dependency_vulnerability"
|
|
67
|
+
AI_SECURITY_MONITORING = "AI_security_monitoring"
|
|
68
|
+
AI_SECURITY_EVALUATION = "AI_security_evaluation"
|
|
69
|
+
LLM_RELIABILITY_SECURITY = "LLM_reliability_security"
|
|
70
|
+
NONE = "none"
|
|
71
|
+
UNKNOWN = "unknown"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class EvidenceTriad(BaseModel):
|
|
75
|
+
"""Strict separation of observed facts, inferred conclusions, and unknowns.
|
|
76
|
+
|
|
77
|
+
AI Secura MUST NOT fabricate CVEs, CWE IDs, MITRE IDs, logs, or credentials.
|
|
78
|
+
If evidence is absent, the field belongs in 'unknown'.
|
|
79
|
+
"""
|
|
80
|
+
observed: List[str] = Field(
|
|
81
|
+
default_factory=list,
|
|
82
|
+
description="Facts directly present in the ActShield evidence packet.",
|
|
83
|
+
)
|
|
84
|
+
inferred: List[str] = Field(
|
|
85
|
+
default_factory=list,
|
|
86
|
+
description="Reasonable conclusions derived from the observed evidence.",
|
|
87
|
+
)
|
|
88
|
+
unknown: List[str] = Field(
|
|
89
|
+
default_factory=list,
|
|
90
|
+
description="Aspects that cannot be established from the available evidence.",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class AuthorityAnalysis(BaseModel):
|
|
95
|
+
"""AI Secura reasoning about delegation authority — for explanation only, not enforcement."""
|
|
96
|
+
acting_agent: Optional[str] = None
|
|
97
|
+
delegated_capabilities: List[str] = Field(default_factory=list)
|
|
98
|
+
requested_capability: Optional[str] = None
|
|
99
|
+
required_capability: Optional[str] = None
|
|
100
|
+
delegation_chain: List[str] = Field(default_factory=list)
|
|
101
|
+
authority_violated: bool = False
|
|
102
|
+
reasoning: str = ""
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class TaintAnalysis(BaseModel):
|
|
106
|
+
"""AI Secura reasoning about context taint lineage."""
|
|
107
|
+
context_id: Optional[str] = None
|
|
108
|
+
source: Optional[str] = None
|
|
109
|
+
trust_level: Optional[str] = None
|
|
110
|
+
taint_state: Optional[str] = None
|
|
111
|
+
origin_agent: Optional[str] = None
|
|
112
|
+
propagation_chain: List[str] = Field(default_factory=list)
|
|
113
|
+
is_tainted: bool = False
|
|
114
|
+
reasoning: str = ""
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class AISecuraAnalysis(BaseModel):
|
|
118
|
+
"""Complete structured output from AI Secura reasoning engine.
|
|
119
|
+
|
|
120
|
+
IMPORTANT: This is *reasoning*, not enforcement.
|
|
121
|
+
The ActShield PolicyEvaluator is the sole enforcement authority.
|
|
122
|
+
ai_recommendation here is advisory only.
|
|
123
|
+
"""
|
|
124
|
+
analysis_id: str = Field(default_factory=lambda: f"aisec35_{uuid.uuid4().hex[:12]}")
|
|
125
|
+
|
|
126
|
+
# --- Threat Classification ---
|
|
127
|
+
threat_type: str = Field(
|
|
128
|
+
default="unknown",
|
|
129
|
+
description="Primary threat type from the AI Secura security taxonomy.",
|
|
130
|
+
)
|
|
131
|
+
attack_category: str = Field(
|
|
132
|
+
default="unknown",
|
|
133
|
+
description="High-level attack category (e.g. 'injection', 'escalation', 'exfiltration').",
|
|
134
|
+
)
|
|
135
|
+
attack_technique: AttackTechnique = Field(
|
|
136
|
+
default=AttackTechnique.UNKNOWN,
|
|
137
|
+
description="Specific attack technique from the AI Secura taxonomy.",
|
|
138
|
+
)
|
|
139
|
+
severity: ThreatSeverity = Field(
|
|
140
|
+
default=ThreatSeverity.UNKNOWN,
|
|
141
|
+
description="Assessed threat severity.",
|
|
142
|
+
)
|
|
143
|
+
confidence: float = Field(
|
|
144
|
+
default=0.0,
|
|
145
|
+
ge=0.0,
|
|
146
|
+
le=1.0,
|
|
147
|
+
description="Confidence in the threat assessment (0.0 = uncertain, 1.0 = certain).",
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# --- Evidence Model ---
|
|
151
|
+
evidence: EvidenceTriad = Field(default_factory=EvidenceTriad)
|
|
152
|
+
observed_indicators: List[str] = Field(
|
|
153
|
+
default_factory=list,
|
|
154
|
+
description="Specific observable indicators extracted from the security packet.",
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# --- Alignment and Authority ---
|
|
158
|
+
intent_alignment: IntentAlignment = Field(
|
|
159
|
+
default=IntentAlignment.UNKNOWN,
|
|
160
|
+
description="Alignment of the requested action to original user intent.",
|
|
161
|
+
)
|
|
162
|
+
authority_analysis: AuthorityAnalysis = Field(default_factory=AuthorityAnalysis)
|
|
163
|
+
taint_analysis: TaintAnalysis = Field(default_factory=TaintAnalysis)
|
|
164
|
+
|
|
165
|
+
# --- MITRE References (only when directly supported by evidence) ---
|
|
166
|
+
mitre_attack_id: Optional[str] = Field(
|
|
167
|
+
default=None,
|
|
168
|
+
description="MITRE ATT&CK ID — only set when directly supported by observed evidence.",
|
|
169
|
+
)
|
|
170
|
+
mitre_atlas_id: Optional[str] = Field(
|
|
171
|
+
default=None,
|
|
172
|
+
description="MITRE ATLAS ID — only set when directly supported by observed evidence.",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# --- Analysis Narrative ---
|
|
176
|
+
analysis: str = Field(
|
|
177
|
+
default="",
|
|
178
|
+
description="Comprehensive reasoning narrative from AI Secura.",
|
|
179
|
+
)
|
|
180
|
+
impact: str = Field(
|
|
181
|
+
default="",
|
|
182
|
+
description="Potential impact if the threat is not mitigated.",
|
|
183
|
+
)
|
|
184
|
+
influencing_context: str = Field(
|
|
185
|
+
default="",
|
|
186
|
+
description="Which context data items most influenced this analysis.",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# --- Remediation ---
|
|
190
|
+
recommended_actions: List[str] = Field(
|
|
191
|
+
default_factory=list,
|
|
192
|
+
description="Security recommendations (advisory only).",
|
|
193
|
+
)
|
|
194
|
+
containment: List[str] = Field(
|
|
195
|
+
default_factory=list,
|
|
196
|
+
description="Immediate containment steps.",
|
|
197
|
+
)
|
|
198
|
+
remediation: List[str] = Field(
|
|
199
|
+
default_factory=list,
|
|
200
|
+
description="Longer-term remediation measures.",
|
|
201
|
+
)
|
|
202
|
+
additional_information_required: List[str] = Field(
|
|
203
|
+
default_factory=list,
|
|
204
|
+
description="Additional context or evidence needed for a definitive assessment.",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# --- Advisory Recommendation ---
|
|
208
|
+
ai_recommendation: AIRecommendation = Field(
|
|
209
|
+
default=AIRecommendation.UNKNOWN,
|
|
210
|
+
description=(
|
|
211
|
+
"NON-BINDING advisory recommendation to PolicyEvaluator. "
|
|
212
|
+
"PolicyEvaluator may override this at any time."
|
|
213
|
+
),
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
# --- Provider Metadata ---
|
|
217
|
+
provider: str = Field(default="local", description="Provider: 'ollama' or 'local'.")
|
|
218
|
+
model: str = Field(default="local-heuristic")
|
|
219
|
+
latency_ms: float = Field(default=0.0, description="Analysis latency in milliseconds.")
|
|
220
|
+
ai_unavailable: bool = Field(
|
|
221
|
+
default=False,
|
|
222
|
+
description=(
|
|
223
|
+
"True when Ollama is unreachable, timed out, or returned irrecoverably malformed output. "
|
|
224
|
+
"When True, ActShield deterministic policy continues as sole enforcer."
|
|
225
|
+
),
|
|
226
|
+
)
|
|
227
|
+
json_repaired: bool = Field(
|
|
228
|
+
default=False,
|
|
229
|
+
description="True if the model output required one JSON repair attempt.",
|
|
230
|
+
)
|
|
231
|
+
raw_response: Optional[str] = Field(
|
|
232
|
+
default=None,
|
|
233
|
+
description="Raw model response string (for debugging). Redacted in production events.",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""APIRIS API decision-intelligence and tool security interface."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable, Dict, List, Optional, Protocol, runtime_checkable
|
|
4
|
+
import uuid
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from actshield.risk.models import RiskLevel, RiskSignal
|
|
8
|
+
from actshield.tools.tool import ToolRequest
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class APIAnalysis(BaseModel):
|
|
12
|
+
"""API & tool intelligence analysis returned by APIRIS."""
|
|
13
|
+
analysis_id: str
|
|
14
|
+
tool_id: str
|
|
15
|
+
tool_name: str
|
|
16
|
+
risk_score: float = Field(default=0.0, ge=0.0, le=1.0)
|
|
17
|
+
anomaly_score: float = Field(default=0.0, ge=0.0, le=1.0)
|
|
18
|
+
cve_indicators: List[str] = Field(default_factory=list)
|
|
19
|
+
vendor_reputation: str = "TRUSTED"
|
|
20
|
+
latency_ms_estimate: float = 50.0
|
|
21
|
+
cost_estimate_usd: float = 0.0
|
|
22
|
+
recommended_action: str = "ALLOW"
|
|
23
|
+
signals: List[RiskSignal] = Field(default_factory=list)
|
|
24
|
+
metadata: Dict[str, Any] = Field(default_factory=dict)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@runtime_checkable
|
|
28
|
+
class APIIntelligence(Protocol):
|
|
29
|
+
"""Protocol for APIRIS API intelligence engine."""
|
|
30
|
+
|
|
31
|
+
def analyze(self, request: ToolRequest) -> APIAnalysis:
|
|
32
|
+
"""Analyze tool request metadata, endpoint parameters, and reputation."""
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class APIRISClient(APIIntelligence):
|
|
37
|
+
"""APIRIS API decision intelligence client.
|
|
38
|
+
|
|
39
|
+
Inspects endpoint reputation, argument injection signatures, rate anomalies,
|
|
40
|
+
and returns recommendations (ALLOW, MONITOR, HUMAN_APPROVAL, BLOCK).
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
api_endpoint: Optional[str] = None,
|
|
46
|
+
api_key: Optional[str] = None,
|
|
47
|
+
custom_engine: Optional[Callable[[ToolRequest], APIAnalysis]] = None,
|
|
48
|
+
) -> None:
|
|
49
|
+
self.api_endpoint = api_endpoint or "https://apiris.internal/v1/analyze"
|
|
50
|
+
self.api_key = api_key or "apiris-live-token"
|
|
51
|
+
self.custom_engine = custom_engine
|
|
52
|
+
|
|
53
|
+
def analyze(self, request: ToolRequest) -> APIAnalysis:
|
|
54
|
+
"""Perform APIRIS decision intelligence analysis on the requested tool invocation."""
|
|
55
|
+
if self.custom_engine:
|
|
56
|
+
return self.custom_engine(request)
|
|
57
|
+
|
|
58
|
+
analysis_id = f"apiris_{uuid.uuid4().hex[:12]}"
|
|
59
|
+
signals: List[RiskSignal] = []
|
|
60
|
+
cves: List[str] = []
|
|
61
|
+
risk_score = 0.05
|
|
62
|
+
anomaly_score = 0.02
|
|
63
|
+
rec_action = "ALLOW"
|
|
64
|
+
|
|
65
|
+
args_str = str(request.arguments).lower()
|
|
66
|
+
tool_name_lower = (request.tool_name or "").lower()
|
|
67
|
+
|
|
68
|
+
# 1. Command injection pattern checks
|
|
69
|
+
if any(pat in args_str for pat in ("rm -rf", "drop table", "--exec", "cmd.exe", "eval(", "; cat /etc/passwd", "bash -i")):
|
|
70
|
+
risk_score = 0.95
|
|
71
|
+
anomaly_score = 0.98
|
|
72
|
+
rec_action = "BLOCK"
|
|
73
|
+
signals.append(
|
|
74
|
+
RiskSignal(
|
|
75
|
+
source="apiris",
|
|
76
|
+
risk_level=RiskLevel.CRITICAL,
|
|
77
|
+
score=0.95,
|
|
78
|
+
indicator="APIRIS_COMMAND_INJECTION_PATTERN",
|
|
79
|
+
details={"arguments": request.arguments},
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# 2. SSRF / Untrusted domain check
|
|
84
|
+
if any(pat in args_str for pat in ("169.254.169.254", "localhost:8080", "127.0.0.1", "evil-exfil.com")):
|
|
85
|
+
risk_score = 0.90
|
|
86
|
+
rec_action = "BLOCK"
|
|
87
|
+
signals.append(
|
|
88
|
+
RiskSignal(
|
|
89
|
+
source="apiris",
|
|
90
|
+
risk_level=RiskLevel.CRITICAL,
|
|
91
|
+
score=0.90,
|
|
92
|
+
indicator="APIRIS_SSRF_OR_UNTRUSTED_DESTINATION",
|
|
93
|
+
details={"arguments": request.arguments},
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# 3. High sensitivity / Financial tool heuristic
|
|
98
|
+
if "customer_db" in tool_name_lower or "pii" in tool_name_lower:
|
|
99
|
+
risk_score = max(risk_score, 0.40)
|
|
100
|
+
vendor_rep = "INTERNAL_RESTRICTED"
|
|
101
|
+
else:
|
|
102
|
+
vendor_rep = "TRUSTED"
|
|
103
|
+
|
|
104
|
+
return APIAnalysis(
|
|
105
|
+
analysis_id=analysis_id,
|
|
106
|
+
tool_id=request.tool_id,
|
|
107
|
+
tool_name=request.tool_name,
|
|
108
|
+
risk_score=risk_score,
|
|
109
|
+
anomaly_score=anomaly_score,
|
|
110
|
+
cve_indicators=cves,
|
|
111
|
+
vendor_reputation=vendor_rep,
|
|
112
|
+
latency_ms_estimate=45.0,
|
|
113
|
+
recommended_action=rec_action,
|
|
114
|
+
signals=signals,
|
|
115
|
+
metadata={"evaluated_by": "APIRIS-v3.0"},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class LocalAPIRISAdapter(APIRISClient):
|
|
120
|
+
"""Backward-compatible alias for local execution."""
|
|
121
|
+
pass
|
|
122
|
+
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Deterministic few-shot example selector for AI Secura prompts.
|
|
2
|
+
|
|
3
|
+
Selects up to MAX_EXAMPLES relevant examples based on:
|
|
4
|
+
- Protocol (mcp, http, rag, tool, api)
|
|
5
|
+
- Taint state (TAINTED, CLEAN)
|
|
6
|
+
- Resource sensitivity (CRITICAL, HIGH, MEDIUM, LOW)
|
|
7
|
+
- Attack category hint
|
|
8
|
+
|
|
9
|
+
No vector database. Pure rule-based selection from the examples directory.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import pathlib
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
_EXAMPLES_DIR = pathlib.Path(__file__).parent / "prompts" / "examples"
|
|
17
|
+
MAX_EXAMPLES = 4
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _load_example(path: pathlib.Path) -> Optional[Dict[str, Any]]:
|
|
21
|
+
try:
|
|
22
|
+
with open(path, encoding="utf-8") as f:
|
|
23
|
+
return json.load(f)
|
|
24
|
+
except Exception:
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _score_example(ex: Dict[str, Any], context: Dict[str, Any]) -> int:
|
|
29
|
+
"""Return relevance score (higher = more relevant)."""
|
|
30
|
+
score = 0
|
|
31
|
+
ex_tags = set(ex.get("tags", []))
|
|
32
|
+
|
|
33
|
+
# Protocol match
|
|
34
|
+
provenance = context.get("context_provenance", [])
|
|
35
|
+
src = " ".join(str(p) for p in provenance).lower()
|
|
36
|
+
tool_name = str(context.get("tool", {}).get("name", "")).lower()
|
|
37
|
+
if "mcp" in src and "mcp" in ex_tags:
|
|
38
|
+
score += 3
|
|
39
|
+
if "http" in src or "api" in src:
|
|
40
|
+
if "http" in ex_tags or "api" in ex_tags:
|
|
41
|
+
score += 3
|
|
42
|
+
if "rag" in src and "rag" in ex_tags:
|
|
43
|
+
score += 3
|
|
44
|
+
|
|
45
|
+
# Taint state match
|
|
46
|
+
taint_states = context.get("taint_states", [])
|
|
47
|
+
has_taint = any(t in ("TAINTED", "UNTRUSTED") for t in taint_states)
|
|
48
|
+
if has_taint and "tainted" in ex_tags:
|
|
49
|
+
score += 2
|
|
50
|
+
if not has_taint and "clean" in ex_tags:
|
|
51
|
+
score += 2
|
|
52
|
+
|
|
53
|
+
# Sensitivity match
|
|
54
|
+
sensitivity = str(context.get("resource", {}).get("sensitivity", "")).upper()
|
|
55
|
+
if sensitivity in ("CRITICAL", "HIGH") and "critical_sink" in ex_tags:
|
|
56
|
+
score += 2
|
|
57
|
+
if sensitivity in ("LOW", "MEDIUM") and "low_risk" in ex_tags:
|
|
58
|
+
score += 1
|
|
59
|
+
|
|
60
|
+
# Attack category match
|
|
61
|
+
ex_threat = ex.get("expected_output", {}).get("attack_technique", "")
|
|
62
|
+
det_policy = context.get("deterministic_policy", {})
|
|
63
|
+
reason_codes = " ".join(det_policy.get("reason_codes", []))
|
|
64
|
+
if "injection" in reason_codes.lower() and "injection" in ex_threat:
|
|
65
|
+
score += 2
|
|
66
|
+
if "authority" in reason_codes.lower() and "escalation" in ex_threat:
|
|
67
|
+
score += 2
|
|
68
|
+
|
|
69
|
+
return score
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def select_few_shot_examples(context: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
73
|
+
"""Return up to MAX_EXAMPLES ordered by relevance to context."""
|
|
74
|
+
if not _EXAMPLES_DIR.exists():
|
|
75
|
+
return []
|
|
76
|
+
|
|
77
|
+
examples = []
|
|
78
|
+
for path in sorted(_EXAMPLES_DIR.glob("*.json")):
|
|
79
|
+
ex = _load_example(path)
|
|
80
|
+
if ex:
|
|
81
|
+
ex["_score"] = _score_example(ex, context)
|
|
82
|
+
examples.append(ex)
|
|
83
|
+
|
|
84
|
+
examples.sort(key=lambda e: e["_score"], reverse=True)
|
|
85
|
+
return [
|
|
86
|
+
{k: v for k, v in ex.items() if k != "_score"}
|
|
87
|
+
for ex in examples[:MAX_EXAMPLES]
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def format_examples_for_prompt(examples: List[Dict[str, Any]]) -> str:
|
|
92
|
+
"""Format selected examples as a few-shot block for the system prompt."""
|
|
93
|
+
if not examples:
|
|
94
|
+
return ""
|
|
95
|
+
lines = ["\n\n### FEW-SHOT EXAMPLES\n"]
|
|
96
|
+
for i, ex in enumerate(examples, 1):
|
|
97
|
+
lines.append(f"#### Example {i}: {ex.get('description', '')}\n")
|
|
98
|
+
lines.append("Input:\n```json")
|
|
99
|
+
lines.append(json.dumps(ex.get("input", {}), indent=2))
|
|
100
|
+
lines.append("```\n")
|
|
101
|
+
lines.append("Expected Output:\n```json")
|
|
102
|
+
lines.append(json.dumps(ex.get("expected_output", {}), indent=2))
|
|
103
|
+
lines.append("```\n")
|
|
104
|
+
return "\n".join(lines)
|