surgeval 0.3.0a0__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 (261) hide show
  1. surgeval-0.3.0a0/.dist-smoke/.gitignore +1 -0
  2. surgeval-0.3.0a0/.dist-smoke/surgeval-0.3.0a0-py3-none-any.whl +0 -0
  3. surgeval-0.3.0a0/.dist-smoke/surgeval-0.3.0a0.tar.gz +0 -0
  4. surgeval-0.3.0a0/.dockerignore +16 -0
  5. surgeval-0.3.0a0/.github/workflows/ci.yml +68 -0
  6. surgeval-0.3.0a0/.github/workflows/droid-review.yml +31 -0
  7. surgeval-0.3.0a0/.github/workflows/droid.yml +38 -0
  8. surgeval-0.3.0a0/.github/workflows/install-smoke.yml +238 -0
  9. surgeval-0.3.0a0/.github/workflows/publish.yml +198 -0
  10. surgeval-0.3.0a0/.github/workflows/sbom.yml +42 -0
  11. surgeval-0.3.0a0/.gitignore +46 -0
  12. surgeval-0.3.0a0/CODE_OF_CONDUCT.md +56 -0
  13. surgeval-0.3.0a0/CONTRIBUTING.md +85 -0
  14. surgeval-0.3.0a0/LICENSE +202 -0
  15. surgeval-0.3.0a0/NOTICE +5 -0
  16. surgeval-0.3.0a0/PKG-INFO +599 -0
  17. surgeval-0.3.0a0/PRODUCT.md +33 -0
  18. surgeval-0.3.0a0/README.md +378 -0
  19. surgeval-0.3.0a0/SECURITY.md +42 -0
  20. surgeval-0.3.0a0/docs/ASSESSMENT.md +441 -0
  21. surgeval-0.3.0a0/docs/BUILD.md +457 -0
  22. surgeval-0.3.0a0/docs/CONFORMANCE.md +147 -0
  23. surgeval-0.3.0a0/docs/DATASETS.md +77 -0
  24. surgeval-0.3.0a0/docs/NEXT_STATUS.md +182 -0
  25. surgeval-0.3.0a0/docs/ONRAMP.md +213 -0
  26. surgeval-0.3.0a0/docs/OSS_GOVERNANCE.md +143 -0
  27. surgeval-0.3.0a0/docs/PLAN.md +345 -0
  28. surgeval-0.3.0a0/docs/V0.3.md +79 -0
  29. surgeval-0.3.0a0/docs/examples/agents/example-counterfactual-world-model/agent.toml +21 -0
  30. surgeval-0.3.0a0/docs/examples/agents/example-counterfactual-world-model/predictions.json +43 -0
  31. surgeval-0.3.0a0/docs/examples/agents/example-counterfactual-world-model/predictor.py +21 -0
  32. surgeval-0.3.0a0/docs/examples/agents/example-cvs-detector/agent.toml +21 -0
  33. surgeval-0.3.0a0/docs/examples/agents/example-cvs-detector/predictions.json +34 -0
  34. surgeval-0.3.0a0/docs/examples/agents/example-cvs-detector/predictor.py +23 -0
  35. surgeval-0.3.0a0/docs/examples/agents/example-video-predictor/agent.toml +20 -0
  36. surgeval-0.3.0a0/docs/examples/agents/example-video-predictor/predictions.json +23 -0
  37. surgeval-0.3.0a0/docs/examples/agents/example-video-predictor/predictor.py +21 -0
  38. surgeval-0.3.0a0/docs/examples/agents/seldingermed-cath-seg/agent.toml +19 -0
  39. surgeval-0.3.0a0/docs/examples/agents/seldingermed-cath-seg/predictions.json +18 -0
  40. surgeval-0.3.0a0/docs/examples/agents/seldingermed-cath-seg/predictor.py +164 -0
  41. surgeval-0.3.0a0/docs/examples/agents/seldingermed-cath-seg/weights.json +27 -0
  42. surgeval-0.3.0a0/docs/examples/agents/seldingermed-lumen-linear/agent.toml +19 -0
  43. surgeval-0.3.0a0/docs/examples/agents/seldingermed-lumen-linear/policy.py +29 -0
  44. surgeval-0.3.0a0/docs/examples/agents/seldingermed-lumen-linear/weights.json +8 -0
  45. surgeval-0.3.0a0/docs/examples/agents/seldingermed-random/agent.toml +11 -0
  46. surgeval-0.3.0a0/docs/examples/datasets/angiostress-v0/dataset.toml +10 -0
  47. surgeval-0.3.0a0/docs/examples/datasets/lumen-nav-v0/dataset.toml +11 -0
  48. surgeval-0.3.0a0/docs/examples/datasets/video-nextstep-v0/dataset.toml +10 -0
  49. surgeval-0.3.0a0/docs/examples/jobs/lumen-nav-random/job.toml +16 -0
  50. surgeval-0.3.0a0/docs/examples/shelves/endovascular.toml +62 -0
  51. surgeval-0.3.0a0/docs/examples/tasks/angiostress-dias/contract.json +17 -0
  52. surgeval-0.3.0a0/docs/examples/tasks/angiostress-dias/inputs.json +5 -0
  53. surgeval-0.3.0a0/docs/examples/tasks/angiostress-dias/instruction.md +5 -0
  54. surgeval-0.3.0a0/docs/examples/tasks/angiostress-dias/labels.json +5 -0
  55. surgeval-0.3.0a0/docs/examples/tasks/angiostress-dias/task.toml +100 -0
  56. surgeval-0.3.0a0/docs/examples/tasks/angiostress-dias/verifier.py +46 -0
  57. surgeval-0.3.0a0/docs/examples/tasks/broncho-airway-nav/instruction.md +7 -0
  58. surgeval-0.3.0a0/docs/examples/tasks/broncho-airway-nav/task.toml +94 -0
  59. surgeval-0.3.0a0/docs/examples/tasks/broncho-airway-nav/verifier.py +93 -0
  60. surgeval-0.3.0a0/docs/examples/tasks/counterfactual-recovery/inputs.json +45 -0
  61. surgeval-0.3.0a0/docs/examples/tasks/counterfactual-recovery/instruction.md +1 -0
  62. surgeval-0.3.0a0/docs/examples/tasks/counterfactual-recovery/labels.json +22 -0
  63. surgeval-0.3.0a0/docs/examples/tasks/counterfactual-recovery/task.toml +114 -0
  64. surgeval-0.3.0a0/docs/examples/tasks/counterfactual-recovery/verifier.py +39 -0
  65. surgeval-0.3.0a0/docs/examples/tasks/laparoscopic-cholec-cvs/inputs.json +29 -0
  66. surgeval-0.3.0a0/docs/examples/tasks/laparoscopic-cholec-cvs/instruction.md +5 -0
  67. surgeval-0.3.0a0/docs/examples/tasks/laparoscopic-cholec-cvs/labels.json +29 -0
  68. surgeval-0.3.0a0/docs/examples/tasks/laparoscopic-cholec-cvs/task.toml +79 -0
  69. surgeval-0.3.0a0/docs/examples/tasks/laparoscopic-cholec-cvs/verifier.py +56 -0
  70. surgeval-0.3.0a0/docs/examples/tasks/lumen-nav-safe/instruction.md +11 -0
  71. surgeval-0.3.0a0/docs/examples/tasks/lumen-nav-safe/task.toml +103 -0
  72. surgeval-0.3.0a0/docs/examples/tasks/lumen-nav-safe/verifier.py +42 -0
  73. surgeval-0.3.0a0/docs/examples/tasks/lumen-nav-safe/verifier.toml +6 -0
  74. surgeval-0.3.0a0/docs/examples/tasks/orbit-needle-lift/instruction.md +19 -0
  75. surgeval-0.3.0a0/docs/examples/tasks/orbit-needle-lift/task.toml +80 -0
  76. surgeval-0.3.0a0/docs/examples/tasks/orbit-needle-lift/verifier.py +83 -0
  77. surgeval-0.3.0a0/docs/examples/tasks/orbit-needle-lift/wrap.json +20 -0
  78. surgeval-0.3.0a0/docs/examples/tasks/ortho-burr-safe/instruction.md +7 -0
  79. surgeval-0.3.0a0/docs/examples/tasks/ortho-burr-safe/task.toml +94 -0
  80. surgeval-0.3.0a0/docs/examples/tasks/ortho-burr-safe/verifier.py +44 -0
  81. surgeval-0.3.0a0/docs/examples/tasks/video-nextstep/inputs.json +7 -0
  82. surgeval-0.3.0a0/docs/examples/tasks/video-nextstep/instruction.md +9 -0
  83. surgeval-0.3.0a0/docs/examples/tasks/video-nextstep/labels.json +22 -0
  84. surgeval-0.3.0a0/docs/examples/tasks/video-nextstep/task.toml +77 -0
  85. surgeval-0.3.0a0/docs/examples/tasks/video-nextstep/verifier.py +37 -0
  86. surgeval-0.3.0a0/docs/examples/tasksets/consequence-rank-v1/taskset.toml +10 -0
  87. surgeval-0.3.0a0/docs/examples/tasksets/counterfactual-recovery-v1/taskset.toml +10 -0
  88. surgeval-0.3.0a0/next.md +223 -0
  89. surgeval-0.3.0a0/pyproject.toml +116 -0
  90. surgeval-0.3.0a0/scripts/check_identity.py +112 -0
  91. surgeval-0.3.0a0/scripts/check_license_allowlist.py +56 -0
  92. surgeval-0.3.0a0/scripts/check_pypi_attestation.py +137 -0
  93. surgeval-0.3.0a0/scripts/check_world_signals.py +536 -0
  94. surgeval-0.3.0a0/scripts/gen_sbom.py +205 -0
  95. surgeval-0.3.0a0/scripts/validate_sbom.py +102 -0
  96. surgeval-0.3.0a0/site/app.js +41 -0
  97. surgeval-0.3.0a0/site/favicon.svg +8 -0
  98. surgeval-0.3.0a0/site/index.html +246 -0
  99. surgeval-0.3.0a0/site/styles.css +655 -0
  100. surgeval-0.3.0a0/src/or_audit/__init__.py +21 -0
  101. surgeval-0.3.0a0/src/or_audit/audit/__init__.py +27 -0
  102. surgeval-0.3.0a0/src/or_audit/audit/canonical.py +222 -0
  103. surgeval-0.3.0a0/src/or_audit/audit/trail.py +417 -0
  104. surgeval-0.3.0a0/src/or_audit/cli.py +619 -0
  105. surgeval-0.3.0a0/src/or_audit/commands/__init__.py +50 -0
  106. surgeval-0.3.0a0/src/or_audit/commands/concierge.py +286 -0
  107. surgeval-0.3.0a0/src/or_audit/commands/conformance.py +109 -0
  108. surgeval-0.3.0a0/src/or_audit/commands/doctor.py +46 -0
  109. surgeval-0.3.0a0/src/or_audit/commands/export_verifiers.py +54 -0
  110. surgeval-0.3.0a0/src/or_audit/commands/onramp.py +292 -0
  111. surgeval-0.3.0a0/src/or_audit/commands/quickstart.py +182 -0
  112. surgeval-0.3.0a0/src/or_audit/commands/shelf.py +250 -0
  113. surgeval-0.3.0a0/src/or_audit/commands/worlds.py +193 -0
  114. surgeval-0.3.0a0/src/or_audit/commands/wrap.py +225 -0
  115. surgeval-0.3.0a0/src/or_audit/concierge/__init__.py +137 -0
  116. surgeval-0.3.0a0/src/or_audit/concierge/adapt.py +627 -0
  117. surgeval-0.3.0a0/src/or_audit/concierge/assess.py +206 -0
  118. surgeval-0.3.0a0/src/or_audit/concierge/intake.py +929 -0
  119. surgeval-0.3.0a0/src/or_audit/concierge/select.py +409 -0
  120. surgeval-0.3.0a0/src/or_audit/decision/__init__.py +24 -0
  121. surgeval-0.3.0a0/src/or_audit/decision/record.py +323 -0
  122. surgeval-0.3.0a0/src/or_audit/decision/rule.py +187 -0
  123. surgeval-0.3.0a0/src/or_audit/deid/__init__.py +50 -0
  124. surgeval-0.3.0a0/src/or_audit/deid/attestation.py +125 -0
  125. surgeval-0.3.0a0/src/or_audit/deid/detectors.py +353 -0
  126. surgeval-0.3.0a0/src/or_audit/deid/pipeline.py +459 -0
  127. surgeval-0.3.0a0/src/or_audit/deid/plan.py +145 -0
  128. surgeval-0.3.0a0/src/or_audit/deid/policy.py +234 -0
  129. surgeval-0.3.0a0/src/or_audit/deid/writer.py +90 -0
  130. surgeval-0.3.0a0/src/or_audit/demo.py +303 -0
  131. surgeval-0.3.0a0/src/or_audit/domain/__init__.py +43 -0
  132. surgeval-0.3.0a0/src/or_audit/domain/entities.py +289 -0
  133. surgeval-0.3.0a0/src/or_audit/domain/enums.py +136 -0
  134. surgeval-0.3.0a0/src/or_audit/domain/ids.py +137 -0
  135. surgeval-0.3.0a0/src/or_audit/errors.py +48 -0
  136. surgeval-0.3.0a0/src/or_audit/eval/__init__.py +205 -0
  137. surgeval-0.3.0a0/src/or_audit/eval/adapters/__init__.py +65 -0
  138. surgeval-0.3.0a0/src/or_audit/eval/adapters/base.py +172 -0
  139. surgeval-0.3.0a0/src/or_audit/eval/adapters/endoluminal.py +139 -0
  140. surgeval-0.3.0a0/src/or_audit/eval/adapters/fluoroscopy.py +141 -0
  141. surgeval-0.3.0a0/src/or_audit/eval/adapters/kinematics.py +164 -0
  142. surgeval-0.3.0a0/src/or_audit/eval/adapters/manifest.py +157 -0
  143. surgeval-0.3.0a0/src/or_audit/eval/adapters/video.py +146 -0
  144. surgeval-0.3.0a0/src/or_audit/eval/agent.py +106 -0
  145. surgeval-0.3.0a0/src/or_audit/eval/bind.py +28 -0
  146. surgeval-0.3.0a0/src/or_audit/eval/cartesian.py +206 -0
  147. surgeval-0.3.0a0/src/or_audit/eval/conformance.py +965 -0
  148. surgeval-0.3.0a0/src/or_audit/eval/contracts.py +301 -0
  149. surgeval-0.3.0a0/src/or_audit/eval/dataset.py +84 -0
  150. surgeval-0.3.0a0/src/or_audit/eval/enums.py +153 -0
  151. surgeval-0.3.0a0/src/or_audit/eval/equivalence.py +559 -0
  152. surgeval-0.3.0a0/src/or_audit/eval/evidence.py +178 -0
  153. surgeval-0.3.0a0/src/or_audit/eval/export_rl.py +161 -0
  154. surgeval-0.3.0a0/src/or_audit/eval/export_verifiers.py +1058 -0
  155. surgeval-0.3.0a0/src/or_audit/eval/gate_dsl.py +246 -0
  156. surgeval-0.3.0a0/src/or_audit/eval/gym_world.py +248 -0
  157. surgeval-0.3.0a0/src/or_audit/eval/integrity.py +48 -0
  158. surgeval-0.3.0a0/src/or_audit/eval/job.py +343 -0
  159. surgeval-0.3.0a0/src/or_audit/eval/job_config.py +119 -0
  160. surgeval-0.3.0a0/src/or_audit/eval/leaderboard.py +219 -0
  161. surgeval-0.3.0a0/src/or_audit/eval/licensing.py +631 -0
  162. surgeval-0.3.0a0/src/or_audit/eval/loader.py +240 -0
  163. surgeval-0.3.0a0/src/or_audit/eval/plugin_host.py +94 -0
  164. surgeval-0.3.0a0/src/or_audit/eval/plugins.py +291 -0
  165. surgeval-0.3.0a0/src/or_audit/eval/predict.py +66 -0
  166. surgeval-0.3.0a0/src/or_audit/eval/provenance.py +442 -0
  167. surgeval-0.3.0a0/src/or_audit/eval/reconstitute.py +112 -0
  168. surgeval-0.3.0a0/src/or_audit/eval/registry.py +219 -0
  169. surgeval-0.3.0a0/src/or_audit/eval/runner.py +701 -0
  170. surgeval-0.3.0a0/src/or_audit/eval/scorecard.py +263 -0
  171. surgeval-0.3.0a0/src/or_audit/eval/shelf.py +968 -0
  172. surgeval-0.3.0a0/src/or_audit/eval/sim/__init__.py +76 -0
  173. surgeval-0.3.0a0/src/or_audit/eval/sim/base.py +448 -0
  174. surgeval-0.3.0a0/src/or_audit/eval/sim/gym_bridge.py +92 -0
  175. surgeval-0.3.0a0/src/or_audit/eval/sim/isaac_bridge.py +616 -0
  176. surgeval-0.3.0a0/src/or_audit/eval/sim/sofa_bridge.py +234 -0
  177. surgeval-0.3.0a0/src/or_audit/eval/sim/warp_bridge.py +242 -0
  178. surgeval-0.3.0a0/src/or_audit/eval/task.py +830 -0
  179. surgeval-0.3.0a0/src/or_audit/eval/trace.py +158 -0
  180. surgeval-0.3.0a0/src/or_audit/eval/vector.py +207 -0
  181. surgeval-0.3.0a0/src/or_audit/eval/verifier.py +188 -0
  182. surgeval-0.3.0a0/src/or_audit/eval/worlds.py +333 -0
  183. surgeval-0.3.0a0/src/or_audit/eval/wrap.py +1226 -0
  184. surgeval-0.3.0a0/src/or_audit/ingest/__init__.py +16 -0
  185. surgeval-0.3.0a0/src/or_audit/ingest/alignment.py +109 -0
  186. surgeval-0.3.0a0/src/or_audit/ingest/manifest.py +156 -0
  187. surgeval-0.3.0a0/src/or_audit/install/__init__.py +73 -0
  188. surgeval-0.3.0a0/src/or_audit/install/catalog.py +769 -0
  189. surgeval-0.3.0a0/src/or_audit/install/catalog.toml +1034 -0
  190. surgeval-0.3.0a0/src/or_audit/install/doctor.py +648 -0
  191. surgeval-0.3.0a0/src/or_audit/install/installer.py +516 -0
  192. surgeval-0.3.0a0/src/or_audit/media/__init__.py +23 -0
  193. surgeval-0.3.0a0/src/or_audit/media/frames.py +193 -0
  194. surgeval-0.3.0a0/src/or_audit/metrics/__init__.py +43 -0
  195. surgeval-0.3.0a0/src/or_audit/metrics/agreement.py +223 -0
  196. surgeval-0.3.0a0/src/or_audit/metrics/harness.py +358 -0
  197. surgeval-0.3.0a0/src/or_audit/metrics/icc.py +151 -0
  198. surgeval-0.3.0a0/src/or_audit/perception/__init__.py +47 -0
  199. surgeval-0.3.0a0/src/or_audit/perception/backend.py +210 -0
  200. surgeval-0.3.0a0/src/or_audit/perception/observations.py +321 -0
  201. surgeval-0.3.0a0/src/or_audit/pipeline.py +213 -0
  202. surgeval-0.3.0a0/src/or_audit/primitives.py +80 -0
  203. surgeval-0.3.0a0/src/or_audit/report.py +285 -0
  204. surgeval-0.3.0a0/src/or_audit/scoring/__init__.py +43 -0
  205. surgeval-0.3.0a0/src/or_audit/scoring/gates.py +533 -0
  206. surgeval-0.3.0a0/src/or_audit/scoring/skill.py +206 -0
  207. surgeval-0.3.0a0/src/or_audit/version.py +23 -0
  208. surgeval-0.3.0a0/src/surgeval/__init__.py +134 -0
  209. surgeval-0.3.0a0/src/surgeval/client.py +301 -0
  210. surgeval-0.3.0a0/src/surgeval/decorators.py +475 -0
  211. surgeval-0.3.0a0/src/surgeval/integrations.py +113 -0
  212. surgeval-0.3.0a0/tests/__init__.py +4 -0
  213. surgeval-0.3.0a0/tests/conftest.py +159 -0
  214. surgeval-0.3.0a0/tests/test_agreement_gate.py +432 -0
  215. surgeval-0.3.0a0/tests/test_artifact_portability.py +253 -0
  216. surgeval-0.3.0a0/tests/test_audit_trail.py +389 -0
  217. surgeval-0.3.0a0/tests/test_canonical.py +165 -0
  218. surgeval-0.3.0a0/tests/test_canonical_conformance.py +143 -0
  219. surgeval-0.3.0a0/tests/test_check_pypi_attestation.py +105 -0
  220. surgeval-0.3.0a0/tests/test_check_world_signals.py +659 -0
  221. surgeval-0.3.0a0/tests/test_cli_branding.py +29 -0
  222. surgeval-0.3.0a0/tests/test_concierge.py +1524 -0
  223. surgeval-0.3.0a0/tests/test_conformance.py +1217 -0
  224. surgeval-0.3.0a0/tests/test_cvs_end_to_end.py +67 -0
  225. surgeval-0.3.0a0/tests/test_decision.py +416 -0
  226. surgeval-0.3.0a0/tests/test_deid_detectors.py +194 -0
  227. surgeval-0.3.0a0/tests/test_deid_leaks.py +986 -0
  228. surgeval-0.3.0a0/tests/test_deid_pipeline.py +436 -0
  229. surgeval-0.3.0a0/tests/test_end_to_end.py +409 -0
  230. surgeval-0.3.0a0/tests/test_entities.py +274 -0
  231. surgeval-0.3.0a0/tests/test_eval_contracts.py +177 -0
  232. surgeval-0.3.0a0/tests/test_eval_p3.py +442 -0
  233. surgeval-0.3.0a0/tests/test_eval_p4.py +186 -0
  234. surgeval-0.3.0a0/tests/test_eval_plugin_host.py +246 -0
  235. surgeval-0.3.0a0/tests/test_eval_run.py +434 -0
  236. surgeval-0.3.0a0/tests/test_eval_task.py +490 -0
  237. surgeval-0.3.0a0/tests/test_eval_v03.py +444 -0
  238. surgeval-0.3.0a0/tests/test_export_verifiers.py +504 -0
  239. surgeval-0.3.0a0/tests/test_frames.py +154 -0
  240. surgeval-0.3.0a0/tests/test_gate_dsl.py +369 -0
  241. surgeval-0.3.0a0/tests/test_gate_evidence_discipline.py +432 -0
  242. surgeval-0.3.0a0/tests/test_ids.py +79 -0
  243. surgeval-0.3.0a0/tests/test_ingest.py +206 -0
  244. surgeval-0.3.0a0/tests/test_install_ladder.py +1072 -0
  245. surgeval-0.3.0a0/tests/test_licensing_expressions.py +146 -0
  246. surgeval-0.3.0a0/tests/test_metrics.py +217 -0
  247. surgeval-0.3.0a0/tests/test_modality_adapters.py +340 -0
  248. surgeval-0.3.0a0/tests/test_multi_modality_contracts.py +408 -0
  249. surgeval-0.3.0a0/tests/test_onramp.py +567 -0
  250. surgeval-0.3.0a0/tests/test_perception.py +352 -0
  251. surgeval-0.3.0a0/tests/test_public_registry.py +44 -0
  252. surgeval-0.3.0a0/tests/test_safety_gates.py +498 -0
  253. surgeval-0.3.0a0/tests/test_sbom_gen.py +179 -0
  254. surgeval-0.3.0a0/tests/test_shelf_equivalence.py +1442 -0
  255. surgeval-0.3.0a0/tests/test_simulation_bridges.py +1240 -0
  256. surgeval-0.3.0a0/tests/test_skill_scoring.py +159 -0
  257. surgeval-0.3.0a0/tests/test_surgeval_sdk.py +270 -0
  258. surgeval-0.3.0a0/tests/test_world_kinds.py +562 -0
  259. surgeval-0.3.0a0/tests/test_world_signals.py +597 -0
  260. surgeval-0.3.0a0/tests/test_wrap_kit.py +660 -0
  261. surgeval-0.3.0a0/uv.lock +947 -0
@@ -0,0 +1 @@
1
+ *
@@ -0,0 +1,16 @@
1
+ .git
2
+ .github
3
+ .venv
4
+ .pytest_cache
5
+ .mypy_cache
6
+ .ruff_cache
7
+ .coverage*
8
+ __pycache__
9
+ *.pyc
10
+ build
11
+ dist
12
+ data
13
+ scratch
14
+ tests
15
+ docs
16
+ site
@@ -0,0 +1,68 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ lint:
18
+ name: Lint and type-check
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
22
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
23
+ with:
24
+ enable-cache: true
25
+ - name: Install
26
+ run: uv sync --all-extras
27
+ - name: Ruff format check
28
+ run: uv run ruff format --check .
29
+ - name: Ruff lint
30
+ run: uv run ruff check --output-format=github .
31
+ - name: Mypy
32
+ run: uv run mypy
33
+
34
+ test:
35
+ name: Test (py${{ matrix.python-version }})
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ python-version: ["3.11", "3.12", "3.13"]
41
+ steps:
42
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
43
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
44
+ with:
45
+ enable-cache: true
46
+ - name: Install
47
+ run: uv sync --all-extras --python ${{ matrix.python-version }}
48
+ - name: Pytest
49
+ run: uv run --python ${{ matrix.python-version }} pytest --cov --cov-report=term-missing --cov-fail-under=90
50
+
51
+ packaging:
52
+ name: OSS packaging gates
53
+ runs-on: ubuntu-latest
54
+ steps:
55
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
56
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
57
+ with:
58
+ enable-cache: true
59
+ - name: Runtime license allowlist
60
+ run: uv run python scripts/check_license_allowlist.py
61
+ - name: Identity consolidation + wheel contents
62
+ run: uv run python scripts/check_identity.py
63
+ - name: SBOM generation + structural SPDX-2.3 validation
64
+ run: |
65
+ uv run python scripts/gen_sbom.py --out sbom.spdx.json
66
+ uv run python scripts/validate_sbom.py --sbom sbom.spdx.json
67
+ - name: Validate neutral example taskset
68
+ run: uv run surgeval tasksets validate docs/examples/tasksets/consequence-rank-v1
@@ -0,0 +1,31 @@
1
+ name: Droid Auto Review
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, ready_for_review, reopened]
6
+
7
+ concurrency:
8
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
9
+ cancel-in-progress: true
10
+
11
+ jobs:
12
+ droid-review:
13
+ if: github.event.pull_request.draft == false
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ contents: write
17
+ pull-requests: write
18
+ issues: write
19
+ id-token: write
20
+ actions: read
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
24
+ with:
25
+ fetch-depth: 1
26
+ - name: Run Droid Auto Review
27
+ uses: Factory-AI/droid-action@c6951275d02429bb172eadc7302352d21b45a694 # main
28
+ with:
29
+ factory_api_key: ${{ secrets.FACTORY_API_KEY }}
30
+ automatic_review: true
31
+ automatic_security_review: true
@@ -0,0 +1,38 @@
1
+ name: Droid Tag
2
+
3
+ on:
4
+ issue_comment:
5
+ types: [created]
6
+ pull_request_review_comment:
7
+ types: [created]
8
+ issues:
9
+ types: [opened, assigned]
10
+ pull_request_review:
11
+ types: [submitted]
12
+ pull_request:
13
+ types: [opened, edited]
14
+
15
+ jobs:
16
+ droid:
17
+ if: |
18
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@droid')) ||
19
+ (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@droid')) ||
20
+ (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@droid')) ||
21
+ (github.event_name == 'issues' && (contains(github.event.issue.body, '@droid') || contains(github.event.issue.title, '@droid'))) ||
22
+ (github.event_name == 'pull_request' && (contains(github.event.pull_request.body, '@droid') || contains(github.event.pull_request.title, '@droid')))
23
+ runs-on: ubuntu-latest
24
+ permissions:
25
+ contents: read
26
+ pull-requests: write
27
+ issues: write
28
+ id-token: write
29
+ actions: read
30
+ steps:
31
+ - name: Checkout repository
32
+ uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
33
+ with:
34
+ fetch-depth: 1
35
+ - name: Run Droid Exec
36
+ uses: Factory-AI/droid-action@c6951275d02429bb172eadc7302352d21b45a694 # main
37
+ with:
38
+ factory_api_key: ${{ secrets.FACTORY_API_KEY }}
@@ -0,0 +1,238 @@
1
+ name: install-smoke
2
+
3
+ # Deliberately a separate workflow from kernel CI (§6.5 pattern).
4
+ #
5
+ # Kernel CI must stay fast, hermetic, and green on every PR: it proves the
6
+ # harness contract. This workflow proves something different and structurally
7
+ # flakier — that the *install ladder* still works against the outside world.
8
+ # Its jobs depend on registries, vendor accounts, EULA gates, and GPU hosts we
9
+ # do not control, so a broken upstream must never be able to red-flag a kernel
10
+ # change. Hence: no `push`/`pull_request` trigger, manual dispatch plus a
11
+ # weekly schedule, and a plan-only default for anything that would touch a
12
+ # third-party registry.
13
+ #
14
+ # One job per install strategy *the catalog actually uses*, discovered from the
15
+ # data rather than hardcoded here. The list moved once already — the audit
16
+ # deleted both `pip-extra` rows (neither package is on PyPI) and added
17
+ # `source-build` — and a hardcoded matrix answered that by failing on an empty
18
+ # strategy instead of by testing the new one. Plus a real `surgeval quickstart`
19
+ # job, the only one that runs a world end to end (CPU-only, no sim deps, no GPU).
20
+ #
21
+ # Until a strategy's entries are license-audited and pin-recorded, its plan
22
+ # step *refuses*. That is a pass here: the ladder's job is to name the missing
23
+ # artifact, and this workflow asserts it names one rather than guessing.
24
+
25
+ on:
26
+ workflow_dispatch:
27
+ schedule:
28
+ # Mondays 05:17 UTC. Off-hour so a registry hiccup does not land in
29
+ # the middle of a review cycle.
30
+ - cron: "17 5 * * 1"
31
+
32
+ permissions:
33
+ contents: read
34
+
35
+ concurrency:
36
+ group: install-smoke-${{ github.ref }}
37
+ cancel-in-progress: true
38
+
39
+ jobs:
40
+ signals:
41
+ name: audited signal citations resolve at their pins
42
+ runs-on: ubuntu-latest
43
+ # Lives here, not in kernel CI, for the same reason as the ladder: it
44
+ # fetches third-party source trees over the network (git, against each
45
+ # catalog pin), so it must not sit in front of a PR. It is also the only
46
+ # check that can catch the class of defect it was written
47
+ # for - a citation pointing at code the pinned revision does not contain -
48
+ # because a prose evidence field cannot be checked by a machine.
49
+ #
50
+ # It fails closed, and being off the PR path is exactly what buys that: an
51
+ # unreachable upstream exits 2 and turns this job red. The alternative was
52
+ # tried and was worse - the first version printed SKIP and still exited 0
53
+ # as long as some other world checked, so a registry outage could have
54
+ # reported success while verifying none of the seven wrap targets. A green
55
+ # tick here means all of them were fetched and checked, or it means
56
+ # nothing at all.
57
+ steps:
58
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
59
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
60
+ with:
61
+ enable-cache: true
62
+ - name: Verify every audited env path and signal line at its world pin
63
+ # Exit 1 = a citation does not resolve. Exit 2 = something could not be
64
+ # checked. Neither is success; do not add continue-on-error here.
65
+ run: uv run python scripts/check_world_signals.py
66
+
67
+ quickstart:
68
+ name: quickstart (CPU-only, no sim deps)
69
+ runs-on: ubuntu-latest
70
+ steps:
71
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
72
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
73
+ with:
74
+ enable-cache: true
75
+
76
+ # The N10 contract is "first vector in minutes on any machine" in <=3
77
+ # commands, so this installs the distribution the way a user would rather
78
+ # than syncing the dev environment. The wheel force-includes the
79
+ # reference pair under `or_audit/_examples`, so every step below runs
80
+ # from a scratch directory with no checkout in sight: if quickstart only
81
+ # worked inside a clone, the ladder's first rung would be a lie.
82
+ - name: Install the distribution the way a user would
83
+ run: |
84
+ uv tool install .
85
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
86
+
87
+ - name: Leave the checkout
88
+ run: mkdir -p "$RUNNER_TEMP/elsewhere"
89
+
90
+ - name: Doctor
91
+ working-directory: ${{ runner.temp }}/elsewhere
92
+ run: surgeval doctor
93
+
94
+ - name: Quickstart and record time-to-first-vector
95
+ working-directory: ${{ runner.temp }}/elsewhere
96
+ run: |
97
+ surgeval quickstart --out "$RUNNER_TEMP/quickstart" --json \
98
+ | tee "$RUNNER_TEMP/ttfv.json"
99
+
100
+ - name: Assert the metric is real and the vector replays
101
+ working-directory: ${{ runner.temp }}/elsewhere
102
+ run: |
103
+ python3 - "$RUNNER_TEMP/ttfv.json" > "$RUNNER_TEMP/replay.args" <<'PY'
104
+ import json
105
+ import sys
106
+
107
+ with open(sys.argv[1], encoding="utf-8") as handle:
108
+ record = json.load(handle)
109
+ assert record["time_to_first_vector_sec"] > 0, record
110
+ assert record["task_id"], record
111
+ print(record["out"], record["head"])
112
+ PY
113
+ read -r OUT HEAD < "$RUNNER_TEMP/replay.args"
114
+ surgeval replay "$OUT" --expect-head "$HEAD"
115
+
116
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
117
+ with:
118
+ name: time-to-first-vector
119
+ path: ${{ runner.temp }}/ttfv.json
120
+
121
+ strategies:
122
+ name: discover strategies in use
123
+ runs-on: ubuntu-latest
124
+ outputs:
125
+ list: ${{ steps.read.outputs.list }}
126
+ steps:
127
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
128
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
129
+ with:
130
+ enable-cache: true
131
+ - name: Install
132
+ run: uv sync --all-extras
133
+ - name: Read the strategies the catalog uses
134
+ id: read
135
+ run: |
136
+ uv run python - <<'PY' >> "$GITHUB_OUTPUT"
137
+ import json
138
+
139
+ from or_audit.install.catalog import load_catalog
140
+
141
+ used = sorted({pkg.strategy.value for pkg in load_catalog().worlds})
142
+ assert used, "catalog has no worlds at all"
143
+ print(f"list={json.dumps(used)}")
144
+ PY
145
+
146
+ ladder:
147
+ name: plan ${{ matrix.strategy }}
148
+ runs-on: ubuntu-latest
149
+ needs: strategies
150
+ strategy:
151
+ fail-fast: false
152
+ matrix:
153
+ strategy: ${{ fromJSON(needs.strategies.outputs.list) }}
154
+ steps:
155
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
156
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
157
+ with:
158
+ enable-cache: true
159
+ - name: Install
160
+ run: uv sync --all-extras
161
+
162
+ - name: List the worlds using this strategy
163
+ run: uv run surgeval worlds list --strategy "${{ matrix.strategy }}"
164
+
165
+ - name: Plan every install for this strategy (dry run, no network)
166
+ env:
167
+ STRATEGY: ${{ matrix.strategy }}
168
+ run: |
169
+ uv run python - <<'PY'
170
+ import os
171
+ import subprocess
172
+ import sys
173
+
174
+ from or_audit.install.catalog import (
175
+ InstallStrategy,
176
+ VendorRuntimeInstall,
177
+ iter_packages,
178
+ )
179
+
180
+ strategy = InstallStrategy(os.environ["STRATEGY"])
181
+ packages = iter_packages(strategy=strategy)
182
+ assert packages, f"catalog has no {strategy.value} entries"
183
+
184
+ planned, refused = 0, 0
185
+ for pkg in packages:
186
+ # Accepting the vendor EULA in CI is exactly what a user does
187
+ # interactively, and only a vendor runtime has one to accept. The
188
+ # plan still pulls nothing without --execute. Derived per package
189
+ # rather than per matrix row so a mixed strategy cannot silently
190
+ # skip the acceptance path.
191
+ extra = (
192
+ ["--accept-vendor-eula"]
193
+ if isinstance(pkg.install, VendorRuntimeInstall)
194
+ else []
195
+ )
196
+ argv = ["uv", "run", "surgeval", "worlds", "install", pkg.id, *extra]
197
+ done = subprocess.run(argv, capture_output=True, text=True)
198
+ sys.stdout.write(done.stdout)
199
+ sys.stderr.write(done.stderr)
200
+ if done.returncode == 0:
201
+ planned += 1
202
+ # A dry run must never execute anything.
203
+ assert "dry run" in done.stdout, pkg.id
204
+ elif done.returncode == 1:
205
+ refused += 1
206
+ # A refusal is a pass only when it names the fix.
207
+ assert "REFUSED:" in done.stderr, pkg.id
208
+ assert "Fix:" in done.stderr or "re-run with" in done.stderr, pkg.id
209
+ else:
210
+ raise SystemExit(f"{pkg.id}: unexpected exit {done.returncode}")
211
+ print(f"{strategy.value}: {planned} planned, {refused} refused with a named fix")
212
+ PY
213
+
214
+ - name: Doctor for each world using this strategy
215
+ env:
216
+ STRATEGY: ${{ matrix.strategy }}
217
+ run: |
218
+ uv run python - <<'PY'
219
+ import os
220
+ import subprocess
221
+
222
+ from or_audit.install.catalog import Disposition, InstallStrategy, iter_packages
223
+
224
+ strategy = InstallStrategy(os.environ["STRATEGY"])
225
+ for pkg in iter_packages(strategy=strategy):
226
+ if pkg.disposition not in {Disposition.SHIPPED, Disposition.WRAP}:
227
+ continue
228
+ # Exit 1 is expected on a runner with no SOFA/Isaac; the point is
229
+ # that every reported problem carries a fix, which the report's
230
+ # own contract enforces.
231
+ done = subprocess.run(
232
+ ["uv", "run", "surgeval", "doctor", "--world", pkg.id, "--json"],
233
+ capture_output=True,
234
+ text=True,
235
+ )
236
+ assert done.returncode in {0, 1}, (pkg.id, done.returncode, done.stderr)
237
+ print(pkg.id, "->", "ok" if done.returncode == 0 else "needs work")
238
+ PY
@@ -0,0 +1,198 @@
1
+ name: Publish
2
+
3
+ # Publisher-signature verification at the release-artifact layer.
4
+ #
5
+ # Trust model: no dormant in-band signing key. Publisher provenance is
6
+ # established out-of-band and enforced end to end:
7
+ #
8
+ # 1. PyPI trusted publishing (OIDC) — secretless upload; GitHub's OIDC
9
+ # id-token proves workflow identity to PyPI.
10
+ # 2. Sigstore build attestations, two independent records over the SAME
11
+ # built bytes:
12
+ # - a GitHub Artifact Attestation (``actions/attest-build-provenance``),
13
+ # verified cryptographically by ``gh attestation verify`` against
14
+ # Sigstore's public-good root (this is the publisher-signature check);
15
+ # - a PEP 740 attestation stored on PyPI by ``gh-action-pypi-publish``,
16
+ # whose *presence* and digest-consistency are confirmed by
17
+ # ``scripts/check_pypi_attestation.py`` (the crypto verification of the
18
+ # same bytes is the GitHub attestation above).
19
+ #
20
+ # Least privilege: only jobs that publish/attest hold ``id-token``; the build
21
+ # job that executes project code is unprivileged and hands over immutable
22
+ # artifacts via upload/download. Project code is never built or installed in a
23
+ # job that holds OIDC release credentials.
24
+ #
25
+ # Task-registry (taskset/agent) signature verification is a separate trust
26
+ # domain; see docs/OSS_GOVERNANCE.md.
27
+
28
+ on:
29
+ push:
30
+ tags: ["v*"]
31
+ workflow_dispatch:
32
+ inputs:
33
+ version:
34
+ description: "Release version (e.g. 0.4.0). Must match pyproject/package version."
35
+ required: true
36
+ type: string
37
+
38
+ permissions:
39
+ contents: read
40
+
41
+ jobs:
42
+ build:
43
+ # Manual releases must originate on main; the tag-triggered path is the
44
+ # sole other entry (pushed v* tags). Skipping this job cascades to every
45
+ # dependent job, so a dispatch from a feature branch runs nothing.
46
+ if: github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main'
47
+ runs-on: ubuntu-latest
48
+ outputs:
49
+ version: ${{ steps.version.outputs.value }}
50
+ steps:
51
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
52
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
53
+ with:
54
+ enable-cache: true
55
+ - name: Resolve release version
56
+ id: version
57
+ env:
58
+ DISPATCH_VERSION: ${{ github.event.inputs.version }}
59
+ run: |
60
+ if [ "${{ github.event_name }}" = "push" ]; then
61
+ echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
62
+ else
63
+ # The dispatch input is user-controlled; never splice it into a
64
+ # shell program. Validate it looks like a version, then pass it
65
+ # through the environment rather than the command string.
66
+ if ! printf '%s' "$DISPATCH_VERSION" | grep -Eq '^[0-9][A-Za-z0-9._+]*$'; then
67
+ echo "invalid release version: $DISPATCH_VERSION" >&2
68
+ exit 1
69
+ fi
70
+ echo "value=$DISPATCH_VERSION" >> "$GITHUB_OUTPUT"
71
+ fi
72
+ - name: Enforce pre-publication version gate
73
+ run: uv run python scripts/check_identity.py --expected-version "${{ steps.version.outputs.value }}"
74
+ - name: Install
75
+ run: uv sync --all-extras
76
+ - name: Test
77
+ run: uv run pytest -q
78
+ - name: Verify runtime licenses (commercial allowlist)
79
+ run: uv run python scripts/check_license_allowlist.py
80
+ - name: Verify identity consolidation
81
+ run: uv run python scripts/check_identity.py
82
+ - name: Build sdist + wheel
83
+ run: uv build
84
+ - name: Twine metadata check
85
+ run: uvx twine check dist/*
86
+ - name: Generate SPDX SBOM
87
+ run: uv run python scripts/gen_sbom.py --out sbom.spdx.json
88
+ - name: Validate SBOM against SPDX 2.3 schema
89
+ run: |
90
+ curl -fsSL \
91
+ https://raw.githubusercontent.com/spdx/spdx-spec/v2.3/schemas/spdx-schema.json \
92
+ -o spdx-schema.json
93
+ uv pip install jsonschema
94
+ uv run python scripts/validate_sbom.py --sbom sbom.spdx.json --schema spdx-schema.json
95
+ - name: Record artifact digests
96
+ run: sha256sum dist/* sbom.spdx.json > RELEASE_DIGESTS.txt
97
+ - name: Upload build artifacts
98
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
99
+ with:
100
+ name: surgeval-dist
101
+ path: |
102
+ dist/
103
+ sbom.spdx.json
104
+ RELEASE_DIGESTS.txt
105
+
106
+ attest:
107
+ name: Attest + verify (GitHub Sigstore)
108
+ runs-on: ubuntu-latest
109
+ needs: build
110
+ permissions:
111
+ contents: read
112
+ id-token: write
113
+ attestations: write
114
+ steps:
115
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
116
+ with:
117
+ name: surgeval-dist
118
+ - name: Attest build provenance (GitHub artifact attestation)
119
+ uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1
120
+ with:
121
+ subject-path: dist/*
122
+ - name: Verify GitHub attestation (Sigstore public-good root)
123
+ env:
124
+ GH_TOKEN: ${{ github.token }}
125
+ run: |
126
+ for file in dist/*; do
127
+ gh attestation verify "$file" \
128
+ --repo "${{ github.repository }}" \
129
+ --predicate-type https://slsa.dev/provenance/v1
130
+ done
131
+
132
+ publish:
133
+ name: Publish to PyPI (minimal, OIDC)
134
+ runs-on: ubuntu-latest
135
+ needs: attest
136
+ environment: release
137
+ permissions:
138
+ contents: read
139
+ id-token: write
140
+ steps:
141
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
142
+ with:
143
+ name: surgeval-dist
144
+ - name: Publish to PyPI (trusted publishing + PEP 740 attestations)
145
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
146
+ with:
147
+ attestations: "true"
148
+
149
+ verify-pypi:
150
+ name: Check PyPI PEP 740 bundle + digest (unprivileged)
151
+ runs-on: ubuntu-latest
152
+ needs: [publish, build]
153
+ permissions:
154
+ contents: read
155
+ steps:
156
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
157
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
158
+ with:
159
+ enable-cache: true
160
+ - name: Sync (for scripts + uv)
161
+ run: uv sync --no-dev
162
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
163
+ with:
164
+ name: surgeval-dist
165
+ - name: Check PyPI serves built digests with PEP 740 bundles present
166
+ run: |
167
+ version="${{ needs.build.outputs.version }}"
168
+ # PEP 740 index entry may lag upload by a few seconds; retry before failing.
169
+ for attempt in 1 2 3 4 5; do
170
+ if uv run python scripts/check_pypi_attestation.py \
171
+ "$version" RELEASE_DIGESTS.txt \
172
+ --publisher-repo "${{ github.repository }}"; then
173
+ exit 0
174
+ fi
175
+ echo "provenance not yet visible (attempt $attempt); retrying"
176
+ sleep 10
177
+ done
178
+ exit 1
179
+
180
+ release:
181
+ runs-on: ubuntu-latest
182
+ needs: [attest, verify-pypi, build]
183
+ permissions:
184
+ contents: write
185
+ steps:
186
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
187
+ with:
188
+ name: surgeval-dist
189
+ - name: Create GitHub Release
190
+ uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
191
+ with:
192
+ tag_name: ${{ github.event_name == 'push' && github.ref_name || format('v{0}', needs.build.outputs.version) }}
193
+ files: |
194
+ dist/surgeval-*.whl
195
+ dist/surgeval-*.tar.gz
196
+ sbom.spdx.json
197
+ RELEASE_DIGESTS.txt
198
+ generate_release_notes: true
@@ -0,0 +1,42 @@
1
+ name: SBOM
2
+
3
+ # On-demand / branch SPDX SBOM generation: resolves uv.lock into an SPDX 2.3
4
+ # JSON document, validates it against the official SPDX 2.3 JSON schema plus
5
+ # the SurgEval structural checks, gates the license allowlist, and uploads the
6
+ # SBOM as an artifact. The release path (Publish.yml) also generates and
7
+ # validates the SBOM; this workflow covers ad-hoc dispatch and branch pushes.
8
+
9
+ on:
10
+ workflow_dispatch:
11
+ push:
12
+ branches: [main]
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ sbom:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
22
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
23
+ with:
24
+ enable-cache: true
25
+ - name: Install
26
+ run: uv sync --all-extras
27
+ - name: Generate SPDX SBOM
28
+ run: uv run python scripts/gen_sbom.py --out sbom.spdx.json
29
+ - name: Validate against SPDX 2.3 schema
30
+ run: |
31
+ curl -fsSL \
32
+ https://raw.githubusercontent.com/spdx/spdx-spec/v2.3/schemas/spdx-schema.json \
33
+ -o spdx-schema.json
34
+ uv pip install jsonschema
35
+ uv run python scripts/validate_sbom.py --sbom sbom.spdx.json --schema spdx-schema.json
36
+ - name: License allowlist gate
37
+ run: uv run python scripts/check_license_allowlist.py
38
+ - name: Upload SBOM
39
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
40
+ with:
41
+ name: surgeval-sbom
42
+ path: sbom.spdx.json
@@ -0,0 +1,46 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+
8
+ # Environments
9
+ .venv/
10
+ venv/
11
+
12
+ # Tooling caches
13
+ .pytest_cache/
14
+ .mypy_cache/
15
+ .ruff_cache/
16
+ .coverage
17
+ .coverage.*
18
+ htmlcov/
19
+ coverage.xml
20
+
21
+ # Editors / OS
22
+ .DS_Store
23
+ .idea/
24
+ .vscode/
25
+
26
+ # Agent tool state
27
+ .opencode/
28
+
29
+ # Local data. Surgical media must never enter version control.
30
+ /data/
31
+ /scratch/
32
+ *.mp4
33
+ *.mkv
34
+ *.mov
35
+ *.avi
36
+ *.dcm
37
+
38
+ .projects/cache
39
+ .projects/vault
40
+ .projects/state.test.json
41
+ .projects/state.local.test.json
42
+ .env
43
+ .env.*
44
+ !.env.example
45
+ .projects/
46
+ .pnpm-store/