saintparish4/openscript

GitHub: saintparish4/openscript

OpenScript 是一个 Python LLM Agent 安全网关 SDK,通过可插拔的策略管道在操作前后拦截注入、脱敏敏感数据、管控工具调用并审批高风险行为。

Stars: 0 | Forks: 0

# OpenScript **用于 LLM/agent 工作流的安全网关 SDK。** 阻断 prompt 注入,脱敏 PII 和机密信息,为 tool 调用设置防火墙,通过人工审批机制对高风险操作进行管控,并评估每一次操作的风险——适用于任何 LLM 提供商。 OpenScript 将任何 agent 包装在 **policy pipeline** 中:policy 在每次操作前后运行,且每一个都可以执行允许、修改(脱敏)、拒绝或要求人工审批。pipeline 本身不包含任何检测逻辑——所有的一切都是一个 `Policy`,你可以随意替换它们、通过 YAML 进行配置,或者自己编写。 ![OpenScript 演示](https://raw.githubusercontent.com/saintparish4/openscript/master/demo/injection_demo.gif) ## 5 分钟入门 ### 1. 安装 ``` pip install openscript ``` 或从源码安装: ``` git clone https://github.com/OrdinalScale/openscript.git cd openscript python -m venv .venv .venv/Scripts/activate # Windows # source .venv/bin/activate # Unix pip install -r requirements.txt pip install -e . ``` 可选的额外依赖:`openscript[redis]`(共享审批存储)、`openscript[metrics]`(Prometheus)、`openscript[otel]`(链路追踪)、`openscript[ml]`(基于 embedding 的检查)。 ### 2. 包装 Agent ``` import asyncio from sdk import PIIPolicy, PromptInjectionPolicy, SecretsPolicy, SecureAgent class MyAgent: async def ainvoke(self, input_data, **kwargs): return {"output": f"Hello, {input_data.get('input', 'world')}!"} async def main(): secure = SecureAgent( agent=MyAgent(), policies=[ PromptInjectionPolicy(threshold=0.5), # blocks injection attempts PIIPolicy(mode="redact"), # redacts PII from output SecretsPolicy(mode="redact"), # redacts credentials, flags internal URLs ], ) result = await secure.invoke({"input": "OpenScript"}) print(result) # {"output": "Hello, OpenScript!"} asyncio.run(main()) ``` 被阻断的操作会引发 `ActionBlockedError`,并附带原因、执行阻断的 policy,以及该操作汇总后的 `risk_score`。 ### 3. 或者通过 YAML 配置 Policy ``` # policies.yaml policies: prompt_injection: threshold: 0.6 toxicity: threshold: 0.5 pii: mode: redact secrets: mode: deny internal_url_mode: annotate compliance: rules: [phi_detection, credential_output_guard] tool_firewall: rules_path: tools.yaml ``` ``` from sdk import SecureAgent, load_policies secure = SecureAgent(agent, policies=load_policies("policies.yaml")) ``` ## 内置 Policy | Policy | 阶段 | 功能描述 | |--------|-------|--------------| | `PromptInjectionPolicy` | input | 评估角色注入、prompt 提取、目标劫持、分隔符/间接注入;在达到阈值时拒绝 | | `ToxicityPolicy` | input | 检测威胁、仇恨言论、骚扰、自残内容;在达到阈值时拒绝 | | `PIIPolicy` | output | 脱敏或拒绝邮箱、电话、社会安全号码(SSN)、信用卡(经 Luhn 校验)、API key、IP | | `SecretsPolicy` | input + output | 脱敏或拒绝 AWS/GitHub/Slack token、JWT、私钥块;单独标记内部 URL/私有 IP(`internal_url_mode`:默认为 annotate,并提供 allowlist) | | `CompliancePolicy` | input + output | 严格界定范围的预设:`phi_detection`、`credential_output_guard`、`data_access_audit` — 参见 [合规定位](#compliance-positioning) | | `ToolFirewallPolicy` | input | 针对 tool 调用的 allowlist/deny/RBAC/参数约束;可要求人工审批。也可通过 `validate_tool_call()` 或 `POST /v1/tools/validate` 独立使用 | | `OutputSchemaPolicy` | output | Pydantic schema 校验,危险内容扫描,针对来源的可选幻觉/接地检查 | | `AuditPolicy` | both | 将每次操作写入事件存储;请将其放在**最后**,以确保其事件包含最终的风险评分 | 每个 policy 都会写入标准化的元数据 —— `{"risk": float, "category": str, ...}` —— 内置的 `RiskScorer` 会将其汇总为每次操作的单一 `risk_score`: ``` result, ctx = await secure.invoke_with_context({"input": "..."}) print(ctx.risk_score) # 0.0 – 1.0 print(ctx.risk_categories) # {"pii": 0.4, "prompt_injection": 0.0, ...} ``` ## 人工审批(审批后重试) 当 policy 返回 `REQUIRE_APPROVAL`(例如被防火墙拦截的 tool 调用)时,该操作会被阻断,并创建一条待处理的审批记录: ``` from sdk import ActionBlockedError, RedisApprovalStore, SecureAgent secure = SecureAgent( agent, policies=[...], # Redis is REQUIRED when approvals are decided via the server API — # the default in-memory store only works within a single process. approval_store=RedisApprovalStore("redis://localhost:6379/0"), ) try: await secure.invoke({"input": "transfer $5,000"}) except ActionBlockedError as e: approval_id = e.approval_id # a human decides via POST /v1/approvals/{id}/decide # 批准后,使用 approval id 重试相同的操作: result = await secure.invoke({"input": "transfer $5,000"}, approval_id=approval_id) ``` 审批是**一次性的**,在 1 小时后过期,且绑定到具体的操作 + 输入哈希值——为某次转账授予的审批无法被重用于另一次转账。 ## 流式传输 `stream()` 支持三种保护模式(通过构造函数或单次调用设置 `stream_output=`): | 模式 | 保护机制 | 延迟 | 用途 | |------|-----------|---------|---------| | `buffer`(默认) | 全面—— output policy 可以在输出任何内容之前,查看、脱敏并阻断完整的响应 | 完整响应时间 | 供机器消费的输出 | | `guarded` | 通过带有保留窗口的增量扫描,对有边界的模式(机密信息、PII)进行全面保护;若触发拒绝(deny),则会中止且不输出任何匹配内容。Schema/接地检查在流结束时运行 | 约一个窗口(几十个 token) | 面向人类的聊天 UI(文本流) | | `passthrough` | **无**—— 分块直接交付,不进行扫描;policy 仅在事后运行以提供元数据/审计,事后的拒绝操作只会在事后引发异常 | 无 | 仅用于可观测性设置,请谨慎使用 | ``` async for chunk in secure.stream({"input": "..."}, stream_output="guarded"): print(chunk, end="") ``` 自定义 policy 可以通过实现 `stream_guard()` 来参与受保护的流式传输(参见 `contracts.interceptor.StreamGuard`)。 ## 可观测性 ``` from sdk import MetricsRecorder, SecureAgent secure = SecureAgent(agent, policies=[...], metrics=MetricsRecorder()) ``` Prometheus 指标(`pip install openscript[metrics]`):按决策分类的操作、`risk_score` 直方图、按类别的违规计数器、注入/ tool 拒绝/ PII 脱敏计数器,以及按 policy 划分的延迟直方图。服务器通过 `GET /metrics` 暴露这些指标(受 API key 控制)。 OpenTelemetry(`pip install openscript[otel]`):设置 `OPENSCRIPT_OTEL=1`,即可为每个操作生成一个 span,其中包含最终决策和风险评分;通过标准的 `OTEL_*` 环境变量配置你的 OTLP exporter。 ## 编写自定义 Policy ``` from contracts.types import ActionContext, InterceptorDecision from sdk import BasePolicy class BusinessHoursPolicy(BasePolicy): async def before_action(self, context: ActionContext) -> ActionContext: if not is_business_hours(): context.decision = InterceptorDecision.DENY context.decision_reason = "agent actions are restricted to business hours" return context ``` 任何包含 `before_action`、`after_action` 和 `failure_mode` 的对象都满足 `Policy` 协议——继承 `BasePolicy` 只是为你提供了直通的默认值。声明 `failure_mode` 可以控制错误处理方式: | 模式 | 行为 | |------|----------| | `FAIL_OPEN` | 记录警告日志,允许操作继续执行 | | `FAIL_CLOSED` | 记录错误日志,阻断操作 | | `FAIL_EXCEPTION` | 重新抛出原始异常 | 安全 policy 默认使用 `FAIL_CLOSED`;可观测性 policy 默认使用 `FAIL_OPEN`。 ## 架构 ``` User Request │ ▼ ┌────────────────────────────────────────────┐ │ SecureAgent │ │ │ │ ┌─ before_action ─────────────────────┐ │ │ │ PromptInjectionPolicy ──► DENY? │ │ │ │ ToxicityPolicy ──► DENY? │ │ │ │ ToolFirewallPolicy ──► APPROVAL? │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ Agent.invoke() / stream() │ │ │ │ │ ┌─ after_action ──────────────────────┐ │ │ │ OutputSchemaPolicy ──► DENY? │ │ │ │ PIIPolicy / SecretsPolicy (redact) │ │ │ │ CompliancePolicy │ │ │ │ AuditPolicy (events + risk) │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ RiskScorer ──► risk_score, metrics │ └────────────────────────────────────────────┘ │ ▼ Response (or ActionBlockedError with reason, risk_score, approval_id) ``` pipeline 是刻意设计得简单的——所有的检测逻辑都位于 policy 中。在 *before* 阶段拒绝(deny)会在 agent 运行前阻断;在 *after* 阶段拒绝会在所有 policy(包括审计)完成后阻断响应。 ## 框架集成 目前已提供 LangChain 和 LangGraph 的包装器: ``` from sdk import wrap_agent, wrap_graph_agent, load_policies secure = wrap_agent(langchain_agent, policies=load_policies("policies.yaml")) result = await secure.invoke({"input": "What is prompt injection?"}) ``` CrewAI、PydanticAI、AutoGen 和 OpenAI Agents SDK 适配器已列入路线图(每一个都将作为可选的额外依赖,基于各框架官方的防护机制/回调钩子构建)。 ## 合规定位 `CompliancePolicy` **协助**合规计划——它的检查项(PHI 标识符检测、凭据输出防护、数据访问审计)对应了常见的 GDPR/HIPAA/SOC 2 控制措施。它**不**代表授予或认证符合任何法规,并且其预设名称特意根据它们检查的内容来命名,而不是以法规名称命名。 ## 服务器 可选的 FastAPI 服务器(`uvicorn server.app:app`)提供事件存储、SSE 推送、会话仪表板(`/dashboard/`)、无状态评分端点(`/v1/threat/score`、`/v1/tools/validate`)、审批队列(`/v1/approvals`)以及 Prometheus 指标(`/metrics`)。除 `/health` 外,所有端点都需要在请求头中提供 `X-API-KEY`(`OPENSCRIPT_API_KEY`)。 尝试端到端运行完整的 pipeline: ``` python demo/injection_demo.py ``` ## 从 Interceptor API 迁移 1.0 版本之前的名称仍然有效,但会发出 `DeprecationWarning`:`OpenScriptMiddleware` → `SecureAgent`,`interceptors=` → `policies=`,`ThreatInterceptor` → `PromptInjectionPolicy`,`PIIInterceptor` → `PIIPolicy`,`EventWriterInterceptor` → `AuditPolicy`,`Interceptor` 协议 → `Policy`。 ## 开发 ``` # 设置 python -m venv .venv && .venv/Scripts/activate pip install -r requirements.txt && pip install -e . # 测试 pytest # Lint + format + type-check ruff check . black . mypy sdk/ contracts/ ``` 详情请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。 ## 许可证 Apache 2.0 — 参见 [LICENSE](LICENSE)。
标签:Kerberos, 搜索引擎查询, 用户代理, 自定义请求头, 逆向工具