spctre-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. spctre_sdk-0.1.0/.gitignore +60 -0
  2. spctre_sdk-0.1.0/PKG-INFO +145 -0
  3. spctre_sdk-0.1.0/README.md +127 -0
  4. spctre_sdk-0.1.0/pyproject.toml +57 -0
  5. spctre_sdk-0.1.0/spctre/__init__.py +43 -0
  6. spctre_sdk-0.1.0/spctre/_generated/__init__.py +8 -0
  7. spctre_sdk-0.1.0/spctre/_generated/api/__init__.py +1 -0
  8. spctre_sdk-0.1.0/spctre/_generated/api/approvals/__init__.py +1 -0
  9. spctre_sdk-0.1.0/spctre/_generated/api/approvals/get_approval.py +174 -0
  10. spctre_sdk-0.1.0/spctre/_generated/api/auth/__init__.py +1 -0
  11. spctre_sdk-0.1.0/spctre/_generated/api/auth/refresh_token.py +203 -0
  12. spctre_sdk-0.1.0/spctre/_generated/api/auth/revoke_token.py +149 -0
  13. spctre_sdk-0.1.0/spctre/_generated/api/blueprint/__init__.py +1 -0
  14. spctre_sdk-0.1.0/spctre/_generated/api/blueprint/import_blueprint.py +217 -0
  15. spctre_sdk-0.1.0/spctre/_generated/api/bundle/__init__.py +1 -0
  16. spctre_sdk-0.1.0/spctre/_generated/api/bundle/get_bundle_latest.py +312 -0
  17. spctre_sdk-0.1.0/spctre/_generated/api/bundle/retain_latest_published_bundle.py +162 -0
  18. spctre_sdk-0.1.0/spctre/_generated/api/compliance/__init__.py +1 -0
  19. spctre_sdk-0.1.0/spctre/_generated/api/compliance/export_compliance.py +217 -0
  20. spctre_sdk-0.1.0/spctre/_generated/api/evidence/__init__.py +1 -0
  21. spctre_sdk-0.1.0/spctre/_generated/api/evidence/forensic_evidence_query.py +261 -0
  22. spctre_sdk-0.1.0/spctre/_generated/api/evidence/get_policy_content_artifact.py +192 -0
  23. spctre_sdk-0.1.0/spctre/_generated/api/evidence/ingest_evidence.py +206 -0
  24. spctre_sdk-0.1.0/spctre/_generated/api/evidence/ingest_git_checkpoint.py +210 -0
  25. spctre_sdk-0.1.0/spctre/_generated/api/evidence/retain_policy_content_artifact.py +211 -0
  26. spctre_sdk-0.1.0/spctre/_generated/api/gateway/__init__.py +1 -0
  27. spctre_sdk-0.1.0/spctre/_generated/api/gateway/gateway_decide.py +192 -0
  28. spctre_sdk-0.1.0/spctre/_generated/api/gateway/gateway_resolve.py +188 -0
  29. spctre_sdk-0.1.0/spctre/_generated/api/gateway/get_escalation_status.py +189 -0
  30. spctre_sdk-0.1.0/spctre/_generated/api/gateway/ingest_helicone_gateway_event.py +197 -0
  31. spctre_sdk-0.1.0/spctre/_generated/api/gateway/ingest_lite_llm_gateway_event.py +197 -0
  32. spctre_sdk-0.1.0/spctre/_generated/api/gateway/ingest_notion_gateway_event.py +201 -0
  33. spctre_sdk-0.1.0/spctre/_generated/api/gateway/ingest_portkey_gateway_event.py +197 -0
  34. spctre_sdk-0.1.0/spctre/_generated/api/gateway/list_escalations.py +178 -0
  35. spctre_sdk-0.1.0/spctre/_generated/api/gateway/register_agt_escalation_request.py +175 -0
  36. spctre_sdk-0.1.0/spctre/_generated/api/meta/__init__.py +1 -0
  37. spctre_sdk-0.1.0/spctre/_generated/api/meta/get_open_api_spec.py +136 -0
  38. spctre_sdk-0.1.0/spctre/_generated/api/policy/__init__.py +1 -0
  39. spctre_sdk-0.1.0/spctre/_generated/api/policy/import_policy.py +209 -0
  40. spctre_sdk-0.1.0/spctre/_generated/api/scim/__init__.py +1 -0
  41. spctre_sdk-0.1.0/spctre/_generated/api/scim/scim_create_user.py +180 -0
  42. spctre_sdk-0.1.0/spctre/_generated/api/scim/scim_list_users.py +210 -0
  43. spctre_sdk-0.1.0/spctre/_generated/api/simulation/__init__.py +1 -0
  44. spctre_sdk-0.1.0/spctre/_generated/api/simulation/evaluate_policy.py +193 -0
  45. spctre_sdk-0.1.0/spctre/_generated/api/trust/__init__.py +1 -0
  46. spctre_sdk-0.1.0/spctre/_generated/api/trust/evaluate_trust_governance.py +190 -0
  47. spctre_sdk-0.1.0/spctre/_generated/api/trust/ingest_context_budget_event.py +190 -0
  48. spctre_sdk-0.1.0/spctre/_generated/api/trust/ingest_trust_score.py +188 -0
  49. spctre_sdk-0.1.0/spctre/_generated/api/verification/__init__.py +1 -0
  50. spctre_sdk-0.1.0/spctre/_generated/api/verification/ingest_verification.py +183 -0
  51. spctre_sdk-0.1.0/spctre/_generated/api/verification/list_verifications.py +204 -0
  52. spctre_sdk-0.1.0/spctre/_generated/client.py +282 -0
  53. spctre_sdk-0.1.0/spctre/_generated/errors.py +16 -0
  54. spctre_sdk-0.1.0/spctre/_generated/models/__init__.py +317 -0
  55. spctre_sdk-0.1.0/spctre/_generated/models/api_error.py +100 -0
  56. spctre_sdk-0.1.0/spctre/_generated/models/api_error_issues_item.py +70 -0
  57. spctre_sdk-0.1.0/spctre/_generated/models/api_meta.py +78 -0
  58. spctre_sdk-0.1.0/spctre/_generated/models/approval_response.py +77 -0
  59. spctre_sdk-0.1.0/spctre/_generated/models/approval_response_approval.py +47 -0
  60. spctre_sdk-0.1.0/spctre/_generated/models/blueprint_import_request.py +74 -0
  61. spctre_sdk-0.1.0/spctre/_generated/models/blueprint_import_response.py +124 -0
  62. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_blocked_response.py +85 -0
  63. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_envelope.py +112 -0
  64. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_envelope_artifact_type_1.py +47 -0
  65. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_format.py +12 -0
  66. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_manifest.py +159 -0
  67. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_manifest_compatibility_level.py +10 -0
  68. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_manifest_provenance.py +148 -0
  69. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_manifest_provenance_target_stacks_item.py +47 -0
  70. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_preview_response.py +85 -0
  71. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_verification.py +91 -0
  72. spctre_sdk-0.1.0/spctre/_generated/models/bundle_export_verification_failed_response.py +95 -0
  73. spctre_sdk-0.1.0/spctre/_generated/models/bundle_response.py +50 -0
  74. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response.py +305 -0
  75. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_approvals_item.py +47 -0
  76. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_artifact.py +47 -0
  77. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_escalations_item.py +47 -0
  78. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_framework_annotation_type_0.py +47 -0
  79. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_retention_plan_type_0.py +47 -0
  80. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_summary.py +126 -0
  81. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_timeline_item.py +47 -0
  82. spctre_sdk-0.1.0/spctre/_generated/models/compliance_export_response_verification_results_type_0.py +47 -0
  83. spctre_sdk-0.1.0/spctre/_generated/models/context_budget_ingest_request.py +192 -0
  84. spctre_sdk-0.1.0/spctre/_generated/models/context_budget_ingest_request_context_source_mix.py +47 -0
  85. spctre_sdk-0.1.0/spctre/_generated/models/context_budget_ingest_request_event_type.py +11 -0
  86. spctre_sdk-0.1.0/spctre/_generated/models/context_budget_ingest_request_governance_action.py +11 -0
  87. spctre_sdk-0.1.0/spctre/_generated/models/credential_grant.py +86 -0
  88. spctre_sdk-0.1.0/spctre/_generated/models/escalation_queue_item.py +194 -0
  89. spctre_sdk-0.1.0/spctre/_generated/models/escalation_status_response.py +257 -0
  90. spctre_sdk-0.1.0/spctre/_generated/models/escalation_status_response_approved_tool_parameters.py +52 -0
  91. spctre_sdk-0.1.0/spctre/_generated/models/escalation_status_response_resolution_outcome.py +10 -0
  92. spctre_sdk-0.1.0/spctre/_generated/models/escalation_status_response_status.py +11 -0
  93. spctre_sdk-0.1.0/spctre/_generated/models/evaluate_request.py +124 -0
  94. spctre_sdk-0.1.0/spctre/_generated/models/evaluate_request_tool_parameters.py +47 -0
  95. spctre_sdk-0.1.0/spctre/_generated/models/evaluate_response.py +150 -0
  96. spctre_sdk-0.1.0/spctre/_generated/models/evaluate_response_result.py +47 -0
  97. spctre_sdk-0.1.0/spctre/_generated/models/evaluate_trust_governance_response_200.py +47 -0
  98. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request.py +567 -0
  99. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request_execution_context.py +107 -0
  100. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request_ingest_mode.py +9 -0
  101. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request_orchestrator_ref.py +91 -0
  102. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request_plugin_source.py +11 -0
  103. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request_raw_evidence.py +47 -0
  104. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request_skill_context.py +96 -0
  105. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_request_tool_parameters.py +47 -0
  106. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_response.py +112 -0
  107. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_response_evidence.py +47 -0
  108. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_response_gateway.py +109 -0
  109. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_response_gateway_outcome.py +10 -0
  110. spctre_sdk-0.1.0/spctre/_generated/models/evidence_ingest_response_gateway_risk_level.py +11 -0
  111. spctre_sdk-0.1.0/spctre/_generated/models/evidence_layer.py +9 -0
  112. spctre_sdk-0.1.0/spctre/_generated/models/export_compliance_format.py +9 -0
  113. spctre_sdk-0.1.0/spctre/_generated/models/export_compliance_framework.py +15 -0
  114. spctre_sdk-0.1.0/spctre/_generated/models/forensic_evidence_query_response_200.py +47 -0
  115. spctre_sdk-0.1.0/spctre/_generated/models/forensic_evidence_query_response_402.py +119 -0
  116. spctre_sdk-0.1.0/spctre/_generated/models/forensic_evidence_query_response_402_plan.py +8 -0
  117. spctre_sdk-0.1.0/spctre/_generated/models/gateway_decision.py +120 -0
  118. spctre_sdk-0.1.0/spctre/_generated/models/gateway_decision_outcome.py +10 -0
  119. spctre_sdk-0.1.0/spctre/_generated/models/gateway_decision_request.py +284 -0
  120. spctre_sdk-0.1.0/spctre/_generated/models/gateway_decision_request_risk_level.py +11 -0
  121. spctre_sdk-0.1.0/spctre/_generated/models/gateway_decision_request_tool_parameters.py +47 -0
  122. spctre_sdk-0.1.0/spctre/_generated/models/gateway_decision_response.py +109 -0
  123. spctre_sdk-0.1.0/spctre/_generated/models/gateway_decision_risk_level.py +11 -0
  124. spctre_sdk-0.1.0/spctre/_generated/models/gateway_ingest_response.py +92 -0
  125. spctre_sdk-0.1.0/spctre/_generated/models/gateway_resolve_request.py +94 -0
  126. spctre_sdk-0.1.0/spctre/_generated/models/gateway_resolve_request_resolution_outcome.py +10 -0
  127. spctre_sdk-0.1.0/spctre/_generated/models/gateway_resolve_response_200.py +83 -0
  128. spctre_sdk-0.1.0/spctre/_generated/models/gateway_webhook_request.py +50 -0
  129. spctre_sdk-0.1.0/spctre/_generated/models/get_open_api_spec_response_200.py +47 -0
  130. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request.py +182 -0
  131. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_agent.py +70 -0
  132. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_checkpoint.py +132 -0
  133. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_checkpoint_diff.py +119 -0
  134. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_checkpoint_diff_files_item.py +91 -0
  135. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_checkpoint_diff_files_item_status.py +13 -0
  136. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_checkpoint_diff_format.py +10 -0
  137. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_checkpoint_repository.py +72 -0
  138. spctre_sdk-0.1.0/spctre/_generated/models/git_checkpoint_ingest_request_metadata.py +47 -0
  139. spctre_sdk-0.1.0/spctre/_generated/models/ingest_context_budget_event_response_201.py +47 -0
  140. spctre_sdk-0.1.0/spctre/_generated/models/ingest_trust_score_response_201.py +47 -0
  141. spctre_sdk-0.1.0/spctre/_generated/models/list_escalations_response_200.py +141 -0
  142. spctre_sdk-0.1.0/spctre/_generated/models/list_verifications_response_200.py +147 -0
  143. spctre_sdk-0.1.0/spctre/_generated/models/list_verifications_response_200_results_item.py +47 -0
  144. spctre_sdk-0.1.0/spctre/_generated/models/pagination.py +77 -0
  145. spctre_sdk-0.1.0/spctre/_generated/models/policy_content_artifact_retain_response.py +83 -0
  146. spctre_sdk-0.1.0/spctre/_generated/models/policy_import_request.py +127 -0
  147. spctre_sdk-0.1.0/spctre/_generated/models/policy_import_request_scope.py +11 -0
  148. spctre_sdk-0.1.0/spctre/_generated/models/policy_import_response.py +115 -0
  149. spctre_sdk-0.1.0/spctre/_generated/models/register_agt_escalation_request_body.py +69 -0
  150. spctre_sdk-0.1.0/spctre/_generated/models/retain_latest_published_bundle_response_201.py +91 -0
  151. spctre_sdk-0.1.0/spctre/_generated/models/runtime_decision_status.py +11 -0
  152. spctre_sdk-0.1.0/spctre/_generated/models/runtime_policy_context.py +115 -0
  153. spctre_sdk-0.1.0/spctre/_generated/models/runtime_policy_context_scope.py +12 -0
  154. spctre_sdk-0.1.0/spctre/_generated/models/runtime_stack.py +26 -0
  155. spctre_sdk-0.1.0/spctre/_generated/models/runtime_target.py +101 -0
  156. spctre_sdk-0.1.0/spctre/_generated/models/scim_create_user_body.py +47 -0
  157. spctre_sdk-0.1.0/spctre/_generated/models/scim_create_user_response_201.py +47 -0
  158. spctre_sdk-0.1.0/spctre/_generated/models/scim_create_user_response_402.py +117 -0
  159. spctre_sdk-0.1.0/spctre/_generated/models/scim_create_user_response_402_plan.py +8 -0
  160. spctre_sdk-0.1.0/spctre/_generated/models/scim_list_users_response_200.py +47 -0
  161. spctre_sdk-0.1.0/spctre/_generated/models/scim_list_users_response_402.py +117 -0
  162. spctre_sdk-0.1.0/spctre/_generated/models/scim_list_users_response_402_plan.py +8 -0
  163. spctre_sdk-0.1.0/spctre/_generated/models/token_refresh_request.py +61 -0
  164. spctre_sdk-0.1.0/spctre/_generated/models/token_refresh_response.py +104 -0
  165. spctre_sdk-0.1.0/spctre/_generated/models/trigger_kind.py +13 -0
  166. spctre_sdk-0.1.0/spctre/_generated/models/trust_evaluate_request.py +160 -0
  167. spctre_sdk-0.1.0/spctre/_generated/models/trust_evaluate_request_consequence_tier.py +11 -0
  168. spctre_sdk-0.1.0/spctre/_generated/models/trust_score_ingest_request.py +115 -0
  169. spctre_sdk-0.1.0/spctre/_generated/models/trust_score_ingest_request_source.py +12 -0
  170. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_request.py +369 -0
  171. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_request_compatibility_check_outcome.py +10 -0
  172. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_request_escrow_verification_outcome.py +10 -0
  173. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_request_outcome.py +10 -0
  174. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_request_summary.py +47 -0
  175. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_request_verification_type.py +13 -0
  176. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_response.py +97 -0
  177. spctre_sdk-0.1.0/spctre/_generated/models/verification_ingest_response_outcome.py +10 -0
  178. spctre_sdk-0.1.0/spctre/_generated/types.py +54 -0
  179. spctre_sdk-0.1.0/spctre/_url.py +52 -0
  180. spctre_sdk-0.1.0/spctre/_version.py +1 -0
  181. spctre_sdk-0.1.0/spctre/client.py +313 -0
  182. spctre_sdk-0.1.0/spctre/errors.py +160 -0
  183. spctre_sdk-0.1.0/spctre/models.py +15 -0
  184. spctre_sdk-0.1.0/spctre/py.typed +0 -0
@@ -0,0 +1,60 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnpm-store/
4
+
5
+ # pnpm is the sole package manager; reject stray npm/yarn lockfiles
6
+ package-lock.json
7
+ yarn.lock
8
+
9
+ # Environment and local secrets
10
+ .env
11
+ .env.*
12
+ !.env*.example
13
+
14
+ # Build outputs
15
+ dist/
16
+ target/
17
+ apps/web/.next/
18
+ apps/web/.source/
19
+ apps/worker/dist/
20
+ packages/cli/dist/
21
+ packages/mcp-server/dist/
22
+ packages/policy-schema/dist/
23
+ packages/policy-schema/native/target/
24
+ packages/ui/storybook-static/
25
+
26
+ # Caches and test output
27
+ .turbo/
28
+ .cache/
29
+ coverage/
30
+ cover.out
31
+ .nyc_output/
32
+ .pytest_cache/
33
+ .ruff_cache/
34
+ __pycache__/
35
+ *.tsbuildinfo
36
+
37
+ # Native artifacts
38
+ *.node
39
+
40
+ # Local tooling
41
+ .venv/
42
+ .agents/
43
+ .antigravitycli/
44
+ .claude/
45
+ .codex/
46
+ .impeccable/
47
+ .vscode/
48
+ .idea/
49
+ .spctre/
50
+ packages/cli/.spctre/
51
+ .polly/
52
+ .worktrees/
53
+ .pi/
54
+
55
+ # Local notes and OS files
56
+ concepts/
57
+ .DS_Store
58
+ .playwright-cli/
59
+ DESIGN.md
60
+ PRODUCT.md
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: spctre-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the Spctre policy operations control plane.
5
+ Project-URL: Homepage, https://spctre.dev
6
+ Project-URL: Source, https://github.com/getspctre/spctre
7
+ Author-email: Spctre <support@spctre.dev>
8
+ License-Expression: Apache-2.0
9
+ Keywords: agents,governance,policy,spctre
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: attrs>=22.2.0
12
+ Requires-Dist: httpx<0.29.0,>=0.23.0
13
+ Requires-Dist: python-dateutil>=2.8.0
14
+ Provides-Extra: test
15
+ Requires-Dist: pyrefly==1.1.0; extra == 'test'
16
+ Requires-Dist: pytest>=9.0.3; extra == 'test'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # spctre-sdk
20
+
21
+ Python client for the [Spctre](https://spctre.dev) policy operations control plane.
22
+
23
+ ```sh
24
+ pip install spctre-sdk
25
+ ```
26
+
27
+ Requires Python 3.11+.
28
+
29
+ ## Usage
30
+
31
+ ```python
32
+ from spctre import SpctreClient
33
+ from spctre.models import GatewayDecisionRequest
34
+
35
+ client = SpctreClient(
36
+ base_url="https://app-staging.spctre.dev",
37
+ token=token,
38
+ )
39
+
40
+ decision = client.gateway.decide(
41
+ GatewayDecisionRequest(
42
+ decision_id="d-1",
43
+ artifact_hash="sha256:...",
44
+ policy_context=[...],
45
+ )
46
+ )
47
+
48
+ if decision.decision.outcome.value == "PROCEED":
49
+ ... # act
50
+ client.evidence.ingest(record)
51
+ ```
52
+
53
+ `base_url` is the deployment origin, not the API root — the client owns the
54
+ `/api/v1` path segment. Staging, production and self-hosted deployments differ
55
+ only in this value:
56
+
57
+ | Given | Requests go to |
58
+ | ------------------------------------- | ------------------------------------------------ |
59
+ | `https://app-staging.spctre.dev` | `https://app-staging.spctre.dev/api/v1/...` |
60
+ | `http://localhost:3000` | `http://localhost:3000/api/v1/...` |
61
+ | `https://internal.example.com/spctre` | `https://internal.example.com/spctre/api/v1/...` |
62
+
63
+ A URL that already ends in `/api/v1` is accepted as-is rather than doubled.
64
+
65
+ ## Domains
66
+
67
+ The client is organized by product domain, following the control-plane loop:
68
+ policy changes become published controls, controls produce enforced decisions,
69
+ decisions produce evidence, evidence supports assurance.
70
+
71
+ | Domain | Operations |
72
+ | --------------------- | --------------------------------------------------------------------------------------- |
73
+ | `client.gateway` | `decide`, `resolve`, `escalation_status`, `list_escalations`, `register_agt_escalation` |
74
+ | `client.evidence` | `ingest`, `ingest_git_checkpoint`, `forensic_query` |
75
+ | `client.policy` | `import_policy` |
76
+ | `client.trust` | `ingest_score`, `evaluate`, `ingest_context_budget` |
77
+ | `client.verification` | `ingest`, `list` |
78
+ | `client.bundle` | `latest`, `retain_latest` |
79
+ | `client.compliance` | `export` |
80
+ | `client.approvals` | `get` |
81
+
82
+ Models come from `spctre.models`. Field names are snake_case in Python and are
83
+ serialized to the API's camelCase automatically.
84
+
85
+ Operations outside these domains — SCIM, auth token rotation, blueprint import,
86
+ simulation — are reachable through `spctre._generated`, which is regenerated
87
+ wholesale from the OpenAPI spec and carries no stability promise. Anything you
88
+ find yourself needing there is a reasonable thing to request as a facade
89
+ addition.
90
+
91
+ ## Errors
92
+
93
+ Every failure is raised as a `SpctreError` subclass. Generated exceptions never
94
+ escape:
95
+
96
+ | Raised | When |
97
+ | ----------------------- | ------------------------------------------- |
98
+ | `SpctreAuthError` | 401: token missing, expired, or revoked |
99
+ | `SpctrePermissionError` | 403: token lacks the required scope |
100
+ | `SpctreRequestError` | other 4xx |
101
+ | `SpctreServerError` | 5xx |
102
+ | `SpctreTransportError` | no HTTP response at all (DNS, TLS, timeout) |
103
+ | `SpctreResponseError` | answered, but the response did not parse |
104
+
105
+ Each carries `status`, `body`, and `trace_id` lifted from the response
106
+ envelope's `meta.traceId` — quote it when reporting a problem.
107
+
108
+ `SpctreResponseError` is deliberately distinct from `SpctreTransportError`: it
109
+ means the client and the deployment disagree about the API contract, usually an
110
+ SDK too old or too new for the server. Reporting that as an unreachable host
111
+ would send debugging in the wrong direction.
112
+
113
+ ## Testing
114
+
115
+ `transport=` accepts any `httpx.BaseTransport`, so tests need no network:
116
+
117
+ ```python
118
+ import httpx
119
+ from spctre import SpctreClient
120
+
121
+
122
+ def handler(request: httpx.Request) -> httpx.Response:
123
+ assert request.url.path == "/api/v1/gateway/decide"
124
+ return httpx.Response(200, json={...})
125
+
126
+
127
+ client = SpctreClient(
128
+ base_url="https://app.example.com",
129
+ token="test-token",
130
+ transport=httpx.MockTransport(handler),
131
+ )
132
+ ```
133
+
134
+ ## How this package is built
135
+
136
+ `spctre._generated` is produced by
137
+ [openapi-python-client](https://github.com/openapi-generators/openapi-python-client)
138
+ from the control plane's OpenAPI spec, at a pinned generator version. Unlike
139
+ most generated code in this repository it is **checked in**, so installing or
140
+ building the package needs no code generator, and CI can assert the committed
141
+ client still matches the spec.
142
+
143
+ ## License
144
+
145
+ Apache-2.0
@@ -0,0 +1,127 @@
1
+ # spctre-sdk
2
+
3
+ Python client for the [Spctre](https://spctre.dev) policy operations control plane.
4
+
5
+ ```sh
6
+ pip install spctre-sdk
7
+ ```
8
+
9
+ Requires Python 3.11+.
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from spctre import SpctreClient
15
+ from spctre.models import GatewayDecisionRequest
16
+
17
+ client = SpctreClient(
18
+ base_url="https://app-staging.spctre.dev",
19
+ token=token,
20
+ )
21
+
22
+ decision = client.gateway.decide(
23
+ GatewayDecisionRequest(
24
+ decision_id="d-1",
25
+ artifact_hash="sha256:...",
26
+ policy_context=[...],
27
+ )
28
+ )
29
+
30
+ if decision.decision.outcome.value == "PROCEED":
31
+ ... # act
32
+ client.evidence.ingest(record)
33
+ ```
34
+
35
+ `base_url` is the deployment origin, not the API root — the client owns the
36
+ `/api/v1` path segment. Staging, production and self-hosted deployments differ
37
+ only in this value:
38
+
39
+ | Given | Requests go to |
40
+ | ------------------------------------- | ------------------------------------------------ |
41
+ | `https://app-staging.spctre.dev` | `https://app-staging.spctre.dev/api/v1/...` |
42
+ | `http://localhost:3000` | `http://localhost:3000/api/v1/...` |
43
+ | `https://internal.example.com/spctre` | `https://internal.example.com/spctre/api/v1/...` |
44
+
45
+ A URL that already ends in `/api/v1` is accepted as-is rather than doubled.
46
+
47
+ ## Domains
48
+
49
+ The client is organized by product domain, following the control-plane loop:
50
+ policy changes become published controls, controls produce enforced decisions,
51
+ decisions produce evidence, evidence supports assurance.
52
+
53
+ | Domain | Operations |
54
+ | --------------------- | --------------------------------------------------------------------------------------- |
55
+ | `client.gateway` | `decide`, `resolve`, `escalation_status`, `list_escalations`, `register_agt_escalation` |
56
+ | `client.evidence` | `ingest`, `ingest_git_checkpoint`, `forensic_query` |
57
+ | `client.policy` | `import_policy` |
58
+ | `client.trust` | `ingest_score`, `evaluate`, `ingest_context_budget` |
59
+ | `client.verification` | `ingest`, `list` |
60
+ | `client.bundle` | `latest`, `retain_latest` |
61
+ | `client.compliance` | `export` |
62
+ | `client.approvals` | `get` |
63
+
64
+ Models come from `spctre.models`. Field names are snake_case in Python and are
65
+ serialized to the API's camelCase automatically.
66
+
67
+ Operations outside these domains — SCIM, auth token rotation, blueprint import,
68
+ simulation — are reachable through `spctre._generated`, which is regenerated
69
+ wholesale from the OpenAPI spec and carries no stability promise. Anything you
70
+ find yourself needing there is a reasonable thing to request as a facade
71
+ addition.
72
+
73
+ ## Errors
74
+
75
+ Every failure is raised as a `SpctreError` subclass. Generated exceptions never
76
+ escape:
77
+
78
+ | Raised | When |
79
+ | ----------------------- | ------------------------------------------- |
80
+ | `SpctreAuthError` | 401: token missing, expired, or revoked |
81
+ | `SpctrePermissionError` | 403: token lacks the required scope |
82
+ | `SpctreRequestError` | other 4xx |
83
+ | `SpctreServerError` | 5xx |
84
+ | `SpctreTransportError` | no HTTP response at all (DNS, TLS, timeout) |
85
+ | `SpctreResponseError` | answered, but the response did not parse |
86
+
87
+ Each carries `status`, `body`, and `trace_id` lifted from the response
88
+ envelope's `meta.traceId` — quote it when reporting a problem.
89
+
90
+ `SpctreResponseError` is deliberately distinct from `SpctreTransportError`: it
91
+ means the client and the deployment disagree about the API contract, usually an
92
+ SDK too old or too new for the server. Reporting that as an unreachable host
93
+ would send debugging in the wrong direction.
94
+
95
+ ## Testing
96
+
97
+ `transport=` accepts any `httpx.BaseTransport`, so tests need no network:
98
+
99
+ ```python
100
+ import httpx
101
+ from spctre import SpctreClient
102
+
103
+
104
+ def handler(request: httpx.Request) -> httpx.Response:
105
+ assert request.url.path == "/api/v1/gateway/decide"
106
+ return httpx.Response(200, json={...})
107
+
108
+
109
+ client = SpctreClient(
110
+ base_url="https://app.example.com",
111
+ token="test-token",
112
+ transport=httpx.MockTransport(handler),
113
+ )
114
+ ```
115
+
116
+ ## How this package is built
117
+
118
+ `spctre._generated` is produced by
119
+ [openapi-python-client](https://github.com/openapi-generators/openapi-python-client)
120
+ from the control plane's OpenAPI spec, at a pinned generator version. Unlike
121
+ most generated code in this repository it is **checked in**, so installing or
122
+ building the package needs no code generator, and CI can assert the committed
123
+ client still matches the spec.
124
+
125
+ ## License
126
+
127
+ Apache-2.0
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "spctre-sdk"
7
+ dynamic = ["version"]
8
+ description = "Python SDK for the Spctre policy operations control plane."
9
+ readme = "README.md"
10
+ # 3.11, not 3.10: the generated client parses timestamps with
11
+ # datetime.fromisoformat, which did not accept the trailing `Z` until 3.11, and
12
+ # every API response carries a required meta.ts. Matches the adapter packages.
13
+ requires-python = ">=3.11"
14
+ license = "Apache-2.0"
15
+ authors = [{ name = "Spctre", email = "support@spctre.dev" }]
16
+ keywords = ["spctre", "policy", "governance", "agents"]
17
+ dependencies = [
18
+ "httpx >= 0.23.0, < 0.29.0",
19
+ "attrs >= 22.2.0",
20
+ "python-dateutil >= 2.8.0",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://spctre.dev"
25
+ Source = "https://github.com/getspctre/spctre"
26
+
27
+ [project.optional-dependencies]
28
+ test = [
29
+ "pytest>=9.0.3",
30
+ "pyrefly==1.1.0",
31
+ ]
32
+
33
+ # Single source of truth for the version, matching the adapter packages. The
34
+ # release workflow rewrites this file to stamp a .devN suffix for TestPyPI.
35
+ [tool.hatch.version]
36
+ path = "spctre/_version.py"
37
+
38
+ # One top-level package. spctre/_generated is generated by
39
+ # scripts/generate-python-sdk.sh but IS checked in, so building needs no code
40
+ # generator.
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["spctre"]
43
+
44
+ [tool.hatch.build.targets.sdist]
45
+ include = ["spctre", "README.md"]
46
+
47
+ [tool.pytest.ini_options]
48
+ testpaths = ["tests"]
49
+
50
+ [tool.pyrefly]
51
+ # The generated tree is checked by its own generator's conventions, not ours;
52
+ # type-checking it would report the generator's style, which we cannot fix.
53
+ project-includes = ["spctre", "tests"]
54
+ project-excludes = ["spctre/_generated/**"]
55
+ # pytest puts the rootdir's tests/ directory on sys.path, which is how the
56
+ # test modules import shared helpers from conftest. Tell the checker the same.
57
+ search-path = [".", "tests"]
@@ -0,0 +1,43 @@
1
+ """Supported Python client for the Spctre control plane.
2
+
3
+ from spctre import SpctreClient
4
+
5
+ client = SpctreClient(base_url="https://app-staging.spctre.dev", token=token)
6
+ decision = client.gateway.decide(request)
7
+
8
+ Request and response models live in `spctre.models`. The full generated
9
+ surface, including operations the facade does not wrap, is under
10
+ `spctre._generated` — regenerated wholesale from the OpenAPI spec and not
11
+ covered by this package's stability promise.
12
+ """
13
+
14
+ from . import models
15
+ from ._url import API_PREFIX, normalize_base_url
16
+ from ._version import __version__
17
+ from .client import UNSET, SpctreClient, Unset
18
+ from .errors import (
19
+ SpctreAuthError,
20
+ SpctreError,
21
+ SpctrePermissionError,
22
+ SpctreRequestError,
23
+ SpctreResponseError,
24
+ SpctreServerError,
25
+ SpctreTransportError,
26
+ )
27
+
28
+ __all__ = [
29
+ "API_PREFIX",
30
+ "SpctreAuthError",
31
+ "SpctreClient",
32
+ "SpctreError",
33
+ "SpctrePermissionError",
34
+ "SpctreRequestError",
35
+ "SpctreResponseError",
36
+ "SpctreServerError",
37
+ "SpctreTransportError",
38
+ "UNSET",
39
+ "Unset",
40
+ "__version__",
41
+ "models",
42
+ "normalize_base_url",
43
+ ]
@@ -0,0 +1,8 @@
1
+ """A client library for accessing Spctre API"""
2
+
3
+ from .client import AuthenticatedClient, Client
4
+
5
+ __all__ = (
6
+ "AuthenticatedClient",
7
+ "Client",
8
+ )
@@ -0,0 +1 @@
1
+ """Contains methods for accessing the API"""
@@ -0,0 +1 @@
1
+ """Contains endpoint functions for accessing the API"""
@@ -0,0 +1,174 @@
1
+ from http import HTTPStatus
2
+ from typing import Any
3
+ from urllib.parse import quote
4
+
5
+ import httpx
6
+
7
+ from ... import errors
8
+ from ...client import AuthenticatedClient, Client
9
+ from ...models.api_error import ApiError
10
+ from ...models.approval_response import ApprovalResponse
11
+ from ...types import Response
12
+
13
+
14
+ def _get_kwargs(
15
+ id: str,
16
+ ) -> dict[str, Any]:
17
+
18
+ _kwargs: dict[str, Any] = {
19
+ "method": "get",
20
+ "url": "/approvals/{id}".format(
21
+ id=quote(str(id), safe=""),
22
+ ),
23
+ }
24
+
25
+ return _kwargs
26
+
27
+
28
+ def _parse_response(
29
+ *, client: AuthenticatedClient | Client, response: httpx.Response
30
+ ) -> ApiError | ApprovalResponse | None:
31
+ if response.status_code == 200:
32
+ response_200 = ApprovalResponse.from_dict(response.json())
33
+
34
+ return response_200
35
+
36
+ if response.status_code == 401:
37
+ response_401 = ApiError.from_dict(response.json())
38
+
39
+ return response_401
40
+
41
+ if response.status_code == 404:
42
+ response_404 = ApiError.from_dict(response.json())
43
+
44
+ return response_404
45
+
46
+ if client.raise_on_unexpected_status:
47
+ raise errors.UnexpectedStatus(response.status_code, response.content)
48
+ else:
49
+ return None
50
+
51
+
52
+ def _build_response(
53
+ *, client: AuthenticatedClient | Client, response: httpx.Response
54
+ ) -> Response[ApiError | ApprovalResponse]:
55
+ return Response(
56
+ status_code=HTTPStatus(response.status_code),
57
+ content=response.content,
58
+ headers=response.headers,
59
+ parsed=_parse_response(client=client, response=response),
60
+ )
61
+
62
+
63
+ def sync_detailed(
64
+ id: str,
65
+ *,
66
+ client: AuthenticatedClient | Client,
67
+ ) -> Response[ApiError | ApprovalResponse]:
68
+ """Get an approval by ID
69
+
70
+ Returns the approval record for a specific revision approval ID.
71
+
72
+ Args:
73
+ id (str):
74
+
75
+ Raises:
76
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
77
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
78
+
79
+ Returns:
80
+ Response[ApiError | ApprovalResponse]
81
+ """
82
+
83
+ kwargs = _get_kwargs(
84
+ id=id,
85
+ )
86
+
87
+ response = client.get_httpx_client().request(
88
+ **kwargs,
89
+ )
90
+
91
+ return _build_response(client=client, response=response)
92
+
93
+
94
+ def sync(
95
+ id: str,
96
+ *,
97
+ client: AuthenticatedClient | Client,
98
+ ) -> ApiError | ApprovalResponse | None:
99
+ """Get an approval by ID
100
+
101
+ Returns the approval record for a specific revision approval ID.
102
+
103
+ Args:
104
+ id (str):
105
+
106
+ Raises:
107
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
108
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
109
+
110
+ Returns:
111
+ ApiError | ApprovalResponse
112
+ """
113
+
114
+ return sync_detailed(
115
+ id=id,
116
+ client=client,
117
+ ).parsed
118
+
119
+
120
+ async def asyncio_detailed(
121
+ id: str,
122
+ *,
123
+ client: AuthenticatedClient | Client,
124
+ ) -> Response[ApiError | ApprovalResponse]:
125
+ """Get an approval by ID
126
+
127
+ Returns the approval record for a specific revision approval ID.
128
+
129
+ Args:
130
+ id (str):
131
+
132
+ Raises:
133
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
134
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
135
+
136
+ Returns:
137
+ Response[ApiError | ApprovalResponse]
138
+ """
139
+
140
+ kwargs = _get_kwargs(
141
+ id=id,
142
+ )
143
+
144
+ response = await client.get_async_httpx_client().request(**kwargs)
145
+
146
+ return _build_response(client=client, response=response)
147
+
148
+
149
+ async def asyncio(
150
+ id: str,
151
+ *,
152
+ client: AuthenticatedClient | Client,
153
+ ) -> ApiError | ApprovalResponse | None:
154
+ """Get an approval by ID
155
+
156
+ Returns the approval record for a specific revision approval ID.
157
+
158
+ Args:
159
+ id (str):
160
+
161
+ Raises:
162
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
163
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
164
+
165
+ Returns:
166
+ ApiError | ApprovalResponse
167
+ """
168
+
169
+ return (
170
+ await asyncio_detailed(
171
+ id=id,
172
+ client=client,
173
+ )
174
+ ).parsed
@@ -0,0 +1 @@
1
+ """Contains endpoint functions for accessing the API"""