@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.
- package/COMPATIBILITY.md +95 -0
- package/README.md +24 -6
- package/agent/environment/README.md +55 -0
- package/agent/environment/export.go +139 -0
- package/agent/environment/export_test.go +62 -0
- package/agent/environment/preflight.go +62 -0
- package/agent/environment/preflight_test.go +41 -0
- package/agent/environment/protocol.go +221 -0
- package/agent/environment/protocol_test.go +81 -0
- package/agent/environment-lease.schema.json +2 -2
- package/agent/environment-template.schema.json +1 -1
- package/agent/guest/browser_network.go +77 -0
- package/agent/guest/data.go +62 -0
- package/agent/guest/protocol.go +235 -0
- package/agent/guest/protocol_test.go +142 -0
- package/agent/guest/renewal.go +56 -0
- package/agent/guest/renewal_test.go +53 -0
- package/agent/guest/runtime.go +315 -0
- package/agent/guest/runtime_json.go +75 -0
- package/agent/guest/runtime_test.go +110 -0
- package/agent/personal-browser-network-request.schema.json +40 -0
- package/agent/personal-browser-network-response.schema.json +44 -0
- package/agent/personal-environment-export.schema.json +55 -0
- package/agent/personal-environment-preflight-request.schema.json +52 -0
- package/agent/personal-environment-preflight-result.schema.json +69 -0
- package/agent/personal-environment-request.schema.json +137 -0
- package/agent/personal-environment-result.schema.json +101 -0
- package/agent/personal-guest-binding.schema.json +92 -0
- package/agent/personal-guest-data-plan.schema.json +32 -0
- package/agent/personal-guest-enrollment.schema.json +21 -0
- package/agent/personal-guest-heartbeat.schema.json +44 -0
- package/agent/personal-guest-provisioning.schema.json +71 -0
- package/agent/personal-guest-renewal.schema.json +33 -0
- package/agent/personal-guest-runtime-result.schema.json +164 -0
- package/agent/personal-guest-runtime.schema.json +304 -0
- package/agent/personal-guest-tools.schema.json +75 -0
- package/auth/catalog_generated.go +2 -2
- package/auth/gateway_permissions_test.go +48 -0
- package/auth/permission-catalog.json +331 -1
- package/auth/token-claims.schema.json +5 -0
- package/compat/consumer-revisions.json +3 -2
- package/compat/json-schema-ecosystem-0.1.0.json +1 -1
- package/compat/openapi-loose-boundaries-0.1.0.json +1 -1
- package/connectors/connector-action.schema.json +138 -0
- package/fixtures/json-schema/connector-action/invalid/empty-values.json +11 -0
- package/fixtures/json-schema/connector-action/invalid/invalid-expiry.json +16 -0
- package/fixtures/json-schema/connector-action/invalid/lowercase-alias.json +16 -0
- package/fixtures/json-schema/connector-action/invalid/unknown-entry-field.json +17 -0
- package/fixtures/json-schema/connector-action/invalid/unknown-frame-field.json +17 -0
- package/fixtures/json-schema/connector-action/invalid/unknown-version.json +16 -0
- package/fixtures/json-schema/connector-action/invalid/unversioned-reference.json +16 -0
- package/fixtures/json-schema/connector-action/invalid/zero-version.json +16 -0
- package/fixtures/json-schema/connector-action/valid/pinned.json +16 -0
- package/fixtures/json-schema/connector-definition/invalid/credential-userinfo.json +8 -0
- package/fixtures/json-schema/connector-definition/invalid/reference-traversal.json +8 -0
- package/fixtures/json-schema/connector-definition/invalid/zero-version.json +8 -0
- package/fixtures/json-schema/connector-definition/valid/canonical.json +8 -0
- package/fixtures/json-schema/connector-definition/valid/pinned.json +8 -0
- package/fixtures/json-schema/personal-browser-network-request/invalid/bounded.json +4 -0
- package/fixtures/json-schema/personal-browser-network-request/valid/bounded.json +4 -0
- package/fixtures/json-schema/personal-browser-network-response/invalid/bounded.json +5 -0
- package/fixtures/json-schema/personal-browser-network-response/valid/bounded.json +5 -0
- package/fixtures/json-schema/personal-environment-export/invalid/extra.json +11 -0
- package/fixtures/json-schema/personal-environment-export/invalid/ownerId.json +10 -0
- package/fixtures/json-schema/personal-environment-export/invalid/sha256.json +10 -0
- package/fixtures/json-schema/personal-environment-export/invalid/sizeBytes.json +10 -0
- package/fixtures/json-schema/personal-environment-export/valid/complete.json +10 -0
- package/fixtures/json-schema/personal-environment-preflight-request/invalid/disk.json +11 -0
- package/fixtures/json-schema/personal-environment-preflight-request/invalid/network.json +11 -0
- package/fixtures/json-schema/personal-environment-preflight-request/invalid/node.json +12 -0
- package/fixtures/json-schema/personal-environment-preflight-request/invalid/owner.json +12 -0
- package/fixtures/json-schema/personal-environment-preflight-request/valid/bounded.json +11 -0
- package/fixtures/json-schema/personal-environment-preflight-result/invalid/disk.json +15 -0
- package/fixtures/json-schema/personal-environment-preflight-result/invalid/network.json +15 -0
- package/fixtures/json-schema/personal-environment-preflight-result/invalid/no-hard-quota.json +15 -0
- package/fixtures/json-schema/personal-environment-preflight-result/invalid/node.json +16 -0
- package/fixtures/json-schema/personal-environment-preflight-result/invalid/not-ready.json +15 -0
- package/fixtures/json-schema/personal-environment-preflight-result/invalid/owner.json +16 -0
- package/fixtures/json-schema/personal-environment-preflight-result/valid/bounded.json +15 -0
- package/fixtures/json-schema/personal-environment-request/invalid/delete-data-argv.json +24 -0
- package/fixtures/json-schema/personal-environment-request/invalid/delete-data-createData.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/delete-data-taskId.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/export-argv.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/export-createData.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/export-taskId.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/extra-command.json +24 -0
- package/fixtures/json-schema/personal-environment-request/invalid/host-workspace.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/image-injection.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/network-egress.json +21 -0
- package/fixtures/json-schema/personal-environment-request/invalid/no-command.json +21 -0
- package/fixtures/json-schema/personal-environment-request/invalid/recreate-on-release.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/relative-command.json +24 -0
- package/fixtures/json-schema/personal-environment-request/invalid/released-identity.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/task-empty.json +27 -0
- package/fixtures/json-schema/personal-environment-request/invalid/task-host-path.json +27 -0
- package/fixtures/json-schema/personal-environment-request/invalid/task-noncanonical.json +27 -0
- package/fixtures/json-schema/personal-environment-request/invalid/task-null.json +27 -0
- package/fixtures/json-schema/personal-environment-request/invalid/task-on-inspection.json +22 -0
- package/fixtures/json-schema/personal-environment-request/invalid/unbounded-quota.json +21 -0
- package/fixtures/json-schema/personal-environment-request/valid/acquire.json +21 -0
- package/fixtures/json-schema/personal-environment-request/valid/delete-data.json +21 -0
- package/fixtures/json-schema/personal-environment-request/valid/execute.json +26 -0
- package/fixtures/json-schema/personal-environment-request/valid/export-data.json +21 -0
- package/fixtures/json-schema/personal-environment-request/valid/inspect.json +21 -0
- package/fixtures/json-schema/personal-environment-request/valid/provision.json +22 -0
- package/fixtures/json-schema/personal-environment-request/valid/release.json +21 -0
- package/fixtures/json-schema/personal-environment-request/valid/task-workspace.json +27 -0
- package/fixtures/json-schema/personal-environment-result/invalid/active-without-observation.json +7 -0
- package/fixtures/json-schema/personal-environment-result/invalid/deleted-output.json +8 -0
- package/fixtures/json-schema/personal-environment-result/invalid/deleted-snapshot.json +8 -0
- package/fixtures/json-schema/personal-environment-result/invalid/deleted-taskId.json +8 -0
- package/fixtures/json-schema/personal-environment-result/invalid/private-handle.json +8 -0
- package/fixtures/json-schema/personal-environment-result/invalid/stopped-fake-observation.json +20 -0
- package/fixtures/json-schema/personal-environment-result/invalid/task-empty.json +22 -0
- package/fixtures/json-schema/personal-environment-result/invalid/task-host-path.json +22 -0
- package/fixtures/json-schema/personal-environment-result/invalid/task-null.json +22 -0
- package/fixtures/json-schema/personal-environment-result/invalid/task-on-stopped.json +8 -0
- package/fixtures/json-schema/personal-environment-result/invalid/task-without-command-output.json +21 -0
- package/fixtures/json-schema/personal-environment-result/valid/active.json +21 -0
- package/fixtures/json-schema/personal-environment-result/valid/deleted.json +7 -0
- package/fixtures/json-schema/personal-environment-result/valid/expired.json +7 -0
- package/fixtures/json-schema/personal-environment-result/valid/missing.json +7 -0
- package/fixtures/json-schema/personal-environment-result/valid/released.json +7 -0
- package/fixtures/json-schema/personal-environment-result/valid/task-workspace.json +22 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/host-path.json +17 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/invalid-policy.json +17 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/invalid-serial.json +17 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/legacy-version.json +17 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/missing-generation.json +17 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/missing-identity.json +16 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/missing-provider-identity.json +16 -0
- package/fixtures/json-schema/personal-guest-binding/invalid/raw-provider-identity.json +17 -0
- package/fixtures/json-schema/personal-guest-binding/valid/minimal.json +17 -0
- package/fixtures/json-schema/personal-guest-data-plan/invalid/quota.json +1 -0
- package/fixtures/json-schema/personal-guest-data-plan/valid/basic.json +1 -0
- package/fixtures/json-schema/personal-guest-enrollment/invalid/capabilities.json +7 -0
- package/fixtures/json-schema/personal-guest-enrollment/invalid/legacy-version.json +4 -0
- package/fixtures/json-schema/personal-guest-enrollment/invalid/missing-identity.json +3 -0
- package/fixtures/json-schema/personal-guest-enrollment/invalid/ownerId.json +5 -0
- package/fixtures/json-schema/personal-guest-enrollment/invalid/token.json +5 -0
- package/fixtures/json-schema/personal-guest-enrollment/valid/minimal.json +4 -0
- package/fixtures/json-schema/personal-guest-heartbeat/invalid/argv.json +11 -0
- package/fixtures/json-schema/personal-guest-heartbeat/invalid/legacy-version.json +8 -0
- package/fixtures/json-schema/personal-guest-heartbeat/invalid/missing-identity.json +7 -0
- package/fixtures/json-schema/personal-guest-heartbeat/invalid/owner.json +9 -0
- package/fixtures/json-schema/personal-guest-heartbeat/invalid/self-ready.json +9 -0
- package/fixtures/json-schema/personal-guest-heartbeat/invalid/zero-sequence.json +8 -0
- package/fixtures/json-schema/personal-guest-heartbeat/valid/minimal.json +8 -0
- package/fixtures/json-schema/personal-guest-provisioning/invalid/network.json +1 -0
- package/fixtures/json-schema/personal-guest-provisioning/valid/basic.json +1 -0
- package/fixtures/json-schema/personal-guest-renewal/invalid/unknown.json +1 -0
- package/fixtures/json-schema/personal-guest-renewal/valid/basic.json +1 -0
- package/fixtures/json-schema/personal-guest-runtime/invalid/minimal.json +45 -0
- package/fixtures/json-schema/personal-guest-runtime/valid/minimal.json +45 -0
- package/fixtures/json-schema/personal-guest-runtime-result/invalid/minimal.json +28 -0
- package/fixtures/json-schema/personal-guest-runtime-result/valid/minimal.json +27 -0
- package/fixtures/json-schema/personal-guest-tools/invalid/minimal.json +31 -0
- package/fixtures/json-schema/personal-guest-tools/valid/minimal.json +30 -0
- package/fixtures/json-schema/source-import-policy/invalid/case-variant-scope.json +4 -0
- package/fixtures/json-schema/source-import-policy/invalid/case-variant-version.json +4 -0
- package/fixtures/json-schema/source-import-policy/invalid/duplicate-grant.json +4 -0
- package/fixtures/json-schema/source-import-policy/invalid/empty-id.json +4 -0
- package/fixtures/json-schema/source-import-policy/invalid/future-version.json +4 -0
- package/fixtures/json-schema/source-import-policy/invalid/unknown-field.json +4 -0
- package/fixtures/json-schema/source-import-policy/valid/deny-all.json +4 -0
- package/fixtures/json-schema/source-import-policy/valid/shared.json +4 -0
- package/fixtures/json-schema/token-claims/invalid/authz-negative.json +23 -0
- package/fixtures/json-schema/token-claims/invalid/authz-string.json +23 -0
- package/fixtures/json-schema/token-claims/invalid/authz-zero.json +23 -0
- package/fixtures/json-schema/token-claims/valid/versioned-session.json +23 -0
- package/fixtures/openapi/AgentRunEventListEnvelope/invalid/basic.json +8 -0
- package/fixtures/openapi/AgentRunEventListEnvelope/valid/basic.json +8 -0
- package/fixtures/openapi/AgentRunEventListEnvelope/valid/native.json +1 -0
- package/fixtures/openapi/AgentRunResumeRequest/invalid/basic.json +3 -0
- package/fixtures/openapi/AgentRunResumeRequest/valid/basic.json +3 -0
- package/fixtures/openapi/AgentSSHCommandRequest/invalid/task51.json +24 -0
- package/fixtures/openapi/AgentSSHCommandRequest/valid/task51.json +23 -0
- package/fixtures/openapi/AgentSSHCommandResult/invalid/task51.json +8 -0
- package/fixtures/openapi/AgentSSHCommandResult/valid/task51.json +7 -0
- package/fixtures/openapi/AgentSSHSessionRequest/invalid/task51.json +20 -0
- package/fixtures/openapi/AgentSSHSessionRequest/valid/task51.json +19 -0
- package/fixtures/openapi/CapabilityTaskInput/invalid/duplicate-scope.json +36 -0
- package/fixtures/openapi/CapabilityTaskInput/valid/scoped.json +32 -0
- package/fixtures/openapi/DockerQuickCreateHostInput/invalid/guest-access.json +7 -0
- package/fixtures/openapi/DockerQuickCreateHostInput/valid/guest-access.json +9 -0
- package/fixtures/openapi/KnowledgeSourceDocument/invalid/tombstone-with-content.json +1 -0
- package/fixtures/openapi/KnowledgeSourceDocument/valid/tombstone.json +1 -0
- package/fixtures/openapi/KubernetesAgentActionCheck/invalid/unproven-state.json +6 -0
- package/fixtures/openapi/KubernetesAgentActionCheck/valid/configured-denied.json +9 -0
- package/fixtures/openapi/KubernetesAgentActionProfile/invalid/wildcard.json +1 -0
- package/fixtures/openapi/KubernetesAgentActionProfile/valid/workbench.json +1 -0
- package/fixtures/openapi/KubernetesClusterRegistrationRequest/invalid/action-profile.json +3 -0
- package/fixtures/openapi/KubernetesClusterRegistrationRequest/valid/action-profile.json +5 -0
- package/fixtures/openapi/KubernetesNodeListEnvelope/invalid/condition-status-boolean.json +17 -0
- package/fixtures/openapi/KubernetesNodeListEnvelope/invalid/taint-effect-missing.json +16 -0
- package/fixtures/openapi/KubernetesNodeListEnvelope/valid/legacy-fields-absent.json +11 -0
- package/fixtures/openapi/KubernetesNodeListEnvelope/valid/no-taints.json +13 -0
- package/fixtures/openapi/KubernetesNodeListEnvelope/valid/ready-cordoned-tainted.json +28 -0
- package/fixtures/openapi/KubernetesNodeListEnvelope/valid/unknown-fields-null.json +13 -0
- package/fixtures/openapi/KubernetesResourceUpdatePlanRequest/invalid/missing-required.json +1 -0
- package/fixtures/openapi/KubernetesResourceYaml/invalid/missing-required.json +1 -0
- package/fixtures/openapi/KubernetesTopologyCoverage/invalid/empty-as-success.json +5 -0
- package/fixtures/openapi/KubernetesTopologyCoverage/valid/not-installed.json +6 -0
- package/fixtures/openapi/KubernetesTopologyGraphEdge/invalid/negative-weight.json +8 -0
- package/fixtures/openapi/KubernetesTopologyGraphEdge/valid/zero-weight.json +20 -0
- package/fixtures/openapi/KubernetesTopologyGraphNode/invalid/fake-flow-kind.json +42 -0
- package/fixtures/openapi/KubernetesTopologyGraphNode/valid/rule.json +42 -0
- package/fixtures/openapi/KubernetesTopologySnapshot/invalid/raw-source-field.json +33 -0
- package/fixtures/openapi/KubernetesTopologySnapshot/valid/projected-source.json +32 -0
- package/fixtures/openapi/KubernetesTopologySnapshotRequest/invalid/arbitrary-gvr.json +8 -0
- package/fixtures/openapi/KubernetesTopologySnapshotRequest/valid/bounded-sources.json +11 -0
- package/fixtures/openapi/KubernetesTopologySourceQuery/invalid/cluster-namespace.json +4 -0
- package/fixtures/openapi/KubernetesTopologySourceQuery/valid/all-namespaces.json +4 -0
- package/fixtures/openapi/ObservabilityDataSource/invalid/missing-required.json +1 -0
- package/fixtures/openapi/PersonalAgentAccess/invalid/invalid.json +1 -0
- package/fixtures/openapi/PersonalAgentAccess/valid/valid.json +1 -0
- package/fixtures/openapi/PersonalAgentAccessDecision/invalid/invalid.json +1 -0
- package/fixtures/openapi/PersonalAgentAccessDecision/valid/valid.json +1 -0
- package/fixtures/openapi/PersonalAssistantArtifactListEnvelope/invalid/owner.json +8 -0
- package/fixtures/openapi/PersonalAssistantArtifactListEnvelope/valid/side-chat.json +9 -0
- package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/motion.json +1 -0
- package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/owner.json +1 -0
- package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/remote.json +1 -0
- package/fixtures/openapi/PersonalAssistantAvatarRequest/invalid/svg.json +1 -0
- package/fixtures/openapi/PersonalAssistantAvatarRequest/valid/raster.json +1 -0
- package/fixtures/openapi/PersonalAssistantAvatarRequest/valid/reset.json +1 -0
- package/fixtures/openapi/PersonalAssistantUpdateRequest/invalid/empty.json +1 -0
- package/fixtures/openapi/PersonalAssistantUpdateRequest/invalid/owner.json +1 -0
- package/fixtures/openapi/PersonalAssistantUpdateRequest/valid/name.json +1 -0
- package/fixtures/openapi/PersonalDockerEnvironmentPolicy/invalid/host-url.json +12 -0
- package/fixtures/openapi/PersonalDockerEnvironmentPolicy/invalid/lifetime.json +11 -0
- package/fixtures/openapi/PersonalDockerEnvironmentPolicy/invalid/unknown-agent.json +11 -0
- package/fixtures/openapi/PersonalDockerEnvironmentPolicy/valid/basic.json +11 -0
- package/fixtures/openapi/PersonalEnvironment/invalid/invented-state.json +6 -0
- package/fixtures/openapi/PersonalEnvironment/invalid/missing-state.json +5 -0
- package/fixtures/openapi/PersonalEnvironment/invalid/negative-generation.json +7 -0
- package/fixtures/openapi/PersonalEnvironment/invalid/network.json +23 -0
- package/fixtures/openapi/PersonalEnvironment/invalid/private-node.json +24 -0
- package/fixtures/openapi/PersonalEnvironment/invalid/unsupported-backend.json +7 -0
- package/fixtures/openapi/PersonalEnvironment/valid/deleted.json +23 -0
- package/fixtures/openapi/PersonalEnvironment/valid/deleting.json +23 -0
- package/fixtures/openapi/PersonalEnvironment/valid/deletion_unknown.json +23 -0
- package/fixtures/openapi/PersonalEnvironment/valid/frozen-binding.json +13 -0
- package/fixtures/openapi/PersonalEnvironment/valid/ready.json +23 -0
- package/fixtures/openapi/PersonalEnvironment/valid/unknown.json +23 -0
- package/fixtures/openapi/PersonalEnvironment/valid/unprovisioned.json +6 -0
- package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/command.json +3 -0
- package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/node.json +4 -0
- package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/owner.json +4 -0
- package/fixtures/openapi/PersonalEnvironmentActionRequest/invalid/quota.json +10 -0
- package/fixtures/openapi/PersonalEnvironmentActionRequest/valid/reconcile.json +3 -0
- package/fixtures/openapi/PersonalEnvironmentActionRequest/valid/sleep.json +3 -0
- package/fixtures/openapi/PersonalEnvironmentActionRequest/valid/wake.json +4 -0
- package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/empty-name.json +5 -0
- package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/long-name.json +5 -0
- package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/missing-name.json +4 -0
- package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/owner.json +6 -0
- package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/invalid/stale-version.json +5 -0
- package/fixtures/openapi/PersonalEnvironmentDataDeletionRequest/valid/confirmed.json +5 -0
- package/fixtures/openapi/PersonalEnvironmentDataExportRequest/invalid/assistantId.json +4 -0
- package/fixtures/openapi/PersonalEnvironmentDataExportRequest/invalid/environmentVersion.json +4 -0
- package/fixtures/openapi/PersonalEnvironmentDataExportRequest/invalid/ownerId.json +5 -0
- package/fixtures/openapi/PersonalEnvironmentDataExportRequest/valid/current.json +4 -0
- package/fixtures/openapi/PersonalEnvironmentEnvelope/invalid/missing-data.json +1 -0
- package/fixtures/openapi/PersonalEnvironmentEnvelope/valid/state.json +8 -0
- package/fixtures/openapi/PersonalEnvironmentQuota/invalid/cpu.json +7 -0
- package/fixtures/openapi/PersonalEnvironmentQuota/invalid/disk.json +7 -0
- package/fixtures/openapi/PersonalEnvironmentQuota/invalid/network.json +7 -0
- package/fixtures/openapi/PersonalEnvironmentQuota/invalid/processes.json +7 -0
- package/fixtures/openapi/PersonalEnvironmentQuota/valid/basic.json +7 -0
- package/fixtures/openapi/PersonalEnvironmentTemplate/invalid/mode.json +13 -0
- package/fixtures/openapi/PersonalEnvironmentTemplate/invalid/network.json +13 -0
- package/fixtures/openapi/PersonalEnvironmentTemplate/invalid/node.json +14 -0
- package/fixtures/openapi/PersonalEnvironmentTemplate/valid/template.json +13 -0
- package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/invalid/missing.json +1 -0
- package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/invalid/unbounded.json +1317 -0
- package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/valid/choices.json +17 -0
- package/fixtures/openapi/PersonalEnvironmentTemplateListEnvelope/valid/empty.json +3 -0
- package/fixtures/openapi/PersonalEnvironmentUsage/invalid/negative.json +6 -0
- package/fixtures/openapi/PersonalEnvironmentUsage/valid/usage.json +6 -0
- package/fixtures/openapi/PersonalFeedFeedback/invalid/owner.json +4 -0
- package/fixtures/openapi/PersonalFeedFeedback/valid/liked.json +3 -0
- package/fixtures/openapi/PersonalFeedItem/invalid/no-source.json +9 -0
- package/fixtures/openapi/PersonalFeedItem/valid/post.json +15 -0
- package/fixtures/openapi/PersonalFeedSettings/invalid/owner.json +6 -0
- package/fixtures/openapi/PersonalFeedSettings/valid/default.json +5 -0
- package/fixtures/openapi/PersonalGuestPreparationInput/invalid/foreign-owner.json +5 -0
- package/fixtures/openapi/PersonalGuestPreparationInput/invalid/unsafe-counter.json +4 -0
- package/fixtures/openapi/PersonalGuestPreparationInput/valid/ed25519-csr.json +4 -0
- package/fixtures/openapi/PersonalGuestRuntimeEnvelope/invalid/minimal.json +10 -0
- package/fixtures/openapi/PersonalGuestRuntimeEnvelope/valid/minimal.json +9 -0
- package/fixtures/openapi/PersonalGuestRuntimeInput/invalid/minimal.json +6 -0
- package/fixtures/openapi/PersonalGuestRuntimeInput/valid/minimal.json +8 -0
- package/fixtures/openapi/PersonalGuestToolsInput/invalid/minimal.json +5 -0
- package/fixtures/openapi/PersonalGuestToolsInput/valid/minimal.json +4 -0
- package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/device.json +15 -0
- package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/fractional-size.json +15 -0
- package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/network.json +15 -0
- package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/owner.json +15 -0
- package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/provider.json +15 -0
- package/fixtures/openapi/PersonalVMEnvironmentPolicy/invalid/unknown.json +16 -0
- package/fixtures/openapi/PersonalVMEnvironmentPolicy/valid/pve.json +15 -0
- package/fixtures/openapi/PersonalWorkspaceRuntime/invalid/shared.json +3 -0
- package/fixtures/openapi/PersonalWorkspaceRuntime/valid/shared.json +4 -0
- package/fixtures/openapi/PersonalWorkspaceRuntimeEnvelope/invalid/shared.json +5 -0
- package/fixtures/openapi/PersonalWorkspaceRuntimeEnvelope/valid/shared.json +6 -0
- package/fixtures/openapi/ResourceMonitoringPanel/invalid/unknown-quality.json +7 -0
- package/fixtures/openapi/ResourceMonitoringPanel/valid/not-collected.json +7 -0
- package/fixtures/openapi/ResourceMonitoringPoint/invalid/string-zero.json +4 -0
- package/fixtures/openapi/ResourceMonitoringPoint/valid/missing.json +4 -0
- package/fixtures/openapi/ResourceMonitoringPoint/valid/zero.json +4 -0
- package/fixtures/openapi/ResourceMonitoringView/invalid/raw-query.json +12 -0
- package/fixtures/openapi/ResourceMonitoringView/valid/unconfigured.json +12 -0
- package/fixtures/openapi/SecretGenerateSSHKeyRequest/invalid/task51.json +6 -0
- package/fixtures/openapi/SecretGenerateSSHKeyRequest/valid/task51.json +12 -0
- package/fixtures/openapi/SecretReferenceUsage/invalid/version.json +6 -0
- package/fixtures/openapi/SecretReferenceUsage/valid/version.json +8 -0
- package/fixtures/openapi/VMSSHCredentialRedemptionInput/invalid/task51.json +7 -0
- package/fixtures/openapi/VMSSHCredentialRedemptionInput/valid/task51.json +6 -0
- package/fixtures/openapi/VirtualMachineAccessBindingInput/invalid/task51.json +10 -0
- package/fixtures/openapi/VirtualMachineAccessBindingInput/valid/task51.json +10 -0
- package/fixtures/openapi/VirtualMachineActionInput/invalid/capacity-not-boolean.json +1 -0
- package/fixtures/openapi/VirtualMachineActionInput/valid/new-data-with-admission.json +1 -0
- package/fixtures/openapi/VirtualMachineCreateInput/valid/cloud-image.json +12 -0
- package/fixtures/openapi/VirtualMachineDiskChange/invalid/serial-config-injection.json +1 -0
- package/fixtures/openapi/VirtualMachineDiskChange/invalid/serial-existing-disk.json +1 -0
- package/fixtures/openapi/VirtualMachineDiskChange/invalid/serial-too-long.json +1 -0
- package/fixtures/openapi/VirtualMachineDiskChange/valid/personal-data.json +1 -0
- package/fixtures/openapi/VirtualMachineGuestAccessInput/invalid/task51.json +4 -0
- package/fixtures/openapi/VirtualMachineGuestAccessInput/valid/task51.json +6 -0
- package/fixtures/openapi/VirtualMachineSSHCommand/invalid/task51.json +9 -0
- package/fixtures/openapi/VirtualMachineSSHCommand/valid/task51.json +8 -0
- package/fixtures/openapi/VirtualMachineSSHCommandInput/invalid/task51.json +5 -0
- package/fixtures/openapi/VirtualMachineSSHCommandInput/valid/task51.json +5 -0
- package/fixtures/openapi/VirtualMachineSSHFrame/invalid/encoding.json +5 -0
- package/fixtures/openapi/VirtualMachineSSHFrame/invalid/task51.json +4 -0
- package/fixtures/openapi/VirtualMachineSSHFrame/valid/binary.json +5 -0
- package/fixtures/openapi/VirtualMachineSSHFrame/valid/task51.json +5 -0
- package/fixtures/openapi/VirtualMachineSSHSessionInput/invalid/task51.json +4 -0
- package/fixtures/openapi/VirtualMachineSSHSessionInput/valid/task51.json +5 -0
- package/fixtures/openapi/VirtualizationCapacityPolicyInput/invalid/task51.json +12 -0
- package/fixtures/openapi/VirtualizationCapacityPolicyInput/valid/task51.json +13 -0
- package/fixtures/openapi/VirtualizationImageInput/invalid/cloud-image-config-type.json +6 -0
- package/fixtures/openapi/VirtualizationImageInput/valid/cloud-image.json +11 -0
- package/fixtures/openapi/WorkbenchAssistantTask/invalid/kind.json +1 -0
- package/fixtures/openapi/WorkbenchAssistantTask/invalid/owner.json +1 -0
- package/fixtures/openapi/WorkbenchAssistantTask/valid/generate.json +1 -0
- package/fixtures/openapi/WorkbenchAssistantTask/valid/undo.json +1 -0
- package/fixtures/openapi/WorkbenchContextSelection/invalid/remote-image.json +1 -0
- package/fixtures/openapi/WorkbenchContextSelection/invalid/too-many-images.json +1 -0
- package/fixtures/openapi/WorkbenchContextSelection/valid/chat-image.json +9 -0
- package/fixtures/openapi/WorkbenchContextUsage/invalid/fractional-capacity.json +1 -0
- package/fixtures/openapi/WorkbenchContextUsage/invalid/negative.json +1 -0
- package/fixtures/openapi/WorkbenchContextUsage/valid/reported.json +1 -0
- package/fixtures/openapi/WorkbenchContextUsage/valid/unknown.json +1 -0
- package/fixtures/openapi/WorkbenchMainSessionRequest/invalid/owner.json +1 -0
- package/fixtures/openapi/WorkbenchMainSessionRequest/invalid/provider.json +1 -0
- package/fixtures/openapi/WorkbenchMainSessionRequest/valid/empty.json +1 -0
- package/fixtures/openapi/WorkbenchMainSessionRequest/valid/provider.json +1 -0
- package/fixtures/openapi/WorkbenchMessageSearchPage/invalid/role.json +12 -0
- package/fixtures/openapi/WorkbenchMessageSearchPage/valid/page.json +12 -0
- package/fixtures/openapi/WorkbenchMessageWindow/invalid/missing.json +1 -0
- package/fixtures/openapi/WorkbenchMessageWindow/valid/empty.json +3 -0
- package/fixtures/openapi/WorkbenchModelOption/invalid/zero-capacity.json +1 -0
- package/fixtures/openapi/WorkbenchModelOption/valid/capacity.json +1 -0
- package/fixtures/openapi/WorkbenchModelOption/valid/unknown.json +1 -0
- package/fixtures/openapi/WorkbenchProfessionalCapabilityInput/invalid/basic.json +7 -0
- package/fixtures/openapi/WorkbenchProfessionalCapabilityInput/valid/basic.json +11 -0
- package/fixtures/openapi/WorkbenchProfessionalCapabilityInput/valid/selected-profile.json +23 -0
- package/fixtures/openapi/WorkbenchSendMessageStreamRequest/invalid/missing-required.json +1 -0
- package/fixtures/openapi/WorkbenchSendMessageStreamRequest/valid/mixed-professional-task.json +22 -0
- package/fixtures/openapi/WorkbenchTaskIntent/invalid/basic.json +5 -0
- package/fixtures/openapi/WorkbenchTaskIntent/invalid/oversized-capability-source.json +3 -0
- package/fixtures/openapi/WorkbenchTaskIntent/valid/basic.json +9 -0
- package/fixtures/openapi/WorkbenchTaskIntent/valid/independent-sources.json +17 -0
- package/gen/go/sohaapi/client.go +1 -1
- package/gen/go/sohaapi/kubernetes_monitoring_test.go +67 -0
- package/gen/go/sohaapi/personal_environment_test.go +25 -0
- package/gen/go/sohaapi/types.go +3460 -433
- package/gen/go/sohaapi/vm_disk_test.go +21 -0
- package/gen/ts/sohaapi/index.ts +5454 -1397
- package/go.mod +61 -49
- package/go.sum +202 -176
- package/knowledge/connector-definition.schema.json +6 -1
- package/knowledge/source-import-policy.schema.json +32 -0
- package/memory/memory-record.schema.json +1 -1
- package/openapi/soha-api.json +24199 -16810
- package/openapi/soha-api.yaml +2537 -14
- package/openapi/spec_generated.go +3 -3
- package/openapi/spec_test.go +34 -0
- package/package.json +19 -3
- package/resource/agent_access.go +12 -0
- package/resource/agent_profiles.go +62 -0
- package/resource/agent_profiles_test.go +36 -0
- package/resource/kubernetes_kinds.go +73 -0
- package/resource/kubernetes_kinds_test.go +38 -0
- package/resource/models.go +23 -14
- package/resource/network_topology.go +166 -0
- package/resource/network_topology_projection.go +208 -0
- package/resource/network_topology_projection_test.go +53 -0
- package/resource/network_topology_test.go +51 -0
- package/resource/network_topology_validation.go +29 -0
- package/resource/node_drain.go +34 -0
- package/resource/resource_monitoring.go +99 -0
- package/resource/runtime/network_topology.go +232 -0
- package/resource/runtime/network_topology_test.go +62 -0
- package/resource/runtime/node_drain.go +124 -0
- package/resource/runtime/node_drain_test.go +95 -0
- package/resource/runtime/resource_edit.go +128 -0
- package/resource/runtime/resource_edit_test.go +183 -0
- package/resource/runtime/resource_monitoring.go +243 -0
- package/resource/runtime/resource_monitoring_test.go +88 -0
- /package/fixtures/openapi/DeliveryExecutionHistoryPage/{invalid-kind.json → invalid/invalid-kind.json} +0 -0
- /package/fixtures/openapi/DeliveryExecutionHistoryPage/{valid-build.json → valid/valid-build.json} +0 -0
- /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.
|
|
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`
|
|
177
|
-
checkout without changing
|
|
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
|
+
}
|