petfishframework 0.3.2__tar.gz → 0.4.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.
- petfishframework-0.4.0/.sisyphus/plans/v0.4.0-plan.md +236 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/CHANGELOG.md +62 -0
- petfishframework-0.4.0/Dockerfile +7 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/PKG-INFO +12 -7
- {petfishframework-0.3.2 → petfishframework-0.4.0}/README.md +6 -6
- petfishframework-0.4.0/docker-compose.yml +8 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/api.md +176 -1
- petfishframework-0.4.0/docs/deployment.md +181 -0
- petfishframework-0.4.0/docs/release-protocol.md +86 -0
- petfishframework-0.4.0/docs/threat-model.md +189 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/pyproject.toml +3 -1
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/__init__.py +1 -1
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/environment.py +12 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/session.py +38 -4
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/credentials/__init__.py +2 -1
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/credentials/broker.py +12 -0
- petfishframework-0.4.0/src/petfishframework/credentials/vault_adapter.py +87 -0
- petfishframework-0.4.0/src/petfishframework/observability/otel_sink.py +111 -0
- petfishframework-0.4.0/src/petfishframework/observability/siem_sink.py +113 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/__init__.py +4 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/replay.py +109 -0
- petfishframework-0.4.0/tests/test_otel_sink.py +87 -0
- petfishframework-0.4.0/tests/test_replay_rerun.py +162 -0
- petfishframework-0.4.0/tests/test_replay_resume.py +185 -0
- petfishframework-0.4.0/tests/test_siem_export.py +114 -0
- petfishframework-0.4.0/tests/test_vault_adapter.py +79 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/uv.lock +67 -6
- {petfishframework-0.3.2 → petfishframework-0.4.0}/.env.example +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/.github/workflows/ci.yml +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/.github/workflows/publish.yml +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/.gitignore +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/.sisyphus/plans/v0.1.6-plan.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/.sisyphus/plans/v0.2.0-plan.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/.sisyphus/plans/v0.3.0-plan.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/AGENTS.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/AGENTS.md.new +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/CONTRIBUTING.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/LICENSE +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/SECURITY.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/conftest.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/architecture.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/benchmark-results.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/development-plan.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/development.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/enterprise-expense-demo.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_0_1_4_playground_recommendations.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_playground_report.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_production_readiness_roadmap.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_recommendations.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_v0_1_6_playground_review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_v0_1_7_review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_v0_1_8_review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_v0_2_1_review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/archives/petfishframework_v0_2_2_review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/feedbacks/petfishframework_v0_3_0_review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/release-checklist.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/competitor-analysis/README.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/competitor-analysis/competitor-matrix.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/competitor-analysis/market-brief.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/competitor-analysis/positioning-map.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/competitor-analysis/swot-analysis.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/literature-review/inclusion-exclusion-criteria.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/literature-review/literature-matrix.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/literature-review/literature-review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/literature-review/search-strategy.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/research/reference-repos-absorption.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/skeleton-completeness-checklist.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/test-results-report.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/usage-guide.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/docs/validation-roadmap.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/initialization-report.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/mcp/README.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/mcp/connection-checklist.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/mcp/mcp-config.example.json +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/opencode.json +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/qa/code-review-checklist.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/qa/qa-review.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/qa/qc-gate-decision.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/qa/test-plan.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/config.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/agent.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/compiled.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/contracts.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/conversation.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/events.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/structured.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/core/types.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/credentials/token.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/mcp/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/mcp/client.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/mcp/server.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/mcp/stdio_transport.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/mcp/wrapper.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/models/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/models/anthropic.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/models/fake.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/models/openai.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/observability/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/observability/sinks.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/permissions/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/permissions/model.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/policies/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/policies/conditions.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/policies/engine.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/policies/rule.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/policies/test_runner.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/policies/validator.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reasoning/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reasoning/lats.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reasoning/llm_plus_p.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reasoning/react.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/audit_report.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/cost.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/cost_report.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/pass_at_k.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/retry.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/reliability/timeout.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/retrieval/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/retrieval/adaptive.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/retrieval/crag.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/retrieval/memory_store.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/tools/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/tools/agent_tool.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/tools/base.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/tools/calculator.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/tools/path_planner.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/tools/registry.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/src/petfishframework/tools/word_sorter.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tasks/backlog.md +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/integration/__init__.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/integration/test_anthropic_integration.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/integration/test_openai_integration.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/policies/enterprise-expense.tests.yaml +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_agent_tool.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_anthropic_adapter.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_api_agent_lifecycle.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_api_edge_cases.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_api_integration.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_api_public_surface.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_api_type_safety.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_async.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_audit_report_v2.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_conversation.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_credential_broker.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_credential_integration.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_degrade.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_degrade_failclosed.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_enterprise_demo.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_m2_m3_m4.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_mcp.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_openai_adapter.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_pass_at_k.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_permission_semantics.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_quickstart_smoke.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_replay.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_retrieval.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_retry.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_skeleton.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_stdio_transport.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_streaming.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_structured.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_tool_registry.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_v016_semantics.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_v018.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_v019.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_v2_interface_compatibility.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_v2_lats.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_v2_llm_plus_p.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_yaml_policy.py +0 -0
- {petfishframework-0.3.2 → petfishframework-0.4.0}/tests/test_yaml_policy_suite.py +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# petfishFramework v0.4.0 开发计划
|
|
2
|
+
|
|
3
|
+
> 基于 v0.3.3 状态 + 8 轮用户反馈 + 全部 deferred 项汇总
|
|
4
|
+
> 目标:observability + deterministic replay + 生产化基础
|
|
5
|
+
> 原则:**TDD 先行,pre_release.py 门禁,文档同步作为完成条件**
|
|
6
|
+
|
|
7
|
+
## v0.4.0 使命
|
|
8
|
+
|
|
9
|
+
> 让 Agent 运行时可观测(OTel)、可回放(确定性 RERUN/RESUME)、可治理(SIEM export)、可部署(Docker + 部署指南)。
|
|
10
|
+
|
|
11
|
+
## Deferred 项汇总(从全部反馈中提取)
|
|
12
|
+
|
|
13
|
+
| 来源 | Deferred 项 | v0.4.0 目标 |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| v0.3.0 §9.2 | deterministic rerun / resume | ✅ 实现 |
|
|
16
|
+
| v0.3.0 §9.2 | MCP server mode | ⏳ v0.5.0(需完整 MCP server 实现) |
|
|
17
|
+
| v0.3.0 §9.2 | deployment guide | ✅ Dockerfile + 部署文档 |
|
|
18
|
+
| v0.3.0 §9.2 | OpenTelemetry | ✅ OTelSink |
|
|
19
|
+
| v0.3.0 §9.2 | SIEM export | ✅ JSON-Lines trace export |
|
|
20
|
+
| v0.3.0 §P2 | Vault adapter | ✅ HashiCorp Vault adapter (可选) |
|
|
21
|
+
| v0.3.0 §P2 | threat model | ✅ 威胁模型文档 |
|
|
22
|
+
| v0.3.0 §P2 | SBOM | ✅ cyclonedx 生成 |
|
|
23
|
+
| v0.3.0 §P2 | signed release | ✅ sigstore cosign |
|
|
24
|
+
| 多轮 | README Current Limitations 中 planned 项 | 清理为 available |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Phase A: Deterministic Replay (RESUME + RERUN)
|
|
29
|
+
|
|
30
|
+
### A1: RESUME — 检查点恢复
|
|
31
|
+
|
|
32
|
+
**目标**:从检查点恢复执行,重注入已记录的模型响应直到检查点,之后继续新鲜调用。
|
|
33
|
+
|
|
34
|
+
#### TDD 测试先行
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
# tests/test_replay_resume.py
|
|
38
|
+
|
|
39
|
+
def test_resume_replays_recorded_prefix():
|
|
40
|
+
"""RESUME: 重注入检查点前的模型响应。"""
|
|
41
|
+
|
|
42
|
+
def test_resume_continues_with_fresh_calls():
|
|
43
|
+
"""RESUME: 检查点后用 live environment 新鲜调用。"""
|
|
44
|
+
|
|
45
|
+
def test_resume_from_mid_session():
|
|
46
|
+
"""RESUME: 从 Session 中间的检查点恢复。"""
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### 实现
|
|
50
|
+
|
|
51
|
+
- `ResumableEnvironment`(已有 v0.1.x 基础)增强:
|
|
52
|
+
- `checkpoint_model_idx` / `checkpoint_tool_idx` 参数
|
|
53
|
+
- 检查点前用 `recording.model_responses[i]` 重注入
|
|
54
|
+
- 检查点后切换到 `live_env`
|
|
55
|
+
- `Session.checkpoint()` 发出 `session.checkpoint` 事件 + 记录当前 model/tool 索引
|
|
56
|
+
- `Session.resume_from(checkpoint_data)` 工厂方法
|
|
57
|
+
|
|
58
|
+
### A2: RERUN — 确定性完整重放 + 偏离检测
|
|
59
|
+
|
|
60
|
+
**目标**:完整重放一个 Session 的所有调用,验证轨迹一致。偏离时报告差异。
|
|
61
|
+
|
|
62
|
+
#### TDD 测试先行
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# tests/test_replay_rerun.py
|
|
66
|
+
|
|
67
|
+
def test_rerun_reproduces_identical_trajectory():
|
|
68
|
+
"""RERUN: 完整重放,轨迹完全一致。"""
|
|
69
|
+
|
|
70
|
+
def test_rerun_detects_model_call_count_divergence():
|
|
71
|
+
"""RERUN: 模型调用次数不一致 → 报告偏离。"""
|
|
72
|
+
|
|
73
|
+
def test_rerun_detects_tool_result_divergence():
|
|
74
|
+
"""RERUN: 工具结果不一致 → 报告偏离。"""
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### 实现
|
|
78
|
+
|
|
79
|
+
- `RerunEnvironment`:封装 `RecordingEnvironment` + `ReplayEnvironment`
|
|
80
|
+
- `rerun() -> RerunResult`:重放 + 比对
|
|
81
|
+
- `RerunResult.matches: bool` + `divergences: list[str]`
|
|
82
|
+
- 检测:调用次数偏离、工具名偏离、结果值偏离
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Phase B: Observability
|
|
87
|
+
|
|
88
|
+
### B1: OpenTelemetry Sink
|
|
89
|
+
|
|
90
|
+
**目标**:Session 事件 → OTel spans,可接入 Jaeger/Zipkin/DataDog。
|
|
91
|
+
|
|
92
|
+
#### TDD 测试先行
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
# tests/test_otel_sink.py
|
|
96
|
+
|
|
97
|
+
def test_otel_sink_creates_span_per_tool_call():
|
|
98
|
+
"""每个 tool.called 事件创建一个 span。"""
|
|
99
|
+
|
|
100
|
+
def test_otel_sink_creates_span_per_model_call():
|
|
101
|
+
"""每个 model.called 事件创建一个 span。"""
|
|
102
|
+
|
|
103
|
+
def test_otel_sink_nests_tool_spans_under_session():
|
|
104
|
+
"""工具 span 嵌套在 session trace 下。"""
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### 实现
|
|
108
|
+
|
|
109
|
+
- `observability/otel_sink.py` — `OTelSink`:
|
|
110
|
+
- 接收 EventEmitter 事件
|
|
111
|
+
- Session → OTel Trace
|
|
112
|
+
- model.called → span (attributes: model name, tokens, cost)
|
|
113
|
+
- tool.called/blocked/masked → span (attributes: tool name, effect, duration)
|
|
114
|
+
- 使用 `opentelemetry-api`(可选依赖:`pip install petfishframework[otel]`)
|
|
115
|
+
- 无 OTel 安装时降级为 no-op
|
|
116
|
+
|
|
117
|
+
### B2: SIEM Export (JSON-Lines Trace)
|
|
118
|
+
|
|
119
|
+
**目标**:结构化事件导出,可导入 Splunk/Elastic/Datadog。
|
|
120
|
+
|
|
121
|
+
#### TDD 测试先行
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
# tests/test_siem_export.py
|
|
125
|
+
|
|
126
|
+
def test_siem_export_produces_jsonlines():
|
|
127
|
+
"""导出为 JSON-Lines 格式。"""
|
|
128
|
+
|
|
129
|
+
def test_siem_export_redacts_credentials():
|
|
130
|
+
"""导出中不含 secret。"""
|
|
131
|
+
|
|
132
|
+
def test_siem_export_includes_policy_version():
|
|
133
|
+
"""每条记录包含 policy_version。"""
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### 实现
|
|
137
|
+
|
|
138
|
+
- `observability/siem_sink.py` — `SIEMSink`:
|
|
139
|
+
- 接收事件 → 写入 JSON-Lines 文件/流
|
|
140
|
+
- 每行:`{"timestamp", "session_id", "event_type", "tool_name", "effect", "executed", "policy_version", "duration_ms"}`
|
|
141
|
+
- 自动脱敏(复用 event_mask 逻辑)
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Phase C: Production Foundation
|
|
146
|
+
|
|
147
|
+
### C1: Vault Adapter
|
|
148
|
+
|
|
149
|
+
**目标**:CredentialBroker 支持 HashiCorp Vault 作为 secret 后端。
|
|
150
|
+
|
|
151
|
+
#### TDD 测试先行
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
# tests/test_vault_adapter.py
|
|
155
|
+
|
|
156
|
+
def test_vault_adapter_reads_secret():
|
|
157
|
+
"""Vault adapter 从 Vault 读取 secret。"""
|
|
158
|
+
# 使用 mock,不连真实 Vault
|
|
159
|
+
|
|
160
|
+
def test_vault_adapter_caches_locally():
|
|
161
|
+
"""读取后缓存,减少 Vault 调用。"""
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### 实现
|
|
165
|
+
|
|
166
|
+
- `credentials/vault_adapter.py` — `VaultCredentialSource`:
|
|
167
|
+
- `read_secret(path: str) -> str` — 从 Vault 读取
|
|
168
|
+
- 可选依赖:`hvac` library
|
|
169
|
+
- 集成到 `CredentialBroker.register_credential_from_vault(path)`
|
|
170
|
+
|
|
171
|
+
### C2: Dockerfile + 部署指南
|
|
172
|
+
|
|
173
|
+
**文件**:
|
|
174
|
+
- `Dockerfile` — 多阶段构建
|
|
175
|
+
- `docker-compose.yml` — 开发环境
|
|
176
|
+
- `docs/deployment.md` — 部署指南
|
|
177
|
+
|
|
178
|
+
### C3: SBOM + Signed Release
|
|
179
|
+
|
|
180
|
+
- `.github/workflows/publish.yml` 增强:
|
|
181
|
+
- 生成 SBOM (cyclonedx)
|
|
182
|
+
- cosign 签名
|
|
183
|
+
- `docs/threat-model.md` — 威胁模型
|
|
184
|
+
|
|
185
|
+
### C4: 文档 + README 更新
|
|
186
|
+
|
|
187
|
+
- api.md: 新增 OTel + SIEM + Vault + Replay 章节
|
|
188
|
+
- README: Current Limitations 清理(deterministic replay: Available; OTel: Available)
|
|
189
|
+
- CHANGELOG: v0.4.0
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 执行顺序与依赖
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
A1 (RESUME) → A2 (RERUN)
|
|
197
|
+
↓
|
|
198
|
+
B1 (OTel) → B2 (SIEM)
|
|
199
|
+
↓
|
|
200
|
+
C1 (Vault) → C2 (Docker) → C3 (SBOM) → C4 (docs)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## 验收标准
|
|
204
|
+
|
|
205
|
+
| # | 标准 | 验证方法 |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| V1 | RESUME 从检查点恢复执行 | `test_replay_resume.py` |
|
|
208
|
+
| V2 | RERUN 完整重放 + 偏离检测 | `test_replay_rerun.py` |
|
|
209
|
+
| V3 | OTel sink 生成 spans | `test_otel_sink.py` |
|
|
210
|
+
| V4 | SIEM 导出 JSON-Lines + 脱敏 | `test_siem_export.py` |
|
|
211
|
+
| V5 | Vault adapter 读取 secret(mock) | `test_vault_adapter.py` |
|
|
212
|
+
| V6 | Dockerfile 可构建 | `docker build .` |
|
|
213
|
+
| V7 | SBOM 生成 | CI workflow |
|
|
214
|
+
| V8 | pre_release.py exit 0 | `python scripts/pre_release.py 0.4.0` |
|
|
215
|
+
| V9 | 所有 284+ 现有测试通过 | pytest |
|
|
216
|
+
| V10 | ruff clean | ruff check |
|
|
217
|
+
| V11 | README Current Limitations 清理 | grep "Planned" |
|
|
218
|
+
|
|
219
|
+
## 不做清单(v0.5.0+)
|
|
220
|
+
|
|
221
|
+
- ❌ MCP server mode
|
|
222
|
+
- ❌ MCP governance (allowlist, rate limit)
|
|
223
|
+
- ❌ Tool sandbox (subprocess isolation)
|
|
224
|
+
- ❌ Policy hot-reload
|
|
225
|
+
- ❌ Multi-tenant policy namespace
|
|
226
|
+
|
|
227
|
+
## 新测试预估
|
|
228
|
+
|
|
229
|
+
| Phase | 测试数 |
|
|
230
|
+
|---|---|
|
|
231
|
+
| A1 RESUME | 3 |
|
|
232
|
+
| A2 RERUN | 3 |
|
|
233
|
+
| B1 OTel | 3 |
|
|
234
|
+
| B2 SIEM | 3 |
|
|
235
|
+
| C1 Vault | 2 |
|
|
236
|
+
| **总计** | **~14 新测试** |
|
|
@@ -2,6 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to petfishFramework will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.4.0] — 2026-07-08
|
|
6
|
+
|
|
7
|
+
### v0.4.0 Production Foundation
|
|
8
|
+
|
|
9
|
+
#### Phase A+B: Deterministic Replay + Observability
|
|
10
|
+
- Deterministic replay infrastructure (`petfishframework.reliability.replay`):
|
|
11
|
+
- `RecordingEnvironment` captures every model response, tool call, and retrieval
|
|
12
|
+
- `ReplayEnvironment` replays recorded calls for deterministic audit
|
|
13
|
+
- `ResumableEnvironment` replays prefix then switches to live execution
|
|
14
|
+
- `ReplayMode.AUDIT`, `RESUME`, `RERUN` semantics
|
|
15
|
+
- OpenTelemetry sink (`OTelSink`) — creates spans for model/tool/session events
|
|
16
|
+
- SIEM export (`SIEMSink`) — structured JSON audit events for downstream SIEMs
|
|
17
|
+
|
|
18
|
+
#### Phase C: Vault Adapter + Deployment + Threat Model
|
|
19
|
+
- `VaultCredentialSource` — reads secrets from HashiCorp Vault with lazy `hvac` import
|
|
20
|
+
- `CredentialBroker.register_credential_from_vault(name, source, path)` — register
|
|
21
|
+
credentials fetched from Vault
|
|
22
|
+
- Optional dependency group `vault = ["hvac>=1.0"]`
|
|
23
|
+
- `Dockerfile` and `docker-compose.yml` for containerized deployment
|
|
24
|
+
- `docs/deployment.md` — Docker deployment guide, environment variables, volume mounts,
|
|
25
|
+
credential-broker integration, and security notes
|
|
26
|
+
- `docs/threat-model.md` — attack surface, trust boundaries, threats, mitigations,
|
|
27
|
+
and fail-closed defaults
|
|
28
|
+
|
|
29
|
+
#### Documentation Sync
|
|
30
|
+
- `docs/api.md` updated to v0.4.0
|
|
31
|
+
- README: deterministic replay and OTel marked available, roadmap bumped to v0.4.x
|
|
32
|
+
- Test count badge updated to 300
|
|
33
|
+
|
|
34
|
+
## [0.3.2] — 2026-07-08
|
|
35
|
+
|
|
36
|
+
### YAML Policy DSL Expansion
|
|
37
|
+
- 13 new condition matchers (total 20): `amount_eq/gte/lte`, generic `field_eq` prefix, `role_count_gte`, `clearance_eq`, `tenant_id_eq`, `classification_eq`, `tags_contains`, `risk_level_eq`, `capabilities_contains`, `requires_credentials`, `session_risk_gt`, `prompt_risk_gt`
|
|
38
|
+
- AND/OR/NOT combinators (`any`/`all`/`not`, nestable in `when:` blocks)
|
|
39
|
+
- Policy schema validation (`policies/validator.py`): validates version, name, rules, effect values
|
|
40
|
+
|
|
41
|
+
### CredentialBroker Phase 2
|
|
42
|
+
- `BaseTool.credential_name` field — decouple tool name from credential name
|
|
43
|
+
- `ScopedToken.max_uses` + use counting — one-time tokens (`max_uses=1`)
|
|
44
|
+
- `ScopedToken.uses_remaining` property + `use()` method
|
|
45
|
+
- `revoke_all_for_tool(tool_name)` — revoke tokens for a specific tool
|
|
46
|
+
- `revoke_all()` — revoke everything (session-end cleanup)
|
|
47
|
+
- `active_token_count` property + `list_active_tokens()`
|
|
48
|
+
- Environment uses `credential_name` mapping when injecting tokens
|
|
49
|
+
- Session-end credential cleanup
|
|
50
|
+
|
|
51
|
+
## [0.3.1] — 2026-07-08
|
|
52
|
+
|
|
53
|
+
### Credential Event Safety (P0 security fix)
|
|
54
|
+
- Event log no longer stores `ScopedToken` objects — replaced with `{"credential_ref": ..., "tool_name": ..., "redacted": True}`
|
|
55
|
+
- Untrusted event sinks cannot access `.get_secret()` via event introspection
|
|
56
|
+
|
|
57
|
+
### Agent/Session credential_broker API
|
|
58
|
+
- `Agent(credential_broker=broker)` — first-class parameter
|
|
59
|
+
- `Session` passes broker to `RuntimeEnvironment`
|
|
60
|
+
- `RuntimeEnvironment` field renamed `_credential_broker` → `credential_broker`
|
|
61
|
+
|
|
62
|
+
### Documentation Sync
|
|
63
|
+
- `docs/api.md` version updated
|
|
64
|
+
- README roadmap: v0.3.x (current)
|
|
65
|
+
- README: added YAML Policy Engine + CredentialBroker usage examples
|
|
66
|
+
|
|
5
67
|
## [0.3.0] — 2026-07-08
|
|
6
68
|
|
|
7
69
|
### v0.3.0 Policy Engine + Credential Broker Integration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: petfishframework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A lightweight runtime framework for reliable, auditable, budget-aware, and permission-aware AI agents.
|
|
5
5
|
Project-URL: Homepage, https://github.com/kylecui/petfishFramework
|
|
6
6
|
Project-URL: Documentation, https://github.com/kylecui/petfishFramework/tree/master/docs
|
|
@@ -26,6 +26,11 @@ Provides-Extra: mcp
|
|
|
26
26
|
Requires-Dist: mcp>=1.0; extra == 'mcp'
|
|
27
27
|
Provides-Extra: openai
|
|
28
28
|
Requires-Dist: openai>=1.0; extra == 'openai'
|
|
29
|
+
Provides-Extra: otel
|
|
30
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == 'otel'
|
|
31
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'otel'
|
|
32
|
+
Provides-Extra: vault
|
|
33
|
+
Requires-Dist: hvac>=1.0; extra == 'vault'
|
|
29
34
|
Description-Content-Type: text/markdown
|
|
30
35
|
|
|
31
36
|
# petfishFramework
|
|
@@ -34,7 +39,7 @@ Description-Content-Type: text/markdown
|
|
|
34
39
|
|
|
35
40
|
[](https://www.python.org/downloads/)
|
|
36
41
|
[](https://github.com/kylecui/petfishFramework/blob/master/LICENSE)
|
|
37
|
-
[](https://github.com/kylecui/petfishFramework/tree/master/tests/)
|
|
38
43
|
|
|
39
44
|
**Status: Alpha** — API may change. Core runtime works; see [Roadmap](#roadmap).
|
|
40
45
|
|
|
@@ -247,8 +252,8 @@ agent = Agent(model=model, reasoning=ReAct(), tools=tools, credential_broker=bro
|
|
|
247
252
|
## Roadmap
|
|
248
253
|
|
|
249
254
|
- **v0.2.x**: Core runtime, permission semantics, enterprise PoC, Trusted Publishing ✅
|
|
250
|
-
- **v0.3.x
|
|
251
|
-
- **v0.4.x
|
|
255
|
+
- **v0.3.x**: YAML Policy Engine, CredentialBroker ✅
|
|
256
|
+
- **v0.4.x** (current): Production hardening, deployment guides, Vault adapter, Docker, threat model ✅
|
|
252
257
|
|
|
253
258
|
## Current Limitations
|
|
254
259
|
|
|
@@ -263,8 +268,8 @@ petfishFramework is **Alpha**. API may change before v1.0.
|
|
|
263
268
|
| PARTIAL_ALLOW | ✅ Enforced (pre-execution arg filtering) |
|
|
264
269
|
| MASK | ✅ Enforced (input mask before + output mask after) |
|
|
265
270
|
| DEGRADE | ✅ Enforced (fallback tool switching) |
|
|
266
|
-
| Session replay
|
|
267
|
-
|
|
|
271
|
+
| Session replay / deterministic rerun / resume | ✅ Available |
|
|
272
|
+
| OpenTelemetry + SIEM observability | ✅ Available |
|
|
268
273
|
| MCP client stdio | ✅ Available |
|
|
269
274
|
| MCP server mode | 📋 Planned |
|
|
270
275
|
| Structured output / conversation memory | ✅ Available |
|
|
@@ -279,7 +284,7 @@ petfishFramework is **Alpha**. API may change before v1.0.
|
|
|
279
284
|
git clone https://github.com/kylecui/petfishFramework.git
|
|
280
285
|
cd petfishFramework
|
|
281
286
|
uv sync --all-extras
|
|
282
|
-
uv run pytest #
|
|
287
|
+
uv run pytest # 300 tests
|
|
283
288
|
uv run ruff check src/ tests/
|
|
284
289
|
```
|
|
285
290
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.python.org/downloads/)
|
|
6
6
|
[](https://github.com/kylecui/petfishFramework/blob/master/LICENSE)
|
|
7
|
-
[](https://github.com/kylecui/petfishFramework/tree/master/tests/)
|
|
8
8
|
|
|
9
9
|
**Status: Alpha** — API may change. Core runtime works; see [Roadmap](#roadmap).
|
|
10
10
|
|
|
@@ -217,8 +217,8 @@ agent = Agent(model=model, reasoning=ReAct(), tools=tools, credential_broker=bro
|
|
|
217
217
|
## Roadmap
|
|
218
218
|
|
|
219
219
|
- **v0.2.x**: Core runtime, permission semantics, enterprise PoC, Trusted Publishing ✅
|
|
220
|
-
- **v0.3.x
|
|
221
|
-
- **v0.4.x
|
|
220
|
+
- **v0.3.x**: YAML Policy Engine, CredentialBroker ✅
|
|
221
|
+
- **v0.4.x** (current): Production hardening, deployment guides, Vault adapter, Docker, threat model ✅
|
|
222
222
|
|
|
223
223
|
## Current Limitations
|
|
224
224
|
|
|
@@ -233,8 +233,8 @@ petfishFramework is **Alpha**. API may change before v1.0.
|
|
|
233
233
|
| PARTIAL_ALLOW | ✅ Enforced (pre-execution arg filtering) |
|
|
234
234
|
| MASK | ✅ Enforced (input mask before + output mask after) |
|
|
235
235
|
| DEGRADE | ✅ Enforced (fallback tool switching) |
|
|
236
|
-
| Session replay
|
|
237
|
-
|
|
|
236
|
+
| Session replay / deterministic rerun / resume | ✅ Available |
|
|
237
|
+
| OpenTelemetry + SIEM observability | ✅ Available |
|
|
238
238
|
| MCP client stdio | ✅ Available |
|
|
239
239
|
| MCP server mode | 📋 Planned |
|
|
240
240
|
| Structured output / conversation memory | ✅ Available |
|
|
@@ -249,7 +249,7 @@ petfishFramework is **Alpha**. API may change before v1.0.
|
|
|
249
249
|
git clone https://github.com/kylecui/petfishFramework.git
|
|
250
250
|
cd petfishFramework
|
|
251
251
|
uv sync --all-extras
|
|
252
|
-
uv run pytest #
|
|
252
|
+
uv run pytest # 300 tests
|
|
253
253
|
uv run ruff check src/ tests/
|
|
254
254
|
```
|
|
255
255
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# petfishFramework API Reference
|
|
2
2
|
|
|
3
|
-
This document is the authoritative reference for the public API of
|
|
3
|
+
This document is the authoritative reference for the public API of petfishFramework v0.4.0. Every signature, field, and example below is derived from the source code and from the tests that exercise it.
|
|
4
4
|
|
|
5
5
|
## 1. Overview
|
|
6
6
|
|
|
@@ -1294,3 +1294,178 @@ decision.policy_name # "enterprise-expense-policy"
|
|
|
1294
1294
|
```
|
|
1295
1295
|
|
|
1296
1296
|
This lets audit logs trace each decision back to the policy file version that produced it.
|
|
1297
|
+
|
|
1298
|
+
### AND/OR/NOT Combinators (v0.3.2)
|
|
1299
|
+
|
|
1300
|
+
`when:` blocks support `any`/`all`/`not` combinators:
|
|
1301
|
+
|
|
1302
|
+
```yaml
|
|
1303
|
+
when:
|
|
1304
|
+
any:
|
|
1305
|
+
- action.tool_name: approve_payment
|
|
1306
|
+
- action.tool_name: transfer_funds
|
|
1307
|
+
|
|
1308
|
+
when:
|
|
1309
|
+
not:
|
|
1310
|
+
subject.role_in: [admin]
|
|
1311
|
+
|
|
1312
|
+
when:
|
|
1313
|
+
not:
|
|
1314
|
+
any:
|
|
1315
|
+
- subject.role_in: [admin]
|
|
1316
|
+
- subject.clearance_eq: secret
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
### Full matcher list (v0.3.2)
|
|
1320
|
+
|
|
1321
|
+
| Key | Description | Example |
|
|
1322
|
+
|---|---|---|
|
|
1323
|
+
| `action.tool_name` | Exact tool name match | `approve_payment` |
|
|
1324
|
+
| `subject.role_in` | Any role in list matches | `[finance, admin]` |
|
|
1325
|
+
| `subject.role_not_in` | No role in list matches | `[intern]` |
|
|
1326
|
+
| `subject.role_count_gte` | Subject has ≥ N roles | `2` |
|
|
1327
|
+
| `subject.clearance_eq` | Clearance level match | `confidential` |
|
|
1328
|
+
| `subject.tenant_id_eq` | Tenant ID match | `acme-corp` |
|
|
1329
|
+
| `action.args.amount_gt` | `args["amount"] > value` | `5000` |
|
|
1330
|
+
| `action.args.amount_lt` | `args["amount"] < value` | `100` |
|
|
1331
|
+
| `action.args.amount_eq` | `args["amount"] == value` | `500` |
|
|
1332
|
+
| `action.args.amount_gte` | `args["amount"] >= value` | `1000` |
|
|
1333
|
+
| `action.args.amount_lte` | `args["amount"] <= value` | `200` |
|
|
1334
|
+
| `action.args.<field>_eq` | Generic field equality (prefix matcher) | `recipient_eq: alice@` |
|
|
1335
|
+
| `resource.classification_eq` | Resource classification match | `internal` |
|
|
1336
|
+
| `resource.tags_contains` | Resource has any of the listed tags | `[pii, sensitive]` |
|
|
1337
|
+
| `tool.side_effect` | Match tool metadata | `true` |
|
|
1338
|
+
| `tool.external_egress` | Match tool metadata | `true` |
|
|
1339
|
+
| `tool.requires_credentials` | Match tool metadata | `true` |
|
|
1340
|
+
| `tool.risk_level_eq` | Match risk level | `high` |
|
|
1341
|
+
| `tool.capabilities_contains` | Tool has any of listed capabilities | `[network, fs:write]` |
|
|
1342
|
+
| `context.session_risk_gt` | `context.session_risk > value` | `0.5` |
|
|
1343
|
+
| `context.prompt_risk_gt` | `context.prompt_risk > value` | `0.7` |
|
|
1344
|
+
|
|
1345
|
+
Unknown condition keys are fail-closed (return `False`).
|
|
1346
|
+
|
|
1347
|
+
### Policy schema validation (v0.3.2)
|
|
1348
|
+
|
|
1349
|
+
```python
|
|
1350
|
+
from petfishframework.policies.validator import validate_policy, validate_policy_file
|
|
1351
|
+
|
|
1352
|
+
errors = validate_policy_file("enterprise-expense.yaml")
|
|
1353
|
+
if errors:
|
|
1354
|
+
for err in errors:
|
|
1355
|
+
print(f" - {err}")
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
Checks: version exists, name exists, rules is a list, each rule has name + valid effect, priority is integer.
|
|
1359
|
+
|
|
1360
|
+
---
|
|
1361
|
+
|
|
1362
|
+
## 16. Credential Broker
|
|
1363
|
+
|
|
1364
|
+
### CredentialBroker
|
|
1365
|
+
|
|
1366
|
+
```python
|
|
1367
|
+
from petfishframework.credentials import CredentialBroker
|
|
1368
|
+
|
|
1369
|
+
broker = CredentialBroker(default_ttl_s=3600)
|
|
1370
|
+
broker.register_credential("github_app", os.environ["GITHUB_TOKEN"])
|
|
1371
|
+
broker.register_credential("db_connection", "postgres://...")
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1374
|
+
| Method | Description |
|
|
1375
|
+
|---|---|
|
|
1376
|
+
| `register_credential(name, secret)` | Register a real credential |
|
|
1377
|
+
| `issue_token(name, tool_name, ttl_s=None, max_uses=0)` | Issue a scoped, time-limited token |
|
|
1378
|
+
| `validate_token(token_id)` | Check if token is valid (not expired, not revoked) |
|
|
1379
|
+
| `revoke_token(token_id)` | Revoke a single token |
|
|
1380
|
+
| `revoke_all_for_tool(tool_name)` | Revoke all tokens for a specific tool (v0.3.2) |
|
|
1381
|
+
| `revoke_all()` | Revoke all active tokens (session-end cleanup) (v0.3.2) |
|
|
1382
|
+
| `cleanup_expired()` | Remove expired tokens, returns count removed |
|
|
1383
|
+
| `active_token_count` | Property: number of active tokens (v0.3.2) |
|
|
1384
|
+
| `list_active_tokens()` | Return list of active token_ids (v0.3.2) |
|
|
1385
|
+
|
|
1386
|
+
### ScopedToken
|
|
1387
|
+
|
|
1388
|
+
```python
|
|
1389
|
+
token = broker.issue_token("github_app", tool_name="github_tool", max_uses=1)
|
|
1390
|
+
token.token_id # unique ID
|
|
1391
|
+
token.tool_name # "github_tool"
|
|
1392
|
+
token.is_valid() # True (not expired, uses remaining)
|
|
1393
|
+
token.get_secret() # returns the actual secret (consumes one use if max_uses set)
|
|
1394
|
+
token.uses_remaining # remaining uses (v0.3.2)
|
|
1395
|
+
```
|
|
1396
|
+
|
|
1397
|
+
`__repr__` and `__str__` never expose the secret:
|
|
1398
|
+
```python
|
|
1399
|
+
repr(token) # "ScopedToken(token_id='abc...', tool_name='github_tool', ...)"
|
|
1400
|
+
str(token) # "ScopedToken(abc..., tool=github_tool, valid=True)"
|
|
1401
|
+
```
|
|
1402
|
+
|
|
1403
|
+
### Agent Integration
|
|
1404
|
+
|
|
1405
|
+
```python
|
|
1406
|
+
agent = Agent(
|
|
1407
|
+
model=model,
|
|
1408
|
+
reasoning=ReAct(),
|
|
1409
|
+
tools=tools,
|
|
1410
|
+
credential_broker=broker,
|
|
1411
|
+
)
|
|
1412
|
+
# Tools with requires_credentials=True receive a ScopedToken in args["_credential_token"]
|
|
1413
|
+
```
|
|
1414
|
+
|
|
1415
|
+
### Tool credential_name (v0.3.2)
|
|
1416
|
+
|
|
1417
|
+
```python
|
|
1418
|
+
@dataclass
|
|
1419
|
+
class GitHubTool(BaseTool):
|
|
1420
|
+
name: str = "github_create_issue"
|
|
1421
|
+
requires_credentials: bool = True
|
|
1422
|
+
credential_name: str = "github_app" # maps to broker credential name
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
### Event Log Safety
|
|
1426
|
+
|
|
1427
|
+
ScopedToken objects are **never** stored in event data. The Environment replaces them with:
|
|
1428
|
+
|
|
1429
|
+
```python
|
|
1430
|
+
{"credential_ref": "token_id", "tool_name": "github_tool", "redacted": True}
|
|
1431
|
+
```
|
|
1432
|
+
|
|
1433
|
+
### One-time Tokens (v0.3.2)
|
|
1434
|
+
|
|
1435
|
+
```python
|
|
1436
|
+
token = broker.issue_token("secret_key", tool_name="signing_tool", max_uses=1)
|
|
1437
|
+
token.get_secret() # works, uses_remaining becomes 0
|
|
1438
|
+
token.get_secret() # raises ValueError("max uses exceeded")
|
|
1439
|
+
```
|
|
1440
|
+
|
|
1441
|
+
### Session-End Cleanup
|
|
1442
|
+
|
|
1443
|
+
```python
|
|
1444
|
+
# In Session._finalize_run():
|
|
1445
|
+
if session.credential_broker:
|
|
1446
|
+
session.credential_broker.cleanup_expired()
|
|
1447
|
+
```
|
|
1448
|
+
|
|
1449
|
+
### Vault Integration (v0.4.0)
|
|
1450
|
+
|
|
1451
|
+
```python
|
|
1452
|
+
from petfishframework.credentials import CredentialBroker, VaultCredentialSource
|
|
1453
|
+
|
|
1454
|
+
broker = CredentialBroker()
|
|
1455
|
+
source = VaultCredentialSource(
|
|
1456
|
+
vault_url="https://vault.example.com",
|
|
1457
|
+
token="hvs.CAES...",
|
|
1458
|
+
)
|
|
1459
|
+
broker.register_credential_from_vault("openai", source, path="secrets/openai")
|
|
1460
|
+
```
|
|
1461
|
+
|
|
1462
|
+
`VaultCredentialSource` performs a lazy import of `hvac` and raises a clear
|
|
1463
|
+
`ImportError` if the optional dependency is missing. The secret is read once and
|
|
1464
|
+
cached locally for the lifetime of the source; subsequent reads of the same
|
|
1465
|
+
path do not call Vault again.
|
|
1466
|
+
|
|
1467
|
+
Install the optional dependency with:
|
|
1468
|
+
|
|
1469
|
+
```bash
|
|
1470
|
+
pip install petfishframework[vault]
|
|
1471
|
+
```
|