sova-oss 0.1.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.
Files changed (381) hide show
  1. sova/__init__.py +14 -0
  2. sova/__main__.py +7 -0
  3. sova/acceptance/__init__.py +35 -0
  4. sova/acceptance/io.py +98 -0
  5. sova/acceptance/lab.py +234 -0
  6. sova/acceptance/model.py +321 -0
  7. sova/adapters/__init__.py +45 -0
  8. sova/adapters/codex_exec.py +345 -0
  9. sova/adapters/security_catalog.py +685 -0
  10. sova/adapters/security_contracts.py +711 -0
  11. sova/adapters/security_parsers.py +635 -0
  12. sova/adapters/security_runner.py +683 -0
  13. sova/assessment.py +542 -0
  14. sova/audit/__init__.py +66 -0
  15. sova/audit/agentdojo.py +340 -0
  16. sova/audit/engine.py +695 -0
  17. sova/audit/report.py +168 -0
  18. sova/audit/specs/__init__.py +2 -0
  19. sova/audit/specs/agentdojo-v1.2.2.json +603 -0
  20. sova/benchmarks/__init__.py +14 -0
  21. sova/benchmarks/comparative.py +167 -0
  22. sova/capsule/__init__.py +47 -0
  23. sova/capsule/lifecycle.py +64 -0
  24. sova/capsule/migrate.py +405 -0
  25. sova/capsule/model.py +490 -0
  26. sova/capsule/primitives.py +132 -0
  27. sova/cli.py +6941 -0
  28. sova/command_audit.py +111 -0
  29. sova/community/__init__.py +94 -0
  30. sova/community/agent_arena.py +1094 -0
  31. sova/community/arena.py +256 -0
  32. sova/community/browser_swarm.py +1218 -0
  33. sova/community/browser_swarm_config.py +270 -0
  34. sova/community/chamber.py +1361 -0
  35. sova/community/chamber_config.py +324 -0
  36. sova/community/config.py +569 -0
  37. sova/community/ctf.py +103 -0
  38. sova/community/executor_capsule_reproduction.py +280 -0
  39. sova/community/executor_chamber.py +2782 -0
  40. sova/community/executor_chamber_config.py +731 -0
  41. sova/community/executor_engine.py +886 -0
  42. sova/community/executor_engine_full.py +577 -0
  43. sova/community/executor_engine_runtime_config.py +446 -0
  44. sova/community/executor_surfaces.py +1001 -0
  45. sova/community/leaderboard.py +221 -0
  46. sova/community/live_executor_engine.py +649 -0
  47. sova/community/media.py +170 -0
  48. sova/community/probe.py +244 -0
  49. sova/community/software_executor_engine.py +549 -0
  50. sova/community/swarm/__init__.py +41 -0
  51. sova/community/swarm/blackboard.py +123 -0
  52. sova/community/swarm/budget.py +191 -0
  53. sova/community/swarm/coordinator.py +535 -0
  54. sova/community/swarm/coverage.py +173 -0
  55. sova/community/swarm/message.py +116 -0
  56. sova/community/swarm/runtime.py +178 -0
  57. sova/community/swarm/software.py +215 -0
  58. sova/community/swarm/stress.py +242 -0
  59. sova/community/swarm/worker.py +267 -0
  60. sova/composition/__init__.py +55 -0
  61. sova/composition/fixtures.py +90 -0
  62. sova/composition/graph.py +149 -0
  63. sova/composition/model.py +232 -0
  64. sova/composition/portable.py +41 -0
  65. sova/composition/search.py +349 -0
  66. sova/conformance.py +209 -0
  67. sova/contracts/__init__.py +94 -0
  68. sova/contracts/coverage.py +182 -0
  69. sova/contracts/data/__init__.py +2 -0
  70. sova/contracts/data/attack-taxonomy-0.1.0.toml +366 -0
  71. sova/contracts/errors.py +28 -0
  72. sova/contracts/identifiers.py +160 -0
  73. sova/contracts/lifecycle.py +182 -0
  74. sova/contracts/taxonomy.py +233 -0
  75. sova/contracts/versions.py +209 -0
  76. sova/contracts/vocabulary.py +47 -0
  77. sova/desktop/__init__.py +25 -0
  78. sova/desktop/appium.py +393 -0
  79. sova/desktop/atspi.py +256 -0
  80. sova/desktop/conformance.py +123 -0
  81. sova/detonation/__init__.py +75 -0
  82. sova/detonation/backends.py +87 -0
  83. sova/detonation/coverage.py +240 -0
  84. sova/detonation/demo.py +517 -0
  85. sova/detonation/sensors.py +221 -0
  86. sova/detonation/targets.py +148 -0
  87. sova/detonation/world.py +445 -0
  88. sova/evidence/__init__.py +45 -0
  89. sova/evidence/adjudication.py +120 -0
  90. sova/evidence/bundle.py +253 -0
  91. sova/evidence/disclosure.py +173 -0
  92. sova/evidence/model.py +212 -0
  93. sova/evidence/report.py +70 -0
  94. sova/executors/__init__.py +75 -0
  95. sova/executors/contract.py +233 -0
  96. sova/executors/docker_desktop.py +652 -0
  97. sova/executors/gvisor.py +462 -0
  98. sova/executors/local.py +928 -0
  99. sova/executors/runner.py +555 -0
  100. sova/executors/scripted.py +143 -0
  101. sova/executors/workspace.py +653 -0
  102. sova/experiments/__init__.py +20 -0
  103. sova/experiments/matrix.py +283 -0
  104. sova/extensions/__init__.py +39 -0
  105. sova/extensions/model.py +171 -0
  106. sova/extensions/runner.py +218 -0
  107. sova/extensions/workflow.py +539 -0
  108. sova/forensics/__init__.py +67 -0
  109. sova/forensics/attribution.py +170 -0
  110. sova/forensics/benchmark.py +158 -0
  111. sova/forensics/blinded.py +825 -0
  112. sova/forensics/browser_counterfactual.py +425 -0
  113. sova/forensics/fixtures.py +101 -0
  114. sova/forensics/model.py +193 -0
  115. sova/forensics/reconstruct.py +214 -0
  116. sova/formats/__init__.py +20 -0
  117. sova/formats/canonical.py +267 -0
  118. sova/formats/errors.py +35 -0
  119. sova/formats/package.py +416 -0
  120. sova/formats/schema.py +160 -0
  121. sova/front_door.py +77 -0
  122. sova/intake/__init__.py +49 -0
  123. sova/intake/contracts.py +657 -0
  124. sova/intake/frontends.py +3182 -0
  125. sova/intake/materials.py +373 -0
  126. sova/intake/model.py +484 -0
  127. sova/intake/pipeline.py +455 -0
  128. sova/interoperability/__init__.py +14 -0
  129. sova/interoperability/agentdojo.py +665 -0
  130. sova/interoperability/inspect_ai.py +129 -0
  131. sova/interoperability/inspect_log.py +510 -0
  132. sova/interoperability/record.py +145 -0
  133. sova/interoperability/trace_attestation.py +255 -0
  134. sova/live/__init__.py +158 -0
  135. sova/live/action_lab.py +934 -0
  136. sova/live/adaptive_campaign.py +493 -0
  137. sova/live/adversarial_missions.py +307 -0
  138. sova/live/agent_campaign.py +610 -0
  139. sova/live/browser.py +865 -0
  140. sova/live/campaign.py +1047 -0
  141. sova/live/control.py +331 -0
  142. sova/live/fixture_web.py +132 -0
  143. sova/live/held_out_web.py +365 -0
  144. sova/live/persistent_session.py +563 -0
  145. sova/live/recording.py +280 -0
  146. sova/live/semantic_browser_driver.py +1408 -0
  147. sova/live/semantic_workflow.py +1420 -0
  148. sova/live/software.py +881 -0
  149. sova/live/startup.py +37 -0
  150. sova/local_mcp/__init__.py +39 -0
  151. sova/local_mcp/approval.py +220 -0
  152. sova/local_mcp/model.py +125 -0
  153. sova/local_mcp/server.py +135 -0
  154. sova/local_mcp/tools.py +514 -0
  155. sova/mapping/__init__.py +60 -0
  156. sova/mapping/analysis.py +257 -0
  157. sova/mapping/discovery.py +864 -0
  158. sova/mapping/drift.py +113 -0
  159. sova/mapping/model.py +342 -0
  160. sova/mapping/report.py +122 -0
  161. sova/mcp/__init__.py +73 -0
  162. sova/mcp/adapter.py +1606 -0
  163. sova/mcp/broker.py +136 -0
  164. sova/mcp/cua_driver.py +163 -0
  165. sova/mcp/profile_state.py +213 -0
  166. sova/mcp/protocol.py +410 -0
  167. sova/mcp/receipts.py +146 -0
  168. sova/mcp/specs.py +476 -0
  169. sova/methodology/__init__.py +58 -0
  170. sova/methodology/compiler.py +870 -0
  171. sova/methodology/contracts.py +830 -0
  172. sova/methodology/contribution.py +190 -0
  173. sova/methodology/data/__init__.py +2 -0
  174. sova/methodology/data/playbook-seeds-0.1.0.json +95 -0
  175. sova/methodology/library.py +814 -0
  176. sova/models/__init__.py +10 -0
  177. sova/models/scripted.py +128 -0
  178. sova/monitoring/__init__.py +39 -0
  179. sova/monitoring/alerts.py +175 -0
  180. sova/monitoring/diff.py +113 -0
  181. sova/monitoring/integrity.py +121 -0
  182. sova/monitoring/model.py +93 -0
  183. sova/monitoring/recorder.py +162 -0
  184. sova/monitoring/sentinel.py +175 -0
  185. sova/monitoring/service.py +565 -0
  186. sova/onboarding.py +348 -0
  187. sova/oracle_lab/__init__.py +78 -0
  188. sova/oracle_lab/calibration.py +285 -0
  189. sova/oracle_lab/comparison.py +103 -0
  190. sova/oracle_lab/contracts.py +641 -0
  191. sova/oracle_lab/coverage.py +118 -0
  192. sova/oracle_lab/evidence.py +44 -0
  193. sova/oracle_lab/io.py +136 -0
  194. sova/oracle_lab/proposal.py +76 -0
  195. sova/oracle_lab/reproduction.py +118 -0
  196. sova/oracle_lab/study.py +160 -0
  197. sova/oracles.py +528 -0
  198. sova/providers/__init__.py +56 -0
  199. sova/providers/core.py +633 -0
  200. sova/providers/runtime.py +372 -0
  201. sova/py.typed +1 -0
  202. sova/registry/__init__.py +66 -0
  203. sova/registry/adapters.py +128 -0
  204. sova/registry/auto_contribute.py +112 -0
  205. sova/registry/backup.py +321 -0
  206. sova/registry/client.py +184 -0
  207. sova/registry/contribution.py +172 -0
  208. sova/registry/index.py +298 -0
  209. sova/registry/model.py +189 -0
  210. sova/registry/pr_contribution.py +120 -0
  211. sova/registry/service.py +1390 -0
  212. sova/registry/sync.py +101 -0
  213. sova/rehearsal/__init__.py +61 -0
  214. sova/rehearsal/agent.py +83 -0
  215. sova/rehearsal/backend.py +73 -0
  216. sova/rehearsal/environment.py +176 -0
  217. sova/rehearsal/model.py +299 -0
  218. sova/rehearsal/provider.py +863 -0
  219. sova/rehearsal/runner.py +439 -0
  220. sova/release.py +456 -0
  221. sova/replay/__init__.py +55 -0
  222. sova/replay/capsule.py +363 -0
  223. sova/replay/controlled.py +120 -0
  224. sova/replay/model.py +240 -0
  225. sova/replay/render.py +695 -0
  226. sova/replay/semantic.py +210 -0
  227. sova/replay/service.py +369 -0
  228. sova/replay/verification.py +288 -0
  229. sova/reproduction.py +304 -0
  230. sova/rerun/__init__.py +50 -0
  231. sova/rerun/agentdojo.py +673 -0
  232. sova/rerun/calibrate.py +475 -0
  233. sova/rerun/command.py +538 -0
  234. sova/rerun/decision.py +648 -0
  235. sova/rerun/engine.py +1241 -0
  236. sova/rerun/findings.py +346 -0
  237. sova/rerun/judges.py +86 -0
  238. sova/rerun/matrix.py +340 -0
  239. sova/rerun/providers.py +524 -0
  240. sova/rerun/records.py +293 -0
  241. sova/rerun/tracing.py +258 -0
  242. sova/runtime/__init__.py +105 -0
  243. sova/runtime/action_codecs.py +1179 -0
  244. sova/runtime/bound_environment.py +1128 -0
  245. sova/runtime/browser_surface.py +759 -0
  246. sova/runtime/computer_surface.py +458 -0
  247. sova/runtime/environment_builder.py +271 -0
  248. sova/runtime/evidence.py +426 -0
  249. sova/runtime/experience.py +111 -0
  250. sova/runtime/managed_surfaces.py +588 -0
  251. sova/runtime/melra_computer.py +386 -0
  252. sova/runtime/native_windows_computer.py +599 -0
  253. sova/runtime/oci_agent.py +631 -0
  254. sova/runtime/orchestration.py +613 -0
  255. sova/runtime/profiles.py +65 -0
  256. sova/runtime/reliability.py +260 -0
  257. sova/runtime/sessions.py +555 -0
  258. sova/runtime/software_target.py +421 -0
  259. sova/runtime/target_environment.py +413 -0
  260. sova/runtime/unified_execution.py +1005 -0
  261. sova/runtime/window_recording.py +770 -0
  262. sova/safety/__init__.py +91 -0
  263. sova/safety/authorization.py +1094 -0
  264. sova/safety/containment.py +326 -0
  265. sova/safety/disclosure.py +81 -0
  266. sova/safety/privacy.py +142 -0
  267. sova/safety/profiles.py +162 -0
  268. sova/schemas/README.md +71 -0
  269. sova/schemas/__init__.py +2 -0
  270. sova/schemas/adapter-descriptor-0.1.0.schema.json +95 -0
  271. sova/schemas/adapter-run-report-0.1.0.schema.json +51 -0
  272. sova/schemas/assessment-coverage-0.1.0.schema.json +15 -0
  273. sova/schemas/blinded-causal-answer-key-0.1.0.schema.json +51 -0
  274. sova/schemas/blinded-causal-predictions-0.1.0.schema.json +35 -0
  275. sova/schemas/blinded-causal-score-0.1.0.schema.json +140 -0
  276. sova/schemas/blinded-causal-study-0.1.0.schema.json +62 -0
  277. sova/schemas/blinded-evaluation-protocol-0.1.0.schema.json +74 -0
  278. sova/schemas/blinded-evaluation-report-0.1.0.schema.json +189 -0
  279. sova/schemas/blinded-oracle-answer-key-0.1.0.schema.json +13 -0
  280. sova/schemas/blinded-oracle-predictions-0.1.0.schema.json +13 -0
  281. sova/schemas/blinded-oracle-study-0.1.0.schema.json +18 -0
  282. sova/schemas/capsule-manifest-0.1.0.schema.json +225 -0
  283. sova/schemas/composition-report-0.1.0.schema.json +24 -0
  284. sova/schemas/decisive-evidence-set-0.1.0.schema.json +15 -0
  285. sova/schemas/evaluation-observation-ledger-0.1.0.schema.json +43 -0
  286. sova/schemas/evaluation-work-order-set-0.1.0.schema.json +25 -0
  287. sova/schemas/event-0.1.0.schema.json +128 -0
  288. sova/schemas/evidence-0.1.0.schema.json +39 -0
  289. sova/schemas/external-benchmark-case-0.1.0.schema.json +23 -0
  290. sova/schemas/firecracker-execution-receipt-0.1.0.schema.json +98 -0
  291. sova/schemas/firecracker-launch-plan-0.1.0.schema.json +19 -0
  292. sova/schemas/firecracker-network-plan-0.1.0.schema.json +42 -0
  293. sova/schemas/forensic-reconstruction-0.1.0.schema.json +52 -0
  294. sova/schemas/fresh-reproduction-0.1.0.schema.json +20 -0
  295. sova/schemas/intake-report-0.1.0.schema.json +174 -0
  296. sova/schemas/launch-dossier-0.1.0.schema.json +154 -0
  297. sova/schemas/launch-evidence-bundle-0.1.0.schema.json +25 -0
  298. sova/schemas/launch-gate-receipt-0.1.0.schema.json +24 -0
  299. sova/schemas/launch-trust-policy-0.1.0.schema.json +31 -0
  300. sova/schemas/map-report-0.1.0.schema.json +226 -0
  301. sova/schemas/methodology-observations-0.1.0.schema.json +9 -0
  302. sova/schemas/methodology-plan-0.1.0.schema.json +17 -0
  303. sova/schemas/methodology-policy-0.1.0.schema.json +12 -0
  304. sova/schemas/normalized-observation-0.1.0.schema.json +42 -0
  305. sova/schemas/oracle-calibration-0.1.0.schema.json +39 -0
  306. sova/schemas/oracle-comparison-0.1.0.schema.json +23 -0
  307. sova/schemas/oracle-proposal-0.1.0.schema.json +41 -0
  308. sova/schemas/playbook-0.1.0.schema.json +107 -0
  309. sova/schemas/playbook-library-0.1.0.schema.json +14 -0
  310. sova/schemas/playbook-submission-0.1.0.schema.json +5 -0
  311. sova/schemas/public-claims-snapshot-0.1.0.schema.json +43 -0
  312. sova/schemas/registry-beta-readiness-0.1.0.schema.json +39 -0
  313. sova/schemas/registry-operational-receipt-0.1.0.schema.json +21 -0
  314. sova/schemas/release-candidate-0.1.0.schema.json +22 -0
  315. sova/schemas/release-gate-ledger-0.1.0.schema.json +50 -0
  316. sova/schemas/release-review-receipt-0.1.0.schema.json +22 -0
  317. sova/schemas/scenario-0.1.0.schema.json +105 -0
  318. sova/schemas/target-profile-0.1.0.schema.json +94 -0
  319. sova/schemas/trace-manifest-0.1.0.schema.json +219 -0
  320. sova/schemas/worker-attestation-0.1.0.schema.json +27 -0
  321. sova/schemas/worker-cleanup-receipt-0.1.0.schema.json +13 -0
  322. sova/schemas/worker-evidence-report-0.1.0.schema.json +17 -0
  323. sova/schemas/worker-exact-host-acceptance-receipt-0.1.0.schema.json +31 -0
  324. sova/schemas/worker-host-preflight-receipt-0.1.0.schema.json +26 -0
  325. sova/schemas/worker-job-manifest-0.1.0.schema.json +110 -0
  326. sova/schemas/worker-network-mediator-policy-0.1.0.schema.json +75 -0
  327. sova/schemas/worker-network-plane-receipt-0.1.0.schema.json +28 -0
  328. sova/schemas/worker-network-receipt-0.1.0.schema.json +16 -0
  329. sova/schemas/worker-protocol-message-0.1.0.schema.json +25 -0
  330. sova/schemas/worker-secret-receipt-0.1.0.schema.json +14 -0
  331. sova/search/__init__.py +56 -0
  332. sova/search/demo.py +107 -0
  333. sova/search/engine.py +484 -0
  334. sova/search/experience.py +51 -0
  335. sova/search/model.py +239 -0
  336. sova/search/phantom.py +179 -0
  337. sova/search/portable.py +35 -0
  338. sova/targets/__init__.py +16 -0
  339. sova/targets/contract.py +163 -0
  340. sova/trace/__init__.py +33 -0
  341. sova/trace/integrity.py +329 -0
  342. sova/trace/kinds.py +105 -0
  343. sova/trace/otel.py +487 -0
  344. sova/trace/reader.py +268 -0
  345. sova/trace/redaction.py +442 -0
  346. sova/trace/writer.py +696 -0
  347. sova/validation/__init__.py +99 -0
  348. sova/validation/adapters.py +243 -0
  349. sova/validation/contracts.py +295 -0
  350. sova/validation/gates.py +445 -0
  351. sova/validation/launch.py +1295 -0
  352. sova/validation/ledger.py +348 -0
  353. sova/validation/work_orders.py +88 -0
  354. sova/worker/__init__.py +154 -0
  355. sova/worker/alternative_backends.py +102 -0
  356. sova/worker/attestation.py +152 -0
  357. sova/worker/brokers.py +348 -0
  358. sova/worker/cas.py +97 -0
  359. sova/worker/contracts.py +476 -0
  360. sova/worker/deployment.py +247 -0
  361. sova/worker/evidence.py +277 -0
  362. sova/worker/firecracker.py +409 -0
  363. sova/worker/host_acceptance.py +213 -0
  364. sova/worker/host_preflight.py +407 -0
  365. sova/worker/identity.py +188 -0
  366. sova/worker/io.py +151 -0
  367. sova/worker/lifecycle.py +822 -0
  368. sova/worker/malicious.py +107 -0
  369. sova/worker/network_plane.py +1076 -0
  370. sova/worker/protocol.py +314 -0
  371. sova/worker/service.py +249 -0
  372. sova/workflows/__init__.py +17 -0
  373. sova/workflows/case.py +560 -0
  374. sova/workflows/check.py +287 -0
  375. sova/workflows/demo.py +248 -0
  376. sova_oss-0.1.0.dist-info/METADATA +1266 -0
  377. sova_oss-0.1.0.dist-info/RECORD +381 -0
  378. sova_oss-0.1.0.dist-info/WHEEL +4 -0
  379. sova_oss-0.1.0.dist-info/entry_points.txt +2 -0
  380. sova_oss-0.1.0.dist-info/licenses/LICENSE +201 -0
  381. sova_oss-0.1.0.dist-info/licenses/NOTICE +20 -0
sova/__init__.py ADDED
@@ -0,0 +1,14 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """SOVA OSS public Python package."""
3
+
4
+ from importlib.metadata import PackageNotFoundError, version
5
+
6
+ _DISTRIBUTION_NAME = "sova-oss"
7
+ _SOURCE_FALLBACK_VERSION = "0.1.0"
8
+
9
+ try:
10
+ __version__ = version(_DISTRIBUTION_NAME)
11
+ except PackageNotFoundError:
12
+ __version__ = _SOURCE_FALLBACK_VERSION
13
+
14
+ __all__ = ["__version__"]
sova/__main__.py ADDED
@@ -0,0 +1,7 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Run SOVA with ``python -m sova``."""
3
+
4
+ from sova.cli import main
5
+
6
+ if __name__ == "__main__":
7
+ raise SystemExit(main())
@@ -0,0 +1,35 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Executable acceptance and stable-release evidence gates."""
3
+
4
+ from sova.acceptance.io import load_receipts, receipt_from_mapping
5
+ from sova.acceptance.lab import (
6
+ AcceptanceLabArtifacts,
7
+ acceptance_receipt_template,
8
+ run_offline_acceptance_lab,
9
+ )
10
+ from sova.acceptance.model import (
11
+ AcceptanceGate,
12
+ AcceptanceReceipt,
13
+ GateClass,
14
+ GateResult,
15
+ ReleaseReadinessReport,
16
+ default_release_gates,
17
+ evaluate_gate,
18
+ evaluate_release_readiness,
19
+ )
20
+
21
+ __all__ = [
22
+ "AcceptanceGate",
23
+ "AcceptanceLabArtifacts",
24
+ "AcceptanceReceipt",
25
+ "GateClass",
26
+ "GateResult",
27
+ "ReleaseReadinessReport",
28
+ "acceptance_receipt_template",
29
+ "default_release_gates",
30
+ "evaluate_gate",
31
+ "evaluate_release_readiness",
32
+ "load_receipts",
33
+ "receipt_from_mapping",
34
+ "run_offline_acceptance_lab",
35
+ ]
sova/acceptance/io.py ADDED
@@ -0,0 +1,98 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Strict acceptance-receipt I/O."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from sova.acceptance.model import AcceptanceReceipt
9
+ from sova.formats import strict_json_loads
10
+ from sova.formats.errors import FormatError
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Mapping
14
+ from pathlib import Path
15
+
16
+ _FIELDS = {
17
+ "artifactType",
18
+ "schemaVersion",
19
+ "gateId",
20
+ "evidenceType",
21
+ "runId",
22
+ "result",
23
+ "producer",
24
+ "organization",
25
+ "environmentId",
26
+ "labels",
27
+ "artifactDigests",
28
+ "independentOfSovaTeam",
29
+ "observedAt",
30
+ "limitations",
31
+ }
32
+
33
+
34
+ def receipt_from_mapping(value: Mapping[str, Any]) -> AcceptanceReceipt:
35
+ if set(value) != _FIELDS:
36
+ raise FormatError("SOVA-ACCEPTANCE-RECEIPT", "receipt fields must be exact")
37
+ if (
38
+ value.get("artifactType") != "sova.acceptance-receipt"
39
+ or value.get("schemaVersion") != "0.1.0"
40
+ ):
41
+ raise FormatError("SOVA-ACCEPTANCE-RECEIPT", "receipt type is unsupported")
42
+ labels = value.get("labels")
43
+ digests = value.get("artifactDigests")
44
+ limitations = value.get("limitations")
45
+ if not isinstance(labels, dict) or not all(
46
+ isinstance(key, str) and isinstance(item, str) for key, item in labels.items()
47
+ ):
48
+ raise FormatError("SOVA-ACCEPTANCE-RECEIPT", "receipt labels are malformed")
49
+ if not isinstance(digests, list) or not all(isinstance(item, str) for item in digests):
50
+ raise FormatError("SOVA-ACCEPTANCE-RECEIPT", "receipt digests are malformed")
51
+ if not isinstance(limitations, list) or not all(isinstance(item, str) for item in limitations):
52
+ raise FormatError("SOVA-ACCEPTANCE-RECEIPT", "receipt limitations are malformed")
53
+ strings = (
54
+ "gateId",
55
+ "evidenceType",
56
+ "runId",
57
+ "result",
58
+ "producer",
59
+ "organization",
60
+ "environmentId",
61
+ "observedAt",
62
+ )
63
+ if not all(isinstance(value.get(name), str) for name in strings) or not isinstance(
64
+ value.get("independentOfSovaTeam"), bool
65
+ ):
66
+ raise FormatError("SOVA-ACCEPTANCE-RECEIPT", "receipt scalar fields are malformed")
67
+ return AcceptanceReceipt(
68
+ str(value["gateId"]),
69
+ str(value["evidenceType"]),
70
+ str(value["runId"]),
71
+ str(value["result"]),
72
+ str(value["producer"]),
73
+ str(value["organization"]),
74
+ str(value["environmentId"]),
75
+ tuple(sorted((str(key), str(item)) for key, item in labels.items())),
76
+ tuple(str(item) for item in digests),
77
+ bool(value["independentOfSovaTeam"]),
78
+ str(value["observedAt"]),
79
+ tuple(str(item) for item in limitations),
80
+ )
81
+
82
+
83
+ def load_receipts(directory: Path) -> tuple[AcceptanceReceipt, ...]:
84
+ root = directory.resolve()
85
+ if not root.is_dir():
86
+ raise FormatError("SOVA-ACCEPTANCE-DIRECTORY", "receipt directory does not exist")
87
+ receipts: list[AcceptanceReceipt] = []
88
+ for path in sorted(root.glob("*.json")):
89
+ if path.is_symlink() or not path.is_file() or path.stat().st_size > 1024 * 1024:
90
+ raise FormatError("SOVA-ACCEPTANCE-FILE", "receipt must be a bounded regular file")
91
+ value = strict_json_loads(path.read_bytes())
92
+ if not isinstance(value, dict):
93
+ raise FormatError("SOVA-ACCEPTANCE-RECEIPT", "receipt root must be an object")
94
+ receipts.append(receipt_from_mapping(value))
95
+ return tuple(receipts)
96
+
97
+
98
+ __all__ = ["load_receipts", "receipt_from_mapping"]
sova/acceptance/lab.py ADDED
@@ -0,0 +1,234 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Safe offline acceptance lab and stable-readiness evaluation."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import platform
7
+ import secrets
8
+ import shutil
9
+ from dataclasses import dataclass
10
+ from datetime import UTC, datetime
11
+ from typing import TYPE_CHECKING, Any
12
+
13
+ from sova.acceptance.model import (
14
+ AcceptanceReceipt,
15
+ default_release_gates,
16
+ evaluate_release_readiness,
17
+ )
18
+ from sova.detonation import (
19
+ CaptureMode,
20
+ CoverageRequirement,
21
+ OrderingGuarantee,
22
+ SensorCoverageLedger,
23
+ SensorCoveragePolicy,
24
+ SensorDeclaration,
25
+ SensorKind,
26
+ SensorSurface,
27
+ run_sleeper_demo,
28
+ )
29
+ from sova.formats import canonical_json_bytes, sha256_digest
30
+ from sova.formats.errors import FormatError
31
+ from sova.replay import verify_artifact
32
+
33
+ if TYPE_CHECKING:
34
+ from pathlib import Path
35
+
36
+
37
+ @dataclass(frozen=True, slots=True)
38
+ class AcceptanceLabArtifacts:
39
+ root: Path
40
+ report: Path
41
+ sensor_coverage: Path
42
+ readiness: Path
43
+ core_capsule: Path
44
+ core_trace: Path
45
+ status: str
46
+
47
+ def to_mapping(self) -> dict[str, Any]:
48
+ return {
49
+ "status": self.status,
50
+ "root": str(self.root),
51
+ "report": str(self.report),
52
+ "sensorCoverage": str(self.sensor_coverage),
53
+ "readiness": str(self.readiness),
54
+ "coreCapsule": str(self.core_capsule),
55
+ "coreTrace": str(self.core_trace),
56
+ }
57
+
58
+
59
+ def _synthetic_coverage() -> dict[str, Any]:
60
+ declarations = (
61
+ SensorDeclaration(
62
+ "sova-authorization",
63
+ SensorKind.AUTHORIZATION,
64
+ SensorSurface.SOVA,
65
+ "healthy",
66
+ "sova.authorization-kernel/0.1",
67
+ CaptureMode.DIRECT,
68
+ "sova-trace-sequence",
69
+ OrderingGuarantee.LOCAL_TOTAL,
70
+ emitted_events=1,
71
+ ),
72
+ SensorDeclaration(
73
+ "sova-containment",
74
+ SensorKind.SAFETY,
75
+ SensorSurface.SOVA,
76
+ "healthy",
77
+ "sova.synthetic-world/0.1",
78
+ CaptureMode.DIRECT,
79
+ "sova-trace-sequence",
80
+ OrderingGuarantee.LOCAL_TOTAL,
81
+ emitted_events=1,
82
+ ),
83
+ SensorDeclaration(
84
+ "synthetic-filesystem",
85
+ SensorKind.FILESYSTEM,
86
+ SensorSurface.HOST,
87
+ "healthy",
88
+ "sova.synthetic-filesystem/0.1",
89
+ CaptureMode.DIRECT,
90
+ "sova-world-sequence",
91
+ OrderingGuarantee.PARTIAL,
92
+ emitted_events=1,
93
+ blind_spots=("simulated filesystem only; no native host activity",),
94
+ ),
95
+ SensorDeclaration(
96
+ "synthetic-network",
97
+ SensorKind.NETWORK,
98
+ SensorSurface.EXTERNAL,
99
+ "healthy",
100
+ "sova.sink-only-network/0.1",
101
+ CaptureMode.DIRECT,
102
+ "sova-world-sequence",
103
+ OrderingGuarantee.PARTIAL,
104
+ emitted_events=1,
105
+ blind_spots=("sink-only simulation; no packet or third-party service observation",),
106
+ ),
107
+ )
108
+ policy = SensorCoveragePolicy(
109
+ "sova:coverage:synthetic-sleeper/0.1",
110
+ "declared synthetic authorization, safety, filesystem, and sink-only network effects",
111
+ tuple(
112
+ CoverageRequirement(declaration.surface, declaration.kind)
113
+ for declaration in declarations
114
+ ),
115
+ )
116
+ return SensorCoverageLedger(declarations).evaluate(policy).to_mapping()
117
+
118
+
119
+ def run_offline_acceptance_lab(
120
+ destination: Path,
121
+ *,
122
+ receipts: tuple[AcceptanceReceipt, ...] = (),
123
+ ) -> AcceptanceLabArtifacts:
124
+ """Run credential-free core evidence tests and evaluate external stable gates."""
125
+ root = destination.resolve()
126
+ if root.exists():
127
+ raise FormatError("SOVA-ACCEPTANCE-EXISTS", "acceptance destination must not exist")
128
+ temporary = root.with_name(f".{root.name}.partial-{secrets.token_hex(8)}")
129
+ temporary.mkdir(parents=True)
130
+ try:
131
+ core = temporary / "core-workflow"
132
+ demo = run_sleeper_demo(core)
133
+ capsule_verification = verify_artifact(demo.capsule).to_mapping()
134
+ trace_verification = verify_artifact(demo.trace).to_mapping()
135
+ core_pass = bool(
136
+ capsule_verification["state"] in {"verified", "partial"}
137
+ and trace_verification["state"] == "verified"
138
+ and demo.oracle_status == "pass"
139
+ and demo.evidence_closure == "sufficient"
140
+ and demo.cleanup_verified
141
+ )
142
+ coverage = _synthetic_coverage()
143
+ coverage_path = temporary / "sensor-coverage.json"
144
+ coverage_path.write_bytes(canonical_json_bytes(coverage) + b"\n")
145
+ readiness = evaluate_release_readiness(receipts).to_mapping()
146
+ readiness_path = temporary / "stable-readiness.json"
147
+ readiness_path.write_bytes(canonical_json_bytes(readiness) + b"\n")
148
+ status = "pass" if core_pass and coverage["accepted"] else "fail"
149
+ report = {
150
+ "artifactType": "sova.acceptance-lab-report",
151
+ "schemaVersion": "0.1.0",
152
+ "status": status,
153
+ "coreAcceptancePassed": core_pass,
154
+ "stable1Ready": readiness["readyForStable1"],
155
+ "environment": {
156
+ "platform": platform.system().casefold(),
157
+ "machine": platform.machine().casefold(),
158
+ "python": platform.python_version(),
159
+ },
160
+ "artifacts": {
161
+ "capsuleDigest": sha256_digest(demo.capsule.read_bytes()),
162
+ "traceDigest": sha256_digest(demo.trace.read_bytes()),
163
+ "sensorCoverageDigest": sha256_digest(coverage_path.read_bytes()),
164
+ "readinessDigest": sha256_digest(readiness_path.read_bytes()),
165
+ },
166
+ "verification": {
167
+ "capsule": capsule_verification,
168
+ "trace": trace_verification,
169
+ "oracleStatus": demo.oracle_status,
170
+ "evidenceClosure": demo.evidence_closure,
171
+ "cleanupVerified": demo.cleanup_verified,
172
+ },
173
+ "scope": {
174
+ "networkUsed": False,
175
+ "credentialsUsed": False,
176
+ "nativeTargetCodeExecuted": False,
177
+ "externalEvidenceGenerated": False,
178
+ },
179
+ "limitations": [
180
+ "Core acceptance uses SOVA's deterministic synthetic fixture.",
181
+ "The lab does not convert self-generated evidence into external validation.",
182
+ "Stable 1.0 remains blocked until every separate stable gate passes.",
183
+ ],
184
+ }
185
+ report["digest"] = sha256_digest(canonical_json_bytes(report))
186
+ report_path = temporary / "report.json"
187
+ report_path.write_bytes(canonical_json_bytes(report) + b"\n")
188
+ temporary.rename(root)
189
+ return AcceptanceLabArtifacts(
190
+ root,
191
+ root / report_path.name,
192
+ root / coverage_path.name,
193
+ root / readiness_path.name,
194
+ root / "core-workflow" / demo.capsule.name,
195
+ root / "core-workflow" / demo.trace.name,
196
+ status,
197
+ )
198
+ except BaseException:
199
+ if temporary.exists():
200
+ shutil.rmtree(temporary)
201
+ raise
202
+
203
+
204
+ def acceptance_receipt_template(gate_id: str) -> dict[str, Any]:
205
+ gate = next((item for item in default_release_gates() if item.id == gate_id), None)
206
+ if gate is None:
207
+ raise FormatError("SOVA-ACCEPTANCE-GATE", "unknown stable-release gate")
208
+ labels = {name: values[0] for name, values in gate.required_labels if values}
209
+ return {
210
+ "artifactType": "sova.acceptance-receipt",
211
+ "schemaVersion": "0.1.0",
212
+ "gateId": gate.id,
213
+ "evidenceType": gate.evidence_type,
214
+ "runId": "replace-with-stable-run-id",
215
+ "result": "inconclusive",
216
+ "producer": "replace-with-runner-or-reviewer",
217
+ "organization": "replace-with-legal-organization",
218
+ "environmentId": "replace-with-environment-fingerprint",
219
+ "labels": labels,
220
+ "artifactDigests": ["sha256:" + "0" * 64],
221
+ "independentOfSovaTeam": False,
222
+ "observedAt": datetime.now(UTC).isoformat().replace("+00:00", "Z"),
223
+ "limitations": [
224
+ "Template only; replace every placeholder with verified evidence.",
225
+ "A receipt signature does not prove reviewer identity or independence.",
226
+ ],
227
+ }
228
+
229
+
230
+ __all__ = [
231
+ "AcceptanceLabArtifacts",
232
+ "acceptance_receipt_template",
233
+ "run_offline_acceptance_lab",
234
+ ]