From ae37042db558db14ccd427a404d3cc1e39d9f8d1 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 04:29:30 -0400 Subject: [PATCH] feat: use compute-core catalog protocol --- README.md | 12 +++++---- SPEC.md | 12 ++++----- go.mod | 5 ++-- go.sum | 3 +++ internal/module.go | 6 ++--- internal/module_test.go | 60 ++++++++++++++++++++--------------------- plugin.json | 8 +++++- 7 files changed, 58 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 4824117..566c2f7 100644 --- a/README.md +++ b/README.md @@ -28,17 +28,19 @@ Examples: eligible enrolled agents, records the resulting task/proof ids, and uses the core ledger for accounting. - A provider plugin, such as product capture or edge compute, exposes a typed - `ProviderContract`; this plugin submits or waits on the resulting generic - workflow-compute task without embedding provider business logic. + `workflow-plugin-compute-core/protocol.ProviderContract`; this plugin submits + or waits on the resulting generic workflow-compute task without embedding + provider business logic. `compute.provider` in this repository means "Workflow connection to a wfcompute control plane." It is not a wfcompute worker/provider node. Provider nodes, supervisors, package updates, proof verification, rewards, and dashboard state belong to `workflow-compute`. -`compute.provider_catalog` consumes `workflow-compute/pkg/protocol.ProviderContract` -records. It intentionally does not define a separate plugin-local executor, -dependency, verification, reward, or network provider shape. +`compute.provider_catalog` consumes +`workflow-plugin-compute-core/protocol.ProviderContract` records. It +intentionally does not define a separate plugin-local executor, dependency, +verification, reward, or network provider shape. Provider-specific contracts belong in the owning provider plugin. For example, product capture owns product URL semantics and edge compute owns edge diff --git a/SPEC.md b/SPEC.md index 1796628..ccf3a87 100644 --- a/SPEC.md +++ b/SPEC.md @@ -18,9 +18,9 @@ C7: Standalone repo verification uses `GOWORK=off` unless parent `go.work` inclu C8: `wfctl compute` CLI adapter owns operator UX only; scheduler/ledger/proof semantics stay core. C9: External Workflow apps may use plugin outside wfcompute deployment/network if they can reach scoped control-plane client APIs. C10: Public client control-plane access ≠ provider/admin mutation ingress. -C11: Plugin provider catalog details track `workflow-compute`'s typed `ProviderContract`, not a parallel plugin-local provider shape. +C11: Plugin provider catalog details track `workflow-plugin-compute-core/protocol.ProviderContract`, not a parallel plugin-local provider shape. C12: Provider-specific typed steps belong in the owning provider plugin, not this generic compute adapter. -C13: Provider catalog entries are imported `workflow-compute` contracts; product/application assumptions belong in the calling workflow or provider plugin. +C13: Provider catalog entries are imported compute-core contracts; product/application assumptions belong in the calling workflow or provider plugin. C14: Task residue policy submitted by this plugin is customer intent only; `workflow-compute` owns provider/product authority resolution, policy hashing, lease enforcement, and residue cleanup. §I @@ -29,7 +29,7 @@ repo: `workflow-plugin-compute` → Workflow external plugin adapter core: `workflow-compute` → scheduler, worker, ledger, proof, reward, dashboard module: `compute.provider` → control-plane connection + auth refs module: `compute.pool` → org/pool/policy defaults -module: `compute.provider_catalog` → core `protocol.ProviderContract` declarations +module: `compute.provider_catalog` → public compute-core `protocol.ProviderContract` declarations step: `step.compute_dispatch` → submit task step: `step.compute_wait` → wait/read proof step: `step.compute_map` → fanout deterministic task set @@ -56,10 +56,10 @@ V15: `wfctl compute submit` supports command/container-build without leaking wor V16: `wfctl compute accounting export` includes raw contribution units and policy reward outputs without leaking token V17: docs/examples distinguish `compute.provider` Workflow connection from wfcompute provider/worker node V18: plugin guidance for public control-plane use excludes bootstrap token, provider mutation, package/campaign/trust-root mutation, and raw agent/supervisor control APIs -V19: PR CI checks plugin provider catalog tests against current `GoCodeAlone/workflow-compute` main with a local module replace +V19: PR CI checks plugin provider catalog tests against public `workflow-plugin-compute-core/protocol.ProviderContract` V20: manifest `stepTypes` exactly match runtime `StepTypes` V21: plugin step/CLI surfaces must not mention product-capture, BMW, edge lambda, edge CDN, or another provider-specific business domain -V22: `compute.provider_catalog` accepts typed `protocol.ProviderContract` records from provider plugins without defining a parallel plugin-local provider schema +V22: `compute.provider_catalog` accepts typed `workflow-plugin-compute-core/protocol.ProviderContract` records from provider plugins without defining a parallel plugin-local provider schema V23: `step.compute_dispatch` and `step.compute_map` accept valid short-lived task `residue_policy`, reject malformed residue policy locally, and do not compute policy hashes or override provider/product authority §T @@ -75,7 +75,7 @@ T7|x|add `wfctl compute github-runner` adapter commands for runner register/job T8|x|add `wfctl compute submit command|container-build` for ad hoc workload demos|I.cmd,I.wfctl,C8,V10,V12,V15 T9|x|include rewards in `wfctl compute accounting export`|I.cmd,I.wfctl,C8,V10,V16 T10|x|document external Workflow client use cases and public client-surface boundary|C9,C10,V17,V18 -T11|x|align provider catalog details with workflow-compute `ProviderContract` and gate drift in PR CI|C11,I.module,V19 +T11|x|align provider catalog details with public compute-core `ProviderContract` and gate drift in PR CI|C11,I.module,V19 T12|x|remove provider-specific product-capture step/CLI/domain preview flattening from generic compute adapter|C12,I.step,V20,V21 T13|x|keep provider catalog validation generic so external provider plugins can supply edge/product contracts without plugin-local provider schema|C13,I.module,V19,V22 T14|x|submit optional short-lived task residue policy through dispatch/map steps without taking over core authority resolution|C14,I.step,V23 diff --git a/go.mod b/go.mod index c789e87..5382b86 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,11 @@ go 1.26.3 require ( github.com/GoCodeAlone/workflow v0.62.0 github.com/GoCodeAlone/workflow-compute v0.0.0-20260524063206-b3e8de8ce8d6 + github.com/GoCodeAlone/workflow-plugin-compute-core v0.0.0-20260524082635-d967d825f9d3 ) require ( + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/BurntSushi/toml v1.6.0 // indirect github.com/DataDog/datadog-go/v5 v5.8.3 // indirect github.com/GoCodeAlone/go-plugin v1.7.0 // indirect @@ -40,7 +42,6 @@ require ( github.com/cloudevents/sdk-go/v2 v2.16.2 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect - github.com/containerd/log v0.1.0 // indirect github.com/danieljoos/wincred v1.2.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect @@ -95,8 +96,6 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/sys/sequential v0.6.0 // indirect - github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect diff --git a/go.sum b/go.sum index cd751a2..2deb597 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/GoCodeAlone/workflow v0.62.0 h1:emFkTomDpVmBcEfw7quRO4V/J4qDsWNx/CrBd github.com/GoCodeAlone/workflow v0.62.0/go.mod h1:659GGDrw3QJ7b625y9rf8QhKIpt1VCoEG0MxKu5tGQs= github.com/GoCodeAlone/workflow-compute v0.0.0-20260524063206-b3e8de8ce8d6 h1:R2YBH5Vnkn/O1ksTRbzn5vaMN/GtnuFNiTDRF/FR0GY= github.com/GoCodeAlone/workflow-compute v0.0.0-20260524063206-b3e8de8ce8d6/go.mod h1:T8yGXrRBm2USwkRFvMaoq4aPDt/f7JciZY9Y/l/upYs= +github.com/GoCodeAlone/workflow-plugin-compute-core v0.0.0-20260524082635-d967d825f9d3 h1:EPYnvSU3sZNnTbFyqZARKvHH00eUL5t7yWHLiBuKnOU= +github.com/GoCodeAlone/workflow-plugin-compute-core v0.0.0-20260524082635-d967d825f9d3/go.mod h1:1T6uCpUWPCNk6XPYgKq5CL/7LkD24MphKYsYVzF4jnI= github.com/GoCodeAlone/yaegi v0.17.2 h1:WK6Y6e0t1a6U7r+S2dN3CGWW1PizYD3zO0zneToZPxM= github.com/GoCodeAlone/yaegi v0.17.2/go.mod h1:z5Pr6Wse6QJcQvpgxTxzMAevFarH0N37TG88Y9dprx0= github.com/IBM/sarama v1.47.0 h1:GcQFEd12+KzfPYeLgN69Fh7vLCtYRhVIx0rO4TZO318= @@ -417,6 +419,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/module.go b/internal/module.go index 4fb2c0a..46ee073 100644 --- a/internal/module.go +++ b/internal/module.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/GoCodeAlone/workflow-compute/pkg/protocol" + coreprotocol "github.com/GoCodeAlone/workflow-plugin-compute-core/protocol" sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" ) @@ -170,7 +170,7 @@ func poolModuleSchema() sdk.ModuleSchemaData { } type providerCatalogConfig struct { - Contracts []protocol.ProviderContract `json:"contracts"` + Contracts []coreprotocol.ProviderContract `json:"contracts"` } type providerCatalogModule struct { @@ -226,7 +226,7 @@ func providerCatalogModuleSchema() sdk.ModuleSchemaData { Category: "Compute", Description: "Declarative workflow-compute provider contracts validated against the core provider catalog protocol.", ConfigFields: []sdk.ConfigField{ - {Name: "contracts", Type: "array", Description: "workflow-compute ProviderContract records.", Required: true}, + {Name: "contracts", Type: "array", Description: "workflow-plugin-compute-core ProviderContract records.", Required: true}, }, } } diff --git a/internal/module_test.go b/internal/module_test.go index 328f97f..5a31461 100644 --- a/internal/module_test.go +++ b/internal/module_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/GoCodeAlone/workflow-compute/pkg/protocol" + coreprotocol "github.com/GoCodeAlone/workflow-plugin-compute-core/protocol" sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" ) @@ -116,7 +116,7 @@ func TestModuleSchemas(t *testing.T) { } } -func TestProviderCatalogUsesWorkflowComputeProviderContracts(t *testing.T) { +func TestProviderCatalogUsesComputeCoreProviderContracts(t *testing.T) { contract := validProviderContract() raw := map[string]any{ "contracts": []any{toMap(t, contract)}, @@ -143,7 +143,7 @@ func TestProviderCatalogRejectsLegacyGroupedProviderDetails(t *testing.T) { } } -func TestProviderCatalogRejectsMalformedWorkflowComputeContract(t *testing.T) { +func TestProviderCatalogRejectsMalformedComputeCoreContract(t *testing.T) { contract := validProviderContract() contract.ConfigSchemaDigest = "sha256:not-hex" _, err := newProviderCatalogModule("catalog", map[string]any{ @@ -157,9 +157,9 @@ func TestProviderCatalogRejectsMalformedWorkflowComputeContract(t *testing.T) { func TestProviderCatalogAcceptsRuntimeProfileResiduePolicy(t *testing.T) { contract := validProviderContract() contract.RuntimeContract.Profiles[0].HostWorkspaceSupported = true - contract.RuntimeContract.Profiles[0].ResiduePolicy = protocol.ResiduePolicy{ - Mode: protocol.ResidueModeProviderBound, - AllowedModes: []protocol.ResidueMode{protocol.ResidueModeIsolated, protocol.ResidueModeProviderBound}, + contract.RuntimeContract.Profiles[0].ResiduePolicy = coreprotocol.ResiduePolicy{ + Mode: coreprotocol.ResidueModeProviderBound, + AllowedModes: []coreprotocol.ResidueMode{coreprotocol.ResidueModeIsolated, coreprotocol.ResidueModeProviderBound}, MaxAgeSeconds: 600, WipeOnFailure: true, } @@ -169,7 +169,7 @@ func TestProviderCatalogAcceptsRuntimeProfileResiduePolicy(t *testing.T) { if err != nil { t.Fatalf("newProviderCatalogModule: %v", err) } - if module.config.Contracts[0].RuntimeContract.Profiles[0].ResiduePolicy.Mode != protocol.ResidueModeProviderBound { + if module.config.Contracts[0].RuntimeContract.Profiles[0].ResiduePolicy.Mode != coreprotocol.ResidueModeProviderBound { t.Fatalf("residue policy not decoded: %+v", module.config.Contracts[0].RuntimeContract.Profiles[0].ResiduePolicy) } } @@ -177,9 +177,9 @@ func TestProviderCatalogAcceptsRuntimeProfileResiduePolicy(t *testing.T) { func TestProviderCatalogRejectsReusableResidueWithoutWorkspace(t *testing.T) { contract := validProviderContract() contract.RuntimeContract.Profiles[0].HostWorkspaceSupported = false - contract.RuntimeContract.Profiles[0].ResiduePolicy = protocol.ResiduePolicy{ - Mode: protocol.ResidueModeProviderBound, - AllowedModes: []protocol.ResidueMode{protocol.ResidueModeProviderBound}, + contract.RuntimeContract.Profiles[0].ResiduePolicy = coreprotocol.ResiduePolicy{ + Mode: coreprotocol.ResidueModeProviderBound, + AllowedModes: []coreprotocol.ResidueMode{coreprotocol.ResidueModeProviderBound}, } _, err := newProviderCatalogModule("catalog", map[string]any{ "contracts": []any{toMap(t, contract)}, @@ -189,9 +189,9 @@ func TestProviderCatalogRejectsReusableResidueWithoutWorkspace(t *testing.T) { } } -func validProviderContract() protocol.ProviderContract { - return protocol.ProviderContract{ - ProtocolVersion: protocol.Version, +func validProviderContract() coreprotocol.ProviderContract { + return coreprotocol.ProviderContract{ + ProtocolVersion: coreprotocol.Version, ID: "workflow-compute-control-plane-v1", PluginID: "workflow-plugin-compute", ProviderID: "workflow-compute-control-plane", @@ -200,29 +200,29 @@ func validProviderContract() protocol.ProviderContract { DisplayName: "workflow-compute Control Plane", ConfigSchemaRef: "schema://providers/workflow-plugin-compute/workflow-compute-control-plane/v1", ConfigSchemaDigest: "sha256:" + strings.Repeat("b", 64), - OperatingModes: []protocol.NetworkOperatingMode{protocol.NetworkModeBatch}, - WorkloadKinds: []string{string(protocol.WorkloadCommand), string(protocol.WorkloadContainerBuild)}, + OperatingModes: []coreprotocol.NetworkOperatingMode{coreprotocol.NetworkModeBatch}, + WorkloadKinds: []string{string(coreprotocol.WorkloadCommand), string(coreprotocol.WorkloadContainerBuild)}, ExecutorProviders: []string{"sandboxed-command"}, - ExecutionSecurityTiers: []protocol.ExecutionSecurityTier{protocol.ExecutionSandboxedContainer}, - ProofTiers: []protocol.ProofTier{protocol.ProofArtifactHash}, - NetworkModes: []protocol.NetworkMode{protocol.NetworkModeRelay}, - RuntimeContract: protocol.ProviderRuntimeContract{ - Profiles: []protocol.ProviderRuntimeProfile{{ + ExecutionSecurityTiers: []coreprotocol.ExecutionSecurityTier{coreprotocol.ExecutionSandboxedContainer}, + ProofTiers: []coreprotocol.ProofTier{coreprotocol.ProofArtifactHash}, + NetworkModes: []coreprotocol.NetworkMode{coreprotocol.NetworkModeRelay}, + RuntimeContract: coreprotocol.ProviderRuntimeContract{ + Profiles: []coreprotocol.ProviderRuntimeProfile{{ ID: "sandboxed-command-oci", - RuntimeProfile: protocol.RuntimeProfileSandboxedOCI, + RuntimeProfile: coreprotocol.RuntimeProfileSandboxedOCI, ExecutorProvider: "sandboxed-command", - ExecutionSecurityTier: protocol.ExecutionSandboxedContainer, - ProofTier: protocol.ProofArtifactHash, - AllowedRuntimeTools: []protocol.ContainerRuntimeTool{protocol.ContainerRuntimePodman, protocol.ContainerRuntimeDocker, protocol.ContainerRuntimeNerdctl}, + ExecutionSecurityTier: coreprotocol.ExecutionSandboxedContainer, + ProofTier: coreprotocol.ProofArtifactHash, + AllowedRuntimeTools: []coreprotocol.ContainerRuntimeTool{coreprotocol.ContainerRuntimePodman, coreprotocol.ContainerRuntimeDocker, coreprotocol.ContainerRuntimeNerdctl}, ImageDigestRequired: true, RootFSDigestRequired: true, AllowedMountRefs: []string{"workspace"}, - WritableRootFS: protocol.RuntimePermissionForbidden, - Privileged: protocol.RuntimePermissionForbidden, - HostNamespaces: protocol.RuntimePermissionForbidden, - HostSocket: protocol.RuntimePermissionForbidden, - SeccompDisable: protocol.RuntimePermissionForbidden, - NoNewPrivilegesDisable: protocol.RuntimePermissionForbidden, + WritableRootFS: coreprotocol.RuntimePermissionForbidden, + Privileged: coreprotocol.RuntimePermissionForbidden, + HostNamespaces: coreprotocol.RuntimePermissionForbidden, + HostSocket: coreprotocol.RuntimePermissionForbidden, + SeccompDisable: coreprotocol.RuntimePermissionForbidden, + NoNewPrivilegesDisable: coreprotocol.RuntimePermissionForbidden, ConformanceProfiles: []string{"sandboxed-oci-v1"}, }}, }, diff --git a/plugin.json b/plugin.json index 6ec23fb..52148ce 100644 --- a/plugin.json +++ b/plugin.json @@ -21,5 +21,11 @@ "description": "Operate a workflow-compute control plane" } ] - } + }, + "dependencies": [ + { + "name": "workflow-plugin-compute-core", + "constraint": ">=0.0.0" + } + ] }