@opensoha/contracts 0.1.23 → 0.1.25

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 (415) hide show
  1. package/COMPATIBILITY.md +95 -0
  2. package/README.md +24 -6
  3. package/agent/environment/README.md +55 -0
  4. package/agent/environment/export.go +139 -0
  5. package/agent/environment/export_test.go +62 -0
  6. package/agent/environment/preflight.go +62 -0
  7. package/agent/environment/preflight_test.go +41 -0
  8. package/agent/environment/protocol.go +221 -0
  9. package/agent/environment/protocol_test.go +81 -0
  10. package/agent/environment-lease.schema.json +2 -2
  11. package/agent/environment-template.schema.json +1 -1
  12. package/agent/guest/browser_network.go +77 -0
  13. package/agent/guest/data.go +62 -0
  14. package/agent/guest/protocol.go +235 -0
  15. package/agent/guest/protocol_test.go +142 -0
  16. package/agent/guest/renewal.go +56 -0
  17. package/agent/guest/renewal_test.go +53 -0
  18. package/agent/guest/runtime.go +315 -0
  19. package/agent/guest/runtime_json.go +75 -0
  20. package/agent/guest/runtime_test.go +110 -0
  21. package/agent/personal-browser-network-request.schema.json +40 -0
  22. package/agent/personal-browser-network-response.schema.json +44 -0
  23. package/agent/personal-environment-export.schema.json +55 -0
  24. package/agent/personal-environment-preflight-request.schema.json +52 -0
  25. package/agent/personal-environment-preflight-result.schema.json +69 -0
  26. package/agent/personal-environment-request.schema.json +137 -0
  27. package/agent/personal-environment-result.schema.json +101 -0
  28. package/agent/personal-guest-binding.schema.json +92 -0
  29. package/agent/personal-guest-data-plan.schema.json +32 -0
  30. package/agent/personal-guest-enrollment.schema.json +21 -0
  31. package/agent/personal-guest-heartbeat.schema.json +44 -0
  32. package/agent/personal-guest-provisioning.schema.json +71 -0
  33. package/agent/personal-guest-renewal.schema.json +33 -0
  34. package/agent/personal-guest-runtime-result.schema.json +164 -0
  35. package/agent/personal-guest-runtime.schema.json +304 -0
  36. package/agent/personal-guest-tools.schema.json +75 -0
  37. package/auth/catalog_generated.go +2 -2
  38. package/auth/gateway_permissions_test.go +48 -0
  39. package/auth/permission-catalog.json +331 -1
  40. package/auth/token-claims.schema.json +5 -0
  41. package/compat/consumer-revisions.json +3 -2
  42. package/compat/json-schema-ecosystem-0.1.0.json +1 -1
  43. package/compat/openapi-loose-boundaries-0.1.0.json +1 -1
  44. package/connectors/connector-action.schema.json +138 -0
  45. package/fixtures/json-schema/connector-action/invalid/empty-values.json +11 -0
  46. package/fixtures/json-schema/connector-action/invalid/invalid-expiry.json +16 -0
  47. package/fixtures/json-schema/connector-action/invalid/lowercase-alias.json +16 -0
  48. package/fixtures/json-schema/connector-action/invalid/unknown-entry-field.json +17 -0
  49. package/fixtures/json-schema/connector-action/invalid/unknown-frame-field.json +17 -0
  50. package/fixtures/json-schema/connector-action/invalid/unknown-version.json +16 -0
  51. package/fixtures/json-schema/connector-action/invalid/unversioned-reference.json +16 -0
  52. package/fixtures/json-schema/connector-action/invalid/zero-version.json +16 -0
  53. package/fixtures/json-schema/connector-action/valid/pinned.json +16 -0
  54. package/fixtures/json-schema/connector-definition/invalid/credential-userinfo.json +8 -0
  55. package/fixtures/json-schema/connector-definition/invalid/reference-traversal.json +8 -0
  56. package/fixtures/json-schema/connector-definition/invalid/zero-version.json +8 -0
  57. package/fixtures/json-schema/connector-definition/valid/canonical.json +8 -0
  58. package/fixtures/json-schema/connector-definition/valid/pinned.json +8 -0
  59. package/fixtures/json-schema/personal-browser-network-request/invalid/bounded.json +4 -0
  60. package/fixtures/json-schema/personal-browser-network-request/valid/bounded.json +4 -0
  61. package/fixtures/json-schema/personal-browser-network-response/invalid/bounded.json +5 -0
  62. package/fixtures/json-schema/personal-browser-network-response/valid/bounded.json +5 -0
  63. package/fixtures/json-schema/personal-environment-export/invalid/extra.json +11 -0
  64. package/fixtures/json-schema/personal-environment-export/invalid/ownerId.json +10 -0
  65. package/fixtures/json-schema/personal-environment-export/invalid/sha256.json +10 -0
  66. package/fixtures/json-schema/personal-environment-export/invalid/sizeBytes.json +10 -0
  67. package/fixtures/json-schema/personal-environment-export/valid/complete.json +10 -0
  68. package/fixtures/json-schema/personal-environment-preflight-request/invalid/disk.json +11 -0
  69. package/fixtures/json-schema/personal-environment-preflight-request/invalid/network.json +11 -0
  70. package/fixtures/json-schema/personal-environment-preflight-request/invalid/node.json +12 -0
  71. package/fixtures/json-schema/personal-environment-preflight-request/invalid/owner.json +12 -0
  72. package/fixtures/json-schema/personal-environment-preflight-request/valid/bounded.json +11 -0
  73. package/fixtures/json-schema/personal-environment-preflight-result/invalid/disk.json +15 -0
  74. package/fixtures/json-schema/personal-environment-preflight-result/invalid/network.json +15 -0
  75. package/fixtures/json-schema/personal-environment-preflight-result/invalid/no-hard-quota.json +15 -0
  76. package/fixtures/json-schema/personal-environment-preflight-result/invalid/node.json +16 -0
  77. package/fixtures/json-schema/personal-environment-preflight-result/invalid/not-ready.json +15 -0
  78. package/fixtures/json-schema/personal-environment-preflight-result/invalid/owner.json +16 -0
  79. package/fixtures/json-schema/personal-environment-preflight-result/valid/bounded.json +15 -0
  80. package/fixtures/json-schema/personal-environment-request/invalid/delete-data-argv.json +24 -0
  81. package/fixtures/json-schema/personal-environment-request/invalid/delete-data-createData.json +22 -0
  82. package/fixtures/json-schema/personal-environment-request/invalid/delete-data-taskId.json +22 -0
  83. package/fixtures/json-schema/personal-environment-request/invalid/export-argv.json +22 -0
  84. package/fixtures/json-schema/personal-environment-request/invalid/export-createData.json +22 -0
  85. package/fixtures/json-schema/personal-environment-request/invalid/export-taskId.json +22 -0
  86. package/fixtures/json-schema/personal-environment-request/invalid/extra-command.json +24 -0
  87. package/fixtures/json-schema/personal-environment-request/invalid/host-workspace.json +22 -0
  88. package/fixtures/json-schema/personal-environment-request/invalid/image-injection.json +22 -0
  89. package/fixtures/json-schema/personal-environment-request/invalid/network-egress.json +21 -0
  90. package/fixtures/json-schema/personal-environment-request/invalid/no-command.json +21 -0
  91. package/fixtures/json-schema/personal-environment-request/invalid/recreate-on-release.json +22 -0
  92. package/fixtures/json-schema/personal-environment-request/invalid/relative-command.json +24 -0
  93. package/fixtures/json-schema/personal-environment-request/invalid/released-identity.json +22 -0
  94. package/fixtures/json-schema/personal-environment-request/invalid/task-empty.json +27 -0
  95. package/fixtures/json-schema/personal-environment-request/invalid/task-host-path.json +27 -0
  96. package/fixtures/json-schema/personal-environment-request/invalid/task-noncanonical.json +27 -0
  97. package/fixtures/json-schema/personal-environment-request/invalid/task-null.json +27 -0
  98. package/fixtures/json-schema/personal-environment-request/invalid/task-on-inspection.json +22 -0
  99. package/fixtures/json-schema/personal-environment-request/invalid/unbounded-quota.json +21 -0
  100. package/fixtures/json-schema/personal-environment-request/valid/acquire.json +21 -0
  101. package/fixtures/json-schema/personal-environment-request/valid/delete-data.json +21 -0
  102. package/fixtures/json-schema/personal-environment-request/valid/execute.json +26 -0
  103. package/fixtures/json-schema/personal-environment-request/valid/export-data.json +21 -0
  104. package/fixtures/json-schema/personal-environment-request/valid/inspect.json +21 -0
  105. package/fixtures/json-schema/personal-environment-request/valid/provision.json +22 -0
  106. package/fixtures/json-schema/personal-environment-request/valid/release.json +21 -0
  107. package/fixtures/json-schema/personal-environment-request/valid/task-workspace.json +27 -0
  108. package/fixtures/json-schema/personal-environment-result/invalid/active-without-observation.json +7 -0
  109. package/fixtures/json-schema/personal-environment-result/invalid/deleted-output.json +8 -0
  110. package/fixtures/json-schema/personal-environment-result/invalid/deleted-snapshot.json +8 -0
  111. package/fixtures/json-schema/personal-environment-result/invalid/deleted-taskId.json +8 -0
  112. package/fixtures/json-schema/personal-environment-result/invalid/private-handle.json +8 -0
  113. package/fixtures/json-schema/personal-environment-result/invalid/stopped-fake-observation.json +20 -0
  114. package/fixtures/json-schema/personal-environment-result/invalid/task-empty.json +22 -0
  115. package/fixtures/json-schema/personal-environment-result/invalid/task-host-path.json +22 -0
  116. package/fixtures/json-schema/personal-environment-result/invalid/task-null.json +22 -0
  117. package/fixtures/json-schema/personal-environment-result/invalid/task-on-stopped.json +8 -0
  118. package/fixtures/json-schema/personal-environment-result/invalid/task-without-command-output.json +21 -0
  119. package/fixtures/json-schema/personal-environment-result/valid/active.json +21 -0
  120. package/fixtures/json-schema/personal-environment-result/valid/deleted.json +7 -0
  121. package/fixtures/json-schema/personal-environment-result/valid/expired.json +7 -0
  122. package/fixtures/json-schema/personal-environment-result/valid/missing.json +7 -0
  123. package/fixtures/json-schema/personal-environment-result/valid/released.json +7 -0
  124. package/fixtures/json-schema/personal-environment-result/valid/task-workspace.json +22 -0
  125. package/fixtures/json-schema/personal-guest-binding/invalid/host-path.json +17 -0
  126. package/fixtures/json-schema/personal-guest-binding/invalid/invalid-policy.json +17 -0
  127. package/fixtures/json-schema/personal-guest-binding/invalid/invalid-serial.json +17 -0
  128. package/fixtures/json-schema/personal-guest-binding/invalid/legacy-version.json +17 -0
  129. package/fixtures/json-schema/personal-guest-binding/invalid/missing-generation.json +17 -0
  130. package/fixtures/json-schema/personal-guest-binding/invalid/missing-identity.json +16 -0
  131. package/fixtures/json-schema/personal-guest-binding/invalid/missing-provider-identity.json +16 -0
  132. package/fixtures/json-schema/personal-guest-binding/invalid/raw-provider-identity.json +17 -0
  133. package/fixtures/json-schema/personal-guest-binding/valid/minimal.json +17 -0
  134. package/fixtures/json-schema/personal-guest-data-plan/invalid/quota.json +1 -0
  135. package/fixtures/json-schema/personal-guest-data-plan/valid/basic.json +1 -0
  136. package/fixtures/json-schema/personal-guest-enrollment/invalid/capabilities.json +7 -0
  137. package/fixtures/json-schema/personal-guest-enrollment/invalid/legacy-version.json +4 -0
  138. package/fixtures/json-schema/personal-guest-enrollment/invalid/missing-identity.json +3 -0
  139. package/fixtures/json-schema/personal-guest-enrollment/invalid/ownerId.json +5 -0
  140. package/fixtures/json-schema/personal-guest-enrollment/invalid/token.json +5 -0
  141. package/fixtures/json-schema/personal-guest-enrollment/valid/minimal.json +4 -0
  142. package/fixtures/json-schema/personal-guest-heartbeat/invalid/argv.json +11 -0
  143. package/fixtures/json-schema/personal-guest-heartbeat/invalid/legacy-version.json +8 -0
  144. package/fixtures/json-schema/personal-guest-heartbeat/invalid/missing-identity.json +7 -0
  145. package/fixtures/json-schema/personal-guest-heartbeat/invalid/owner.json +9 -0
  146. package/fixtures/json-schema/personal-guest-heartbeat/invalid/self-ready.json +9 -0
  147. package/fixtures/json-schema/personal-guest-heartbeat/invalid/zero-sequence.json +8 -0
  148. package/fixtures/json-schema/personal-guest-heartbeat/valid/minimal.json +8 -0
  149. package/fixtures/json-schema/personal-guest-provisioning/invalid/network.json +1 -0
  150. package/fixtures/json-schema/personal-guest-provisioning/valid/basic.json +1 -0
  151. package/fixtures/json-schema/personal-guest-renewal/invalid/unknown.json +1 -0
  152. package/fixtures/json-schema/personal-guest-renewal/valid/basic.json +1 -0
  153. package/fixtures/json-schema/personal-guest-runtime/invalid/minimal.json +45 -0
  154. package/fixtures/json-schema/personal-guest-runtime/valid/minimal.json +45 -0
  155. package/fixtures/json-schema/personal-guest-runtime-result/invalid/minimal.json +28 -0
  156. package/fixtures/json-schema/personal-guest-runtime-result/valid/minimal.json +27 -0
  157. package/fixtures/json-schema/personal-guest-tools/invalid/minimal.json +31 -0
  158. package/fixtures/json-schema/personal-guest-tools/valid/minimal.json +30 -0
  159. package/fixtures/json-schema/source-import-policy/invalid/case-variant-scope.json +4 -0
  160. package/fixtures/json-schema/source-import-policy/invalid/case-variant-version.json +4 -0
  161. package/fixtures/json-schema/source-import-policy/invalid/duplicate-grant.json +4 -0
  162. package/fixtures/json-schema/source-import-policy/invalid/empty-id.json +4 -0
  163. package/fixtures/json-schema/source-import-policy/invalid/future-version.json +4 -0
  164. package/fixtures/json-schema/source-import-policy/invalid/unknown-field.json +4 -0
  165. package/fixtures/json-schema/source-import-policy/valid/deny-all.json +4 -0
  166. package/fixtures/json-schema/source-import-policy/valid/shared.json +4 -0
  167. package/fixtures/json-schema/token-claims/invalid/authz-negative.json +23 -0
  168. package/fixtures/json-schema/token-claims/invalid/authz-string.json +23 -0
  169. package/fixtures/json-schema/token-claims/invalid/authz-zero.json +23 -0
  170. package/fixtures/json-schema/token-claims/valid/versioned-session.json +23 -0
  171. package/fixtures/openapi/AgentRunEventListEnvelope/invalid/basic.json +8 -0
  172. package/fixtures/openapi/AgentRunEventListEnvelope/valid/basic.json +8 -0
  173. package/fixtures/openapi/AgentRunEventListEnvelope/valid/native.json +1 -0
  174. package/fixtures/openapi/AgentRunResumeRequest/invalid/basic.json +3 -0
  175. package/fixtures/openapi/AgentRunResumeRequest/valid/basic.json +3 -0
  176. package/fixtures/openapi/AgentSSHCommandRequest/invalid/task51.json +24 -0
  177. package/fixtures/openapi/AgentSSHCommandRequest/valid/task51.json +23 -0
  178. package/fixtures/openapi/AgentSSHCommandResult/invalid/task51.json +8 -0
  179. package/fixtures/openapi/AgentSSHCommandResult/valid/task51.json +7 -0
  180. package/fixtures/openapi/AgentSSHSessionRequest/invalid/task51.json +20 -0
  181. package/fixtures/openapi/AgentSSHSessionRequest/valid/task51.json +19 -0
  182. package/fixtures/openapi/CapabilityTaskInput/invalid/duplicate-scope.json +36 -0
  183. package/fixtures/openapi/CapabilityTaskInput/valid/scoped.json +32 -0
  184. package/fixtures/openapi/DockerQuickCreateHostInput/invalid/guest-access.json +7 -0
  185. package/fixtures/openapi/DockerQuickCreateHostInput/valid/guest-access.json +9 -0
  186. package/fixtures/openapi/KnowledgeSourceDocument/invalid/tombstone-with-content.json +1 -0
  187. package/fixtures/openapi/KnowledgeSourceDocument/valid/tombstone.json +1 -0
  188. package/fixtures/openapi/KubernetesAgentActionCheck/invalid/unproven-state.json +6 -0
  189. package/fixtures/openapi/KubernetesAgentActionCheck/valid/configured-denied.json +9 -0
  190. package/fixtures/openapi/KubernetesAgentActionProfile/invalid/wildcard.json +1 -0
  191. package/fixtures/openapi/KubernetesAgentActionProfile/valid/workbench.json +1 -0
  192. package/fixtures/openapi/KubernetesClusterRegistrationRequest/invalid/action-profile.json +3 -0
  193. package/fixtures/openapi/KubernetesClusterRegistrationRequest/valid/action-profile.json +5 -0
  194. package/fixtures/openapi/KubernetesNodeListEnvelope/invalid/condition-status-boolean.json +17 -0
  195. package/fixtures/openapi/KubernetesNodeListEnvelope/invalid/taint-effect-missing.json +16 -0
  196. package/fixtures/openapi/KubernetesNodeListEnvelope/valid/legacy-fields-absent.json +11 -0
  197. package/fixtures/openapi/KubernetesNodeListEnvelope/valid/no-taints.json +13 -0
  198. package/fixtures/openapi/KubernetesNodeListEnvelope/valid/ready-cordoned-tainted.json +28 -0
  199. package/fixtures/openapi/KubernetesNodeListEnvelope/valid/unknown-fields-null.json +13 -0
  200. package/fixtures/openapi/KubernetesResourceUpdatePlanRequest/invalid/missing-required.json +1 -0
  201. package/fixtures/openapi/KubernetesResourceYaml/invalid/missing-required.json +1 -0
  202. package/fixtures/openapi/KubernetesTopologyCoverage/invalid/empty-as-success.json +5 -0
  203. package/fixtures/openapi/KubernetesTopologyCoverage/valid/not-installed.json +6 -0
  204. package/fixtures/openapi/KubernetesTopologyGraphEdge/invalid/negative-weight.json +8 -0
  205. package/fixtures/openapi/KubernetesTopologyGraphEdge/valid/zero-weight.json +20 -0
  206. package/fixtures/openapi/KubernetesTopologyGraphNode/invalid/fake-flow-kind.json +42 -0
  207. package/fixtures/openapi/KubernetesTopologyGraphNode/valid/rule.json +42 -0
  208. package/fixtures/openapi/KubernetesTopologySnapshot/invalid/raw-source-field.json +33 -0
  209. package/fixtures/openapi/KubernetesTopologySnapshot/valid/projected-source.json +32 -0
  210. package/fixtures/openapi/KubernetesTopologySnapshotRequest/invalid/arbitrary-gvr.json +8 -0
  211. package/fixtures/openapi/KubernetesTopologySnapshotRequest/valid/bounded-sources.json +11 -0
  212. package/fixtures/openapi/KubernetesTopologySourceQuery/invalid/cluster-namespace.json +4 -0
  213. package/fixtures/openapi/KubernetesTopologySourceQuery/valid/all-namespaces.json +4 -0
  214. package/fixtures/openapi/ObservabilityDataSource/invalid/missing-required.json +1 -0
  215. package/fixtures/openapi/PersonalAgentAccess/invalid/invalid.json +1 -0
  216. package/fixtures/openapi/PersonalAgentAccess/valid/valid.json +1 -0
  217. package/fixtures/openapi/PersonalAgentAccessDecision/invalid/invalid.json +1 -0
  218. package/fixtures/openapi/PersonalAgentAccessDecision/valid/valid.json +1 -0
  219. package/fixtures/openapi/PersonalAssistantArtifactListEnvelope/invalid/owner.json +8 -0
  220. package/fixtures/openapi/PersonalAssistantArtifactListEnvelope/valid/side-chat.json +9 -0
  221. package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/motion.json +1 -0
  222. package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/owner.json +1 -0
  223. package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/remote.json +1 -0
  224. package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/svg.json +1 -0
  225. package/fixtures/openapi/PersonalAssistantAvatarRequest/valid/raster.json +1 -0
  226. package/fixtures/openapi/PersonalAssistantAvatarRequest/valid/reset.json +1 -0
  227. package/fixtures/openapi/PersonalAssistantUpdateRequest/invalid/empty.json +1 -0
  228. package/fixtures/openapi/PersonalAssistantUpdateRequest/invalid/owner.json +1 -0
  229. package/fixtures/openapi/PersonalAssistantUpdateRequest/valid/name.json +1 -0
  230. package/fixtures/openapi/PersonalDockerEnvironmentPolicy/invalid/host-url.json +12 -0
  231. package/fixtures/openapi/PersonalDockerEnvironmentPolicy/invalid/lifetime.json +11 -0
  232. package/fixtures/openapi/PersonalDockerEnvironmentPolicy/invalid/unknown-agent.json +11 -0
  233. package/fixtures/openapi/PersonalDockerEnvironmentPolicy/valid/basic.json +11 -0
  234. package/fixtures/openapi/PersonalEnvironment/invalid/invented-state.json +6 -0
  235. package/fixtures/openapi/PersonalEnvironment/invalid/missing-state.json +5 -0
  236. package/fixtures/openapi/PersonalEnvironment/invalid/negative-generation.json +7 -0
  237. package/fixtures/openapi/PersonalEnvironment/invalid/network.json +23 -0
  238. package/fixtures/openapi/PersonalEnvironment/invalid/private-node.json +24 -0
  239. package/fixtures/openapi/PersonalEnvironment/invalid/unsupported-backend.json +7 -0
  240. package/fixtures/openapi/PersonalEnvironment/valid/deleted.json +23 -0
  241. package/fixtures/openapi/PersonalEnvironment/valid/deleting.json +23 -0
  242. package/fixtures/openapi/PersonalEnvironment/valid/deletion_unknown.json +23 -0
  243. package/fixtures/openapi/PersonalEnvironment/valid/frozen-binding.json +13 -0
  244. package/fixtures/openapi/PersonalEnvironment/valid/ready.json +23 -0
  245. package/fixtures/openapi/PersonalEnvironment/valid/unknown.json +23 -0
  246. package/fixtures/openapi/PersonalEnvironment/valid/unprovisioned.json +6 -0
  247. package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/command.json +3 -0
  248. package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/node.json +4 -0
  249. package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/owner.json +4 -0
  250. package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/quota.json +10 -0
  251. package/fixtures/openapi/PersonalEnvironmentActionRequest/valid/reconcile.json +3 -0
  252. package/fixtures/openapi/PersonalEnvironmentActionRequest/valid/sleep.json +3 -0
  253. package/fixtures/openapi/PersonalEnvironmentActionRequest/valid/wake.json +4 -0
  254. package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/empty-name.json +5 -0
  255. package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/long-name.json +5 -0
  256. package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/missing-name.json +4 -0
  257. package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/owner.json +6 -0
  258. package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/stale-version.json +5 -0
  259. package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/valid/confirmed.json +5 -0
  260. package/fixtures/openapi/PersonalEnvironmentDataExportRequest/invalid/assistantId.json +4 -0
  261. package/fixtures/openapi/PersonalEnvironmentDataExportRequest/invalid/environmentVersion.json +4 -0
  262. package/fixtures/openapi/PersonalEnvironmentDataExportRequest/invalid/ownerId.json +5 -0
  263. package/fixtures/openapi/PersonalEnvironmentDataExportRequest/valid/current.json +4 -0
  264. package/fixtures/openapi/PersonalEnvironmentEnvelope/invalid/missing-data.json +1 -0
  265. package/fixtures/openapi/PersonalEnvironmentEnvelope/valid/state.json +8 -0
  266. package/fixtures/openapi/PersonalEnvironmentQuota/invalid/cpu.json +7 -0
  267. package/fixtures/openapi/PersonalEnvironmentQuota/invalid/disk.json +7 -0
  268. package/fixtures/openapi/PersonalEnvironmentQuota/invalid/network.json +7 -0
  269. package/fixtures/openapi/PersonalEnvironmentQuota/invalid/processes.json +7 -0
  270. package/fixtures/openapi/PersonalEnvironmentQuota/valid/basic.json +7 -0
  271. package/fixtures/openapi/PersonalEnvironmentTemplate/invalid/mode.json +13 -0
  272. package/fixtures/openapi/PersonalEnvironmentTemplate/invalid/network.json +13 -0
  273. package/fixtures/openapi/PersonalEnvironmentTemplate/invalid/node.json +14 -0
  274. package/fixtures/openapi/PersonalEnvironmentTemplate/valid/template.json +13 -0
  275. package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/invalid/missing.json +1 -0
  276. package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/invalid/unbounded.json +1317 -0
  277. package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/valid/choices.json +17 -0
  278. package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/valid/empty.json +3 -0
  279. package/fixtures/openapi/PersonalEnvironmentUsage/invalid/negative.json +6 -0
  280. package/fixtures/openapi/PersonalEnvironmentUsage/valid/usage.json +6 -0
  281. package/fixtures/openapi/PersonalFeedFeedback/invalid/owner.json +4 -0
  282. package/fixtures/openapi/PersonalFeedFeedback/valid/liked.json +3 -0
  283. package/fixtures/openapi/PersonalFeedItem/invalid/no-source.json +9 -0
  284. package/fixtures/openapi/PersonalFeedItem/valid/post.json +15 -0
  285. package/fixtures/openapi/PersonalFeedSettings/invalid/owner.json +6 -0
  286. package/fixtures/openapi/PersonalFeedSettings/valid/default.json +5 -0
  287. package/fixtures/openapi/PersonalGuestPreparationInput/invalid/foreign-owner.json +5 -0
  288. package/fixtures/openapi/PersonalGuestPreparationInput/invalid/unsafe-counter.json +4 -0
  289. package/fixtures/openapi/PersonalGuestPreparationInput/valid/ed25519-csr.json +4 -0
  290. package/fixtures/openapi/PersonalGuestRuntimeEnvelope/invalid/minimal.json +10 -0
  291. package/fixtures/openapi/PersonalGuestRuntimeEnvelope/valid/minimal.json +9 -0
  292. package/fixtures/openapi/PersonalGuestRuntimeInput/invalid/minimal.json +6 -0
  293. package/fixtures/openapi/PersonalGuestRuntimeInput/valid/minimal.json +8 -0
  294. package/fixtures/openapi/PersonalGuestToolsInput/invalid/minimal.json +5 -0
  295. package/fixtures/openapi/PersonalGuestToolsInput/valid/minimal.json +4 -0
  296. package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/device.json +15 -0
  297. package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/fractional-size.json +15 -0
  298. package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/network.json +15 -0
  299. package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/owner.json +15 -0
  300. package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/provider.json +15 -0
  301. package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/unknown.json +16 -0
  302. package/fixtures/openapi/PersonalVMEnvironmentPolicy/valid/pve.json +15 -0
  303. package/fixtures/openapi/PersonalWorkspaceRuntime/invalid/shared.json +3 -0
  304. package/fixtures/openapi/PersonalWorkspaceRuntime/valid/shared.json +4 -0
  305. package/fixtures/openapi/PersonalWorkspaceRuntimeEnvelope/invalid/shared.json +5 -0
  306. package/fixtures/openapi/PersonalWorkspaceRuntimeEnvelope/valid/shared.json +6 -0
  307. package/fixtures/openapi/ResourceMonitoringPanel/invalid/unknown-quality.json +7 -0
  308. package/fixtures/openapi/ResourceMonitoringPanel/valid/not-collected.json +7 -0
  309. package/fixtures/openapi/ResourceMonitoringPoint/invalid/string-zero.json +4 -0
  310. package/fixtures/openapi/ResourceMonitoringPoint/valid/missing.json +4 -0
  311. package/fixtures/openapi/ResourceMonitoringPoint/valid/zero.json +4 -0
  312. package/fixtures/openapi/ResourceMonitoringView/invalid/raw-query.json +12 -0
  313. package/fixtures/openapi/ResourceMonitoringView/valid/unconfigured.json +12 -0
  314. package/fixtures/openapi/SecretGenerateSSHKeyRequest/invalid/task51.json +6 -0
  315. package/fixtures/openapi/SecretGenerateSSHKeyRequest/valid/task51.json +12 -0
  316. package/fixtures/openapi/SecretReferenceUsage/invalid/version.json +6 -0
  317. package/fixtures/openapi/SecretReferenceUsage/valid/version.json +8 -0
  318. package/fixtures/openapi/VMSSHCredentialRedemptionInput/invalid/task51.json +7 -0
  319. package/fixtures/openapi/VMSSHCredentialRedemptionInput/valid/task51.json +6 -0
  320. package/fixtures/openapi/VirtualMachineAccessBindingInput/invalid/task51.json +10 -0
  321. package/fixtures/openapi/VirtualMachineAccessBindingInput/valid/task51.json +10 -0
  322. package/fixtures/openapi/VirtualMachineActionInput/invalid/capacity-not-boolean.json +1 -0
  323. package/fixtures/openapi/VirtualMachineActionInput/valid/new-data-with-admission.json +1 -0
  324. package/fixtures/openapi/VirtualMachineCreateInput/valid/cloud-image.json +12 -0
  325. package/fixtures/openapi/VirtualMachineDiskChange/invalid/serial-config-injection.json +1 -0
  326. package/fixtures/openapi/VirtualMachineDiskChange/invalid/serial-existing-disk.json +1 -0
  327. package/fixtures/openapi/VirtualMachineDiskChange/invalid/serial-too-long.json +1 -0
  328. package/fixtures/openapi/VirtualMachineDiskChange/valid/personal-data.json +1 -0
  329. package/fixtures/openapi/VirtualMachineGuestAccessInput/invalid/task51.json +4 -0
  330. package/fixtures/openapi/VirtualMachineGuestAccessInput/valid/task51.json +6 -0
  331. package/fixtures/openapi/VirtualMachineSSHCommand/invalid/task51.json +9 -0
  332. package/fixtures/openapi/VirtualMachineSSHCommand/valid/task51.json +8 -0
  333. package/fixtures/openapi/VirtualMachineSSHCommandInput/invalid/task51.json +5 -0
  334. package/fixtures/openapi/VirtualMachineSSHCommandInput/valid/task51.json +5 -0
  335. package/fixtures/openapi/VirtualMachineSSHFrame/invalid/encoding.json +5 -0
  336. package/fixtures/openapi/VirtualMachineSSHFrame/invalid/task51.json +4 -0
  337. package/fixtures/openapi/VirtualMachineSSHFrame/valid/binary.json +5 -0
  338. package/fixtures/openapi/VirtualMachineSSHFrame/valid/task51.json +5 -0
  339. package/fixtures/openapi/VirtualMachineSSHSessionInput/invalid/task51.json +4 -0
  340. package/fixtures/openapi/VirtualMachineSSHSessionInput/valid/task51.json +5 -0
  341. package/fixtures/openapi/VirtualizationCapacityPolicyInput/invalid/task51.json +12 -0
  342. package/fixtures/openapi/VirtualizationCapacityPolicyInput/valid/task51.json +13 -0
  343. package/fixtures/openapi/VirtualizationImageInput/invalid/cloud-image-config-type.json +6 -0
  344. package/fixtures/openapi/VirtualizationImageInput/valid/cloud-image.json +11 -0
  345. package/fixtures/openapi/WorkbenchAssistantTask/invalid/kind.json +1 -0
  346. package/fixtures/openapi/WorkbenchAssistantTask/invalid/owner.json +1 -0
  347. package/fixtures/openapi/WorkbenchAssistantTask/valid/generate.json +1 -0
  348. package/fixtures/openapi/WorkbenchAssistantTask/valid/undo.json +1 -0
  349. package/fixtures/openapi/WorkbenchContextSelection/invalid/remote-image.json +1 -0
  350. package/fixtures/openapi/WorkbenchContextSelection/invalid/too-many-images.json +1 -0
  351. package/fixtures/openapi/WorkbenchContextSelection/valid/chat-image.json +9 -0
  352. package/fixtures/openapi/WorkbenchContextUsage/invalid/fractional-capacity.json +1 -0
  353. package/fixtures/openapi/WorkbenchContextUsage/invalid/negative.json +1 -0
  354. package/fixtures/openapi/WorkbenchContextUsage/valid/reported.json +1 -0
  355. package/fixtures/openapi/WorkbenchContextUsage/valid/unknown.json +1 -0
  356. package/fixtures/openapi/WorkbenchMainSessionRequest/invalid/owner.json +1 -0
  357. package/fixtures/openapi/WorkbenchMainSessionRequest/invalid/provider.json +1 -0
  358. package/fixtures/openapi/WorkbenchMainSessionRequest/valid/empty.json +1 -0
  359. package/fixtures/openapi/WorkbenchMainSessionRequest/valid/provider.json +1 -0
  360. package/fixtures/openapi/WorkbenchMessageSearchPage/invalid/role.json +12 -0
  361. package/fixtures/openapi/WorkbenchMessageSearchPage/valid/page.json +12 -0
  362. package/fixtures/openapi/WorkbenchMessageWindow/invalid/missing.json +1 -0
  363. package/fixtures/openapi/WorkbenchMessageWindow/valid/empty.json +3 -0
  364. package/fixtures/openapi/WorkbenchModelOption/invalid/zero-capacity.json +1 -0
  365. package/fixtures/openapi/WorkbenchModelOption/valid/capacity.json +1 -0
  366. package/fixtures/openapi/WorkbenchModelOption/valid/unknown.json +1 -0
  367. package/fixtures/openapi/WorkbenchProfessionalCapabilityInput/invalid/basic.json +7 -0
  368. package/fixtures/openapi/WorkbenchProfessionalCapabilityInput/valid/basic.json +11 -0
  369. package/fixtures/openapi/WorkbenchProfessionalCapabilityInput/valid/selected-profile.json +23 -0
  370. package/fixtures/openapi/WorkbenchSendMessageStreamRequest/invalid/missing-required.json +1 -0
  371. package/fixtures/openapi/WorkbenchSendMessageStreamRequest/valid/mixed-professional-task.json +22 -0
  372. package/fixtures/openapi/WorkbenchTaskIntent/invalid/basic.json +5 -0
  373. package/fixtures/openapi/WorkbenchTaskIntent/invalid/oversized-capability-source.json +3 -0
  374. package/fixtures/openapi/WorkbenchTaskIntent/valid/basic.json +9 -0
  375. package/fixtures/openapi/WorkbenchTaskIntent/valid/independent-sources.json +17 -0
  376. package/gen/go/sohaapi/client.go +1 -1
  377. package/gen/go/sohaapi/kubernetes_monitoring_test.go +67 -0
  378. package/gen/go/sohaapi/personal_environment_test.go +25 -0
  379. package/gen/go/sohaapi/types.go +3460 -433
  380. package/gen/go/sohaapi/vm_disk_test.go +21 -0
  381. package/gen/ts/sohaapi/index.ts +5454 -1397
  382. package/go.mod +61 -49
  383. package/go.sum +202 -176
  384. package/knowledge/connector-definition.schema.json +6 -1
  385. package/knowledge/source-import-policy.schema.json +32 -0
  386. package/memory/memory-record.schema.json +1 -1
  387. package/openapi/soha-api.json +24199 -16810
  388. package/openapi/soha-api.yaml +2537 -14
  389. package/openapi/spec_generated.go +3 -3
  390. package/openapi/spec_test.go +34 -0
  391. package/package.json +19 -3
  392. package/resource/agent_access.go +12 -0
  393. package/resource/agent_profiles.go +62 -0
  394. package/resource/agent_profiles_test.go +36 -0
  395. package/resource/kubernetes_kinds.go +73 -0
  396. package/resource/kubernetes_kinds_test.go +38 -0
  397. package/resource/models.go +23 -14
  398. package/resource/network_topology.go +166 -0
  399. package/resource/network_topology_projection.go +208 -0
  400. package/resource/network_topology_projection_test.go +53 -0
  401. package/resource/network_topology_test.go +51 -0
  402. package/resource/network_topology_validation.go +29 -0
  403. package/resource/node_drain.go +34 -0
  404. package/resource/resource_monitoring.go +99 -0
  405. package/resource/runtime/network_topology.go +232 -0
  406. package/resource/runtime/network_topology_test.go +62 -0
  407. package/resource/runtime/node_drain.go +124 -0
  408. package/resource/runtime/node_drain_test.go +95 -0
  409. package/resource/runtime/resource_edit.go +128 -0
  410. package/resource/runtime/resource_edit_test.go +183 -0
  411. package/resource/runtime/resource_monitoring.go +243 -0
  412. package/resource/runtime/resource_monitoring_test.go +88 -0
  413. /package/fixtures/openapi/DeliveryExecutionHistoryPage/{invalid-kind.json → invalid/invalid-kind.json} +0 -0
  414. /package/fixtures/openapi/DeliveryExecutionHistoryPage/{valid-build.json → valid/valid-build.json} +0 -0
  415. /package/fixtures/openapi/DeliveryExecutionHistoryPage/{valid-empty.json → valid/valid-empty.json} +0 -0
package/COMPATIBILITY.md CHANGED
@@ -364,6 +364,14 @@ role migration and consumer conformance prove no active dependency.
364
364
 
365
365
  ## Consumer Adoption
366
366
 
367
+ Session access tokens may add the optional positive `authzVersion` claim. Core
368
+ binds versioned tokens to the current user authorization version; refreshing a
369
+ session cannot revive a token issued before a membership change. During migration,
370
+ tokens without the claim must resolve current roles, teams, projects and tags from
371
+ the authoritative identity store rather than trusting their embedded membership.
372
+ Refresh tokens and existing client login/refresh response fields are unchanged.
373
+ This does not replace session revocation, account-state or per-resource authorization.
374
+
367
375
  Connection tests and Compute provider health checks return HTTP 200 with
368
376
  `ConnectionCheckResultEnvelope` after each fresh probe. Consumers read `healthy`
369
377
  and the diagnostic fields directly; no task or task log is created. The Compute
@@ -435,3 +443,90 @@ only with an explicit compatibility reason and successful matrix evidence.
435
443
  Manual CI may select `consumer_mode=latest` for separate integration evidence.
436
444
  This does not rewrite the fixed manifest or replace fixed-combination acceptance.
437
445
  Record the actual contracts and consumer commits, not only the selected mode.
446
+
447
+ The matrix includes the independent App frontend. Its initial pin
448
+ `0c3c76c373246f7d2218b48f68b89bf3097f777b` was built from isolated committed source
449
+ against the packed Contracts 0.1.23 working tree to establish backward compatibility.
450
+ That commit predates the uncommitted Native client adaptation; current-worktree
451
+ checks are separate, and release of that adaptation requires a reviewed new App
452
+ pin and verification with the published SDK rather than the local package overlay.
453
+
454
+ ## External knowledge source import ceilings
455
+
456
+ `knowledge/source-import-policy.schema.json` defines optional trusted
457
+ `config.importPolicy` for external HTTP/Git/Object connectors. Core intersects
458
+ fetched document grants with this ceiling before persisting documents and chunks.
459
+ Omission defaults to the stable knowledge-base owner; an explicitly empty private
460
+ scope grants nobody. Public returned ACLs cannot exceed a finite ceiling. Finite
461
+ grants intersect within the same identity category, without inferring membership
462
+ across users, roles, teams or projects. Inline source behavior is unchanged.
463
+
464
+ Older external configurations that relied on returned public/shared ACLs must
465
+ be reviewed and given an explicit trusted policy before reingestion. Existing
466
+ indexed documents are not retroactively rewritten by this change; source-policy
467
+ editing, revocation of existing indexed data and a migration/backfill remain
468
+ separate acceptance work. Upgrade every Core replica before relying on the new
469
+ ceiling. No independent SDK release or deployment is established by a sibling
470
+ consumer matrix.
471
+
472
+ Connector credential references use the existing Gateway `secretRefs` channel
473
+ with alias `SOURCE`, instead of ordinary fetch input. Executable references use
474
+ `soha://secrets/<id>` with an optional `/versions/<n>`, matching the existing
475
+ secret service. Legacy `secret:` references remain valid stored configuration,
476
+ but fetching rejects them until an authorized source edit selects a canonical
477
+ reference; names and paths are not automatically mapped to a secret identity.
478
+ A runtime without a
479
+ versioned per-call credential delivery protocol must reject a nonempty resolved
480
+ secret context before sending an action. Static runtime credentials do not
481
+ substitute for the caller-selected source credential.
482
+
483
+ `connectors/connector-action.schema.json` adds credential-bearing action v1.
484
+ Only actions explicitly declaring `credentialProtocol=opensoha.dev/connector-action/v1`
485
+ and bounded `credentialAliases` may receive it. The caller sends the same action
486
+ in the path and envelope, invocation-local values with exact pinned references,
487
+ and a bounded expiry. The runtime authenticates Core, validates declarations,
488
+ rejects unknown/expired frames, signals cooperative cancellation and rejects late
489
+ responses on expiry or disconnect. This does not prove an external effect stopped. Core remains
490
+ the authority for identity, reference versions and scope; wire metadata does not
491
+ authorize a caller. Credentials require authenticated HTTPS or loopback transport,
492
+ and must not follow redirects, enter persistent retry queues, logs, events or results.
493
+ Unversioned requests without credentials remain compatible; old runtimes continue
494
+ to be rejected before credential-bearing actions are sent. New runtimes must not
495
+ silently substitute globally configured credentials. Connectors SDK and Core
496
+ receive dedicated HTTP boundary tests in addition to the existing consumer matrix.
497
+
498
+ The v1 runtime also bounds canonical UTF-8 JSON frames to 1 MiB, each value to
499
+ 64 KiB, and structured material to depth 16 and 64 distinct nonempty strings,
500
+ including keys and the opaque value. The declaration advertises support; calls
501
+ without credentials retain the legacy envelope. An action requiring credentials
502
+ must explicitly reject their absence. Known raw and structured string material
503
+ is masked in SDK results/errors and Core outputs; conservative masking may also
504
+ mask matching business keys. A trusted connector must honor cancellation and
505
+ never persist credentials; masking is not a universal encoded-exfiltration guard.
506
+
507
+
508
+ ## 0.1.24 adoption inputs
509
+
510
+ The 0.1.24 package publishes the personal-workspace and managed-VM contracts
511
+ already committed after the 0.1.23 tag. The release does not replace the bytes
512
+ of the previously published 0.1.23 package.
513
+
514
+ The fixed source-consumer matrix intentionally advances two revisions:
515
+
516
+ - Core: `e022021d9f8da8917c135671f92248ef19f2b5b4` to
517
+ `c29cc6294dd4b7cb69db1187d728c227475fdf7c`, which implements the newly
518
+ documented VM access, SSH and capacity routes. The earlier revision fails
519
+ its live-route conformance test against the new operations.
520
+ - Web: `816ec0fb82e6e804f0f66d47d3446a7b5baeabc1` to
521
+ `447cbe5358802ef40d86ac67b7b59c5afe9c846a`, which handles the additional
522
+ `vm` and `vm_create` secret-scope enum members. The earlier exhaustive
523
+ TypeScript record does not compile against those additive enum members.
524
+
525
+ The other four fixed revisions and all six checks remain in place. These are
526
+ reviewed adoption inputs, not a claim that the earlier source revisions pass
527
+ against the expanded SDK. The OpenAPI compatibility snapshot and all JSON
528
+ Schema and loose-boundary expectations remain unchanged; the latter two files
529
+ only synchronize their release-version metadata to satisfy their existing
530
+ guards. Candidate matrices use the packed/local contracts source. Consumers
531
+ must still pin the published version and validate the registry/proxy package
532
+ before claiming released-version acceptance.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Shared public contracts for OpenSoha.
4
4
 
5
5
  This repository is the source of truth for schemas consumed across Soha core,
6
- Soha CLI, Soha Agent, Soha Web, official skills, connectors, and Soha
6
+ Soha CLI, Soha Agent, Soha Web, Soha App, official skills, connectors, and Soha
7
7
  Cloud services. Product repositories should depend on generated SDKs, HTTP
8
8
  APIs, JSON Schemas, or released artifacts from this repository instead of
9
9
  copying business logic between repos.
@@ -23,6 +23,8 @@ presets/mcp-preset.schema.json MCP preset manifest
23
23
  governance/approval-request.schema.json Approval request and trace contract
24
24
  governance/audit-log.schema.json Audit log contract
25
25
  agent/agent-protocol.schema.json Runner and agent control-plane protocol
26
+ agent/personal-guest-*.schema.json Personal VM guest binding, enrollment and heartbeat
27
+ agent/guest Hand-maintained Go guest protocol validators
26
28
  runner/operation-lifecycle.schema.json Long-running operation lifecycle events
27
29
  mcp/gateway-manifest.schema.json AI Gateway / MCP capability manifest
28
30
  skills/skill-manifest.schema.json Official skill front matter contract
@@ -49,6 +51,15 @@ gen/ts/sohaapi TypeScript SDK types for stable Web contra
49
51
  - Public behavior changes should update this repository first, then update
50
52
  generated SDKs and consumers.
51
53
 
54
+ Personal VM guest messages are an independent protocol. Docker v1 and Network
55
+ Control credentials do not authorize it. Enrollment requires a guest-specific
56
+ mTLS identity and a short one-time challenge; Core must derive the frozen owner,
57
+ assistant, compute generation, data identity and policy. Heartbeats carry no task
58
+ execution or readiness grant. Certificate pinning, current authorization, atomic
59
+ challenge consumption and sequence persistence belong to the consuming service.
60
+ The contracts package alone does not implement guest enrollment or enable VM
61
+ personal environments.
62
+
52
63
  ## SDK Consumers
53
64
 
54
65
  Current SDK entry points:
@@ -107,7 +118,7 @@ calling code in the consumer until those APIs are promoted into the supported
107
118
  client surface. Redirect-oriented flows such as OIDC provider redirects should
108
119
  not use the JSON-only `doJSON` helper until a non-JSON client mode is added.
109
120
 
110
- The Go generator and generated DTO checks run with Go 1.26.6 in CI.
121
+ The Go generator and generated DTO checks run with Go 1.27.2 in CI.
111
122
 
112
123
  ## Validation
113
124
 
@@ -124,6 +135,10 @@ operation ID uniqueness, version synchronization, OpenAPI lint rules,
124
135
  breaking-change compatibility against the checked-in baseline, TypeScript
125
136
  type declarations, and Go compilation for the generated SDK package.
126
137
 
138
+ OpenAPI fixture directories are discovered automatically; registered required directories
139
+ must still exist. Put every JSON fixture in `valid/` or `invalid/`, with at least
140
+ one of each. The validation gate rejects misplaced or unrecognized entries.
141
+
127
142
  Useful focused checks:
128
143
 
129
144
  ```sh
@@ -151,7 +166,7 @@ failure.
151
166
 
152
167
  Network runtime schemas and network-access DTOs require `0.1.17` or later;
153
168
  they are absent from npm `0.1.16` and Go `v0.1.15`. For unpublished changes,
154
- use the local consumer matrix below: it packs this checkout for Web and
169
+ use the local consumer matrix below: it packs this checkout for Web/App and
155
170
  supplies an isolated Go workspace. After publishing, update consumer versions
156
171
  and lockfiles and verify them without the local override.
157
172
 
@@ -167,15 +182,18 @@ and skips any missing consumer. CI uses the strict form:
167
182
  ```sh
168
183
  npm run check:consumers -- --consumer soha --require-all
169
184
  npm run check:consumers -- --consumer soha-web --require-all
185
+ npm run check:consumers -- --consumer soha-app --require-all
170
186
  npm run check:consumers -- --consumer soha-cli --require-all
171
187
  npm run check:consumers -- --consumer soha-agent --require-all
172
188
  npm run check:consumers -- --consumer soha-skills --require-all
173
189
  ```
174
190
 
175
191
  Go consumers run in a temporary `go.work` that replaces the contracts module
176
- with this checkout. `soha-web` runs `npm ci`, installs a packed copy of this
177
- checkout without changing its dependency manifest or lockfile, and builds
178
- against that package.
192
+ with this checkout. `soha-web` and `soha-app/frontend` run `npm ci`, install a packed copy of this
193
+ checkout without changing their dependency manifests or lockfiles, and build
194
+ against that package. The App pin represents its recorded committed source;
195
+ local uncommitted Native adaptations need separate worktree evidence and a new
196
+ reviewed pin after they are committed.
179
197
 
180
198
  Use `--dry-run` to inspect the discovered commands without executing consumer
181
199
  builds.
@@ -0,0 +1,55 @@
1
+ # Personal environment Agent protocol
2
+
3
+ The source schemas are `agent/personal-environment-request.schema.json` and
4
+ `agent/personal-environment-result.schema.json`, reusing the existing lease and
5
+ snapshot schemas. This small Go package carries the same wire types without
6
+ exposing Docker container IDs, volume names, host paths, or provider errors.
7
+
8
+ The Agent accepts `POST /api/v1/runtime/personal-environments` from the trusted
9
+ Core connection. Its normal `{ "data": ... }` envelope contains `Result`.
10
+ Authentication is required even on loopback; each action also requires its
11
+ explicit `runtime.personal_environments.<action>` allowlist entry. This feature
12
+ is disabled by default. Existing Agents without this endpoint cannot execute it.
13
+
14
+ Core derives the owner from its authenticated user and persistent assistant
15
+ identity. It selects the registered execution node, quotas, scope hash, run ID
16
+ and original lease timestamps. These must not come from model-selected identity,
17
+ user-entered endpoints, or provider credentials. Each request is limited to
18
+ 512 KiB; dispatch/observation has a 30 second deadline, and cleanup has an
19
+ independent 30 second deadline. Slow cleanup can outlast the HTTP receipt window
20
+ and must be reconciled as an unknown outcome. Leases last at most 24 hours.
21
+ This Docker backend requires pinned images, cgroup v2 and already-enabled,
22
+ consistent Btrfs subvolume quotas. Unsupported enforcement fails acquisition.
23
+
24
+ - `acquire`: recover the same immutable original lease, or start its task sandbox.
25
+ `createData=true` is permitted only during initial provisioning before Core has
26
+ a ready receipt or allows any task execution. Later acquisition uses false:
27
+ missing volumes or data subvolumes are errors, never replacements with empty data.
28
+ - `inspect`: observe this lease, without creating a container. Expired containers
29
+ are stopped before an expired receipt is returned. Missing containers report missing.
30
+ - `execute`: bounded absolute argv inside this lease's sandbox. It cannot be
31
+ retried automatically: network loss, timeout or lost receipts mean an unknown
32
+ outcome. Core must persist dispatch state and require reconciliation rather
33
+ than replaying a write. The Agent fences concurrent commands and retains data
34
+ when cancellation or failure stops the task sandbox.
35
+ - `release`: stop only this original lease. Persistent data is retained. If its
36
+ container is absent, return missing rather than inventing a release receipt.
37
+ - `delete_data`: Core requires the current owner's exact assistant name/version,
38
+ sleeping data and no active task. The Agent takes the physical volume lock,
39
+ removes only that owner's data and retains a non-recreation tombstone. A
40
+ partial deletion is unknown; only a `deleted` receipt confirms it.
41
+ - `export_data`: use the dedicated `POST /runtime/personal-environments/export`
42
+ endpoint, with the same server-derived original lease and no argv/task/create
43
+ fields. Ordinary JSON `Result` is never a valid export response. The binary
44
+ stream has big-endian uint32 chunk lengths (maximum 32 KiB), then zero, a
45
+ uint32 JSON-receipt length (maximum 4 KiB), and the export receipt. The TAR
46
+ payload is bounded to 256 MiB. Receivers reject truncation, trailing bytes,
47
+ changed identity, size or SHA-256 before exposing any file. The producer sends
48
+ the final receipt only after its archive command and owned cleanup complete.
49
+
50
+ Active results include actual quota/cgroup observations. Inactive results omit
51
+ observations rather than manufacturing zero usage. `ValidateFor` checks receipt
52
+ identity, action completion, bounded command output, and observation identity.
53
+ Core must also reject stale receipts. Data export and deletion are separate
54
+ explicit owner operations; their allowlist entries remain opt-in. TAR preserves
55
+ link entries without following their targets and is never extracted by export.
@@ -0,0 +1,139 @@
1
+ package environment
2
+
3
+ import (
4
+ "bytes"
5
+ "crypto/sha256"
6
+ "encoding/binary"
7
+ "encoding/hex"
8
+ "encoding/json"
9
+ "errors"
10
+ "hash"
11
+ "io"
12
+ "time"
13
+ )
14
+
15
+ const ExportResultVersion = "opensoha.dev/personal-environment-export/v1"
16
+
17
+ // ponytail: bounded synchronous downloads; use the artifact store for archives
18
+ // above 256 MiB rather than silently truncating or buffering them in memory.
19
+ const ExportMaxBytes int64 = 256 << 20
20
+ const exportChunkBytes = 32 << 10
21
+
22
+ type ExportResult struct {
23
+ SchemaVersion string `json:"schemaVersion"`
24
+ LeaseID string `json:"leaseId"`
25
+ RunID string `json:"runId"`
26
+ OwnerID string `json:"ownerId"`
27
+ ScopeHash string `json:"scopeHash"`
28
+ SizeBytes int64 `json:"sizeBytes"`
29
+ SHA256 string `json:"sha256"`
30
+ ObservedAt time.Time `json:"observedAt"`
31
+ }
32
+
33
+ func (r ExportResult) ValidateFor(request Request) error {
34
+ if request.Validate() != nil || request.Action != "export_data" || r.SchemaVersion != ExportResultVersion || r.LeaseID != request.Lease.ID || r.RunID != request.Lease.RunID || r.OwnerID != request.Lease.OwnerID || r.ScopeHash != request.Lease.ScopeHash || r.SizeBytes < 1 || r.SizeBytes > ExportMaxBytes || !scopePattern.MatchString(r.SHA256) || r.ObservedAt.IsZero() {
35
+ return errors.New("invalid personal data export receipt")
36
+ }
37
+ return nil
38
+ }
39
+
40
+ // Each archive chunk has a four-byte big-endian length. Zero ends the archive;
41
+ // a length-prefixed JSON receipt follows only after Docker and cleanup succeed.
42
+ // EOF, a partial archive or a failed producer cannot become a confirmed export.
43
+ type ExportWriter struct {
44
+ Writer io.Writer
45
+ size int64
46
+ digest hash.Hash
47
+ }
48
+
49
+ func (w *ExportWriter) Write(data []byte) (int, error) {
50
+ if w.size+int64(len(data)) > ExportMaxBytes {
51
+ return 0, errors.New("personal data archive exceeds 256 MiB")
52
+ }
53
+ if w.digest == nil {
54
+ w.digest = sha256.New()
55
+ }
56
+ written := 0
57
+ for len(data) > 0 {
58
+ n := min(len(data), exportChunkBytes)
59
+ if err := binary.Write(w.Writer, binary.BigEndian, uint32(n)); err != nil {
60
+ return written, err
61
+ }
62
+ if count, err := w.Writer.Write(data[:n]); err != nil || count != n {
63
+ return written, errors.Join(err, io.ErrShortWrite)
64
+ }
65
+ _, _ = w.digest.Write(data[:n])
66
+ w.size += int64(n)
67
+ written += n
68
+ data = data[n:]
69
+ }
70
+ return written, nil
71
+ }
72
+
73
+ func (w *ExportWriter) Finish(request Request) (ExportResult, error) {
74
+ if w.digest == nil {
75
+ return ExportResult{}, errors.New("empty personal data archive")
76
+ }
77
+ l := request.Lease
78
+ r := ExportResult{SchemaVersion: ExportResultVersion, LeaseID: l.ID, RunID: l.RunID, OwnerID: l.OwnerID, ScopeHash: l.ScopeHash, SizeBytes: w.size, SHA256: "sha256:" + hex.EncodeToString(w.digest.Sum(nil)), ObservedAt: time.Now().UTC()}
79
+ if err := r.ValidateFor(request); err != nil {
80
+ return ExportResult{}, err
81
+ }
82
+ data, err := json.Marshal(r)
83
+ if err != nil {
84
+ return ExportResult{}, err
85
+ }
86
+ if err := binary.Write(w.Writer, binary.BigEndian, uint32(0)); err != nil {
87
+ return ExportResult{}, err
88
+ }
89
+ if err := binary.Write(w.Writer, binary.BigEndian, uint32(len(data))); err != nil {
90
+ return ExportResult{}, err
91
+ }
92
+ if n, err := w.Writer.Write(data); err != nil || n != len(data) {
93
+ return ExportResult{}, errors.Join(err, io.ErrShortWrite)
94
+ }
95
+ return r, nil
96
+ }
97
+
98
+ func ReadExport(reader io.Reader, target io.Writer, request Request) (ExportResult, error) {
99
+ var size int64
100
+ digest := sha256.New()
101
+ buffer := make([]byte, exportChunkBytes)
102
+ for {
103
+ var n uint32
104
+ if err := binary.Read(reader, binary.BigEndian, &n); err != nil {
105
+ return ExportResult{}, err
106
+ }
107
+ if n == 0 {
108
+ break
109
+ }
110
+ if n > exportChunkBytes || size+int64(n) > ExportMaxBytes {
111
+ return ExportResult{}, errors.New("personal data export exceeds its bound")
112
+ }
113
+ if _, err := io.ReadFull(reader, buffer[:n]); err != nil {
114
+ return ExportResult{}, err
115
+ }
116
+ if _, err := io.Copy(io.MultiWriter(target, digest), bytes.NewReader(buffer[:n])); err != nil {
117
+ return ExportResult{}, err
118
+ }
119
+ size += int64(n)
120
+ }
121
+ var receiptBytes uint32
122
+ if err := binary.Read(reader, binary.BigEndian, &receiptBytes); err != nil || receiptBytes == 0 || receiptBytes > 4096 {
123
+ return ExportResult{}, errors.New("personal data export has no bounded receipt")
124
+ }
125
+ data := make([]byte, receiptBytes)
126
+ if _, err := io.ReadFull(reader, data); err != nil {
127
+ return ExportResult{}, err
128
+ }
129
+ decoder := json.NewDecoder(bytes.NewReader(data))
130
+ decoder.DisallowUnknownFields()
131
+ var result ExportResult
132
+ if decoder.Decode(&result) != nil || decoder.Decode(new(any)) != io.EOF || result.ValidateFor(request) != nil || result.SizeBytes != size || result.SHA256 != "sha256:"+hex.EncodeToString(digest.Sum(nil)) {
133
+ return ExportResult{}, errors.New("personal data export integrity or identity mismatch")
134
+ }
135
+ if n, err := reader.Read(buffer[:1]); n != 0 || err != io.EOF {
136
+ return ExportResult{}, errors.New("personal data export contains trailing bytes")
137
+ }
138
+ return result, nil
139
+ }
@@ -0,0 +1,62 @@
1
+ package environment
2
+
3
+ import (
4
+ "bytes"
5
+ "encoding/binary"
6
+ "encoding/json"
7
+ "os"
8
+ "testing"
9
+ )
10
+
11
+ func TestPersonalDataStreamRejectsIncompleteOrChangedArchive(t *testing.T) {
12
+ fixture, err := os.ReadFile("../../fixtures/json-schema/personal-environment-request/valid/export-data.json")
13
+ if err != nil {
14
+ t.Fatal(err)
15
+ }
16
+ var request Request
17
+ if err := json.Unmarshal(fixture, &request); err != nil {
18
+ t.Fatal(err)
19
+ }
20
+ data := bytes.Repeat([]byte("archive fixture\x00"), 5000)
21
+ var stream bytes.Buffer
22
+ writer := ExportWriter{Writer: &stream}
23
+ if _, err := writer.Write(data); err != nil {
24
+ t.Fatal(err)
25
+ }
26
+ if _, err := writer.Finish(request); err != nil {
27
+ t.Fatal(err)
28
+ }
29
+ var target bytes.Buffer
30
+ if _, err := ReadExport(bytes.NewReader(stream.Bytes()), &target, request); err != nil || !bytes.Equal(target.Bytes(), data) {
31
+ t.Fatalf("complete binary stream changed: %v", err)
32
+ }
33
+ for _, cut := range []int{0, 4, 500, stream.Len() - 1} {
34
+ if _, err := ReadExport(bytes.NewReader(stream.Bytes()[:cut]), &bytes.Buffer{}, request); err == nil {
35
+ t.Fatal("truncated producer became a completed export")
36
+ }
37
+ }
38
+ changed := bytes.Clone(stream.Bytes())
39
+ changed[5] ^= 1
40
+ if _, err := ReadExport(bytes.NewReader(changed), &bytes.Buffer{}, request); err == nil {
41
+ t.Fatal("corrupt archive bypassed final SHA-256")
42
+ }
43
+ other := request
44
+ other.Lease.OwnerID = "another-owner"
45
+ if _, err := ReadExport(bytes.NewReader(stream.Bytes()), &bytes.Buffer{}, other); err == nil {
46
+ t.Fatal("archive borrowed another owner's receipt")
47
+ }
48
+ if _, err := ReadExport(bytes.NewReader(append(bytes.Clone(stream.Bytes()), 'x')), &bytes.Buffer{}, request); err == nil {
49
+ t.Fatal("trailing stream accepted")
50
+ }
51
+ var invalid bytes.Buffer
52
+ if err := binary.Write(&invalid, binary.BigEndian, uint32(exportChunkBytes+1)); err != nil {
53
+ t.Fatal(err)
54
+ }
55
+ if _, err := ReadExport(&invalid, &bytes.Buffer{}, request); err == nil {
56
+ t.Fatal("oversized frame accepted")
57
+ }
58
+ writer.size = ExportMaxBytes
59
+ if _, err := writer.Write([]byte("x")); err == nil {
60
+ t.Fatal("archive bound was silently truncated")
61
+ }
62
+ }
@@ -0,0 +1,62 @@
1
+ package environment
2
+
3
+ import (
4
+ "bytes"
5
+ "encoding/json"
6
+ "errors"
7
+ "io"
8
+ "time"
9
+ "unicode/utf8"
10
+ )
11
+
12
+ const PreflightRequestVersion = "opensoha.dev/personal-environment-preflight-request/v1"
13
+ const PreflightResultVersion = "opensoha.dev/personal-environment-preflight-result/v1"
14
+
15
+ // A preflight may create only its disposable quota probe, never personal data.
16
+ type PreflightRequest struct {
17
+ SchemaVersion string `json:"schemaVersion"`
18
+ ID string `json:"id"`
19
+ Quota Quota `json:"quota"`
20
+ }
21
+
22
+ type PreflightResult struct {
23
+ SchemaVersion string `json:"schemaVersion"`
24
+ ID string `json:"id"`
25
+ Quota Quota `json:"quota"`
26
+ Ready bool `json:"ready"`
27
+ CgroupVersion string `json:"cgroupVersion"`
28
+ DiskMechanism string `json:"diskMechanism"`
29
+ ObservedAt time.Time `json:"observedAt"`
30
+ }
31
+
32
+ func (r *PreflightRequest) UnmarshalJSON(data []byte) error {
33
+ if !utf8.Valid(data) {
34
+ return errors.New("preflight request must be UTF-8")
35
+ }
36
+ type wireRequest PreflightRequest
37
+ var decoded wireRequest
38
+ d := json.NewDecoder(bytes.NewReader(data))
39
+ d.DisallowUnknownFields()
40
+ if err := d.Decode(&decoded); err != nil {
41
+ return err
42
+ }
43
+ if d.Decode(&struct{}{}) != io.EOF {
44
+ return errors.New("invalid preflight request")
45
+ }
46
+ *r = PreflightRequest(decoded)
47
+ return r.Validate()
48
+ }
49
+
50
+ func (r PreflightRequest) Validate() error {
51
+ if r.SchemaVersion != PreflightRequestVersion || !canonicalUUIDPattern.MatchString(r.ID) {
52
+ return errors.New("invalid preflight identity")
53
+ }
54
+ return r.Quota.ValidatePersonalDocker()
55
+ }
56
+
57
+ func (r PreflightResult) ValidateFor(request PreflightRequest) error {
58
+ if r.SchemaVersion != PreflightResultVersion || r.ID != request.ID || r.Quota != request.Quota || !r.Ready || r.CgroupVersion != "2" || r.DiskMechanism != "btrfs-qgroup" || r.ObservedAt.IsZero() {
59
+ return errors.New("invalid personal environment preflight receipt")
60
+ }
61
+ return nil
62
+ }
@@ -0,0 +1,41 @@
1
+ package environment
2
+
3
+ import (
4
+ "encoding/json"
5
+ "testing"
6
+ "time"
7
+ )
8
+
9
+ func TestPreflightRejectsCallerSelectedResourcesAndMismatchedQuotaReceipt(t *testing.T) {
10
+ request := PreflightRequest{SchemaVersion: PreflightRequestVersion, ID: "00000000-0000-4000-8000-000000000048", Quota: Quota{DiskBytes: 32 << 20, MemoryBytes: 64 << 20, CPUUnits: 250, MaxProcesses: 16}}
11
+ payload, err := json.Marshal(request)
12
+ if err != nil {
13
+ t.Fatal(err)
14
+ }
15
+ var decoded PreflightRequest
16
+ if err := json.Unmarshal(payload, &decoded); err != nil {
17
+ t.Fatal(err)
18
+ }
19
+ for _, key := range []string{"ownerId", "nodeUrl", "command", "image"} {
20
+ var fields map[string]any
21
+ if err := json.Unmarshal(payload, &fields); err != nil {
22
+ t.Fatal(err)
23
+ }
24
+ fields[key] = "caller-selected"
25
+ invalid, err := json.Marshal(fields)
26
+ if err != nil {
27
+ t.Fatal(err)
28
+ }
29
+ if json.Unmarshal(invalid, &decoded) == nil {
30
+ t.Fatalf("accepted %s", key)
31
+ }
32
+ }
33
+ result := PreflightResult{SchemaVersion: PreflightResultVersion, ID: request.ID, Quota: request.Quota, Ready: true, CgroupVersion: "2", DiskMechanism: "btrfs-qgroup", ObservedAt: time.Now().UTC()}
34
+ if err := result.ValidateFor(request); err != nil {
35
+ t.Fatal(err)
36
+ }
37
+ result.Quota.DiskBytes++
38
+ if result.ValidateFor(request) == nil {
39
+ t.Fatal("different quota acknowledged")
40
+ }
41
+ }