Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,16 @@ host's default container namespace.

Managed runtime release packaging verifies the upstream `SHA256SUMS` and
`SHA256SUMS.asc` digests and emits a source manifest in the plugin release
archive. Agent-side download, extraction, signature verification, and lifecycle
wiring are intentionally left to the workflow-compute host integration phase so
the plugin does not advertise a host-installed `nerdctl` as bundled.
archive. The public `ManagedRuntimeBundleInstaller` helper and
`managed-runtime` subcommands provide the reusable agent-side lifecycle contract:
download pinned artifact/checksum/signature objects from catalog metadata,
verify the detached OpenPGP signature against the catalog-pinned trust root,
extract the bundle into an agent-owned scoped install root, write an install
manifest with extracted file digests, doctor the scoped install, remove only the
scoped bundle root, and reinstall from the same pinned metadata without removing
the old install before the replacement has been staged. Workflow Compute hosts
consume this contract instead of implementing private host-only bundle lifecycle
behavior.

The default conformance image reference is the Debian 13 distroless static index:

Expand Down Expand Up @@ -77,3 +84,21 @@ Run installed runtime smoke probes explicitly:
```sh
WORKFLOW_COMPUTE_RUNTIME_PROBE_REAL=1 GOWORK=off go test ./container -run TestDockerCompatibleRuntimeProbeRealBackends -count=1 -v
```

Install and verify a managed bundle from catalog metadata:

```sh
workflow-plugin-compute-container managed-runtime install \
--catalog managed-runtime-bundles.json \
--install-root "$HOME/.local/share/workflow-compute/managed-runtime" \
--bundle-id managed-containerd-linux-amd64 \
--target-os linux \
--target-arch amd64

workflow-plugin-compute-container managed-runtime doctor \
--catalog managed-runtime-bundles.json \
--install-root "$HOME/.local/share/workflow-compute/managed-runtime" \
--bundle-id managed-containerd-linux-amd64 \
--target-os linux \
--target-arch amd64
```
6 changes: 6 additions & 0 deletions cmd/workflow-plugin-compute-container/main.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package main

import (
"context"
"os"

plugin "github.com/GoCodeAlone/workflow-plugin-compute-container/internal"
sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk"
)

var version = "0.0.0"

func main() {
if len(os.Args) > 1 && os.Args[1] == "managed-runtime" {
os.Exit(plugin.RunManagedRuntimeCLI(context.Background(), os.Args[1:], os.Stdout, os.Stderr))
}
plugin.Version = version
sdk.Serve(plugin.NewPlugin(),
sdk.WithBuildVersion(sdk.ResolveBuildVersion(plugin.Version)),
Expand Down
21 changes: 21 additions & 0 deletions container/managed_runtime_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,21 @@ type ManagedRuntimeBundleCatalog struct {
SourceBaseURL string `json:"source_base_url,omitempty"`
GeneratedAt time.Time `json:"generated_at"`
Bundles []core.ManagedRuntimeBundleDescriptor `json:"bundles"`
TrustRoots []ManagedRuntimeTrustRoot `json:"trust_roots,omitempty"`
BlockedVersions []string `json:"blocked_versions,omitempty"`
RevokedKeyIDs []string `json:"revoked_key_ids,omitempty"`
MinimumVersion string `json:"minimum_version,omitempty"`
StableSigningKey string `json:"stable_signing_key,omitempty"`
}

type ManagedRuntimeTrustRoot struct {
KeyID string `json:"key_id"`
Name string `json:"name"`
URL string `json:"url,omitempty"`
Digest string `json:"digest"`
Issuer string `json:"issuer,omitempty"`
}

func (c ManagedRuntimeBundleCatalog) Bundle(bundleID string, now time.Time) (core.ManagedRuntimeBundleDescriptor, error) {
if strings.TrimSpace(bundleID) == "" {
return core.ManagedRuntimeBundleDescriptor{}, errors.New("bundle_id is required")
Expand Down Expand Up @@ -52,6 +61,18 @@ func (c ManagedRuntimeBundleCatalog) BundleForTarget(bundleID, targetOS, targetA
return bundle, nil
}

func (c ManagedRuntimeBundleCatalog) TrustRootForBundle(bundle core.ManagedRuntimeBundleDescriptor) (ManagedRuntimeTrustRoot, error) {
for _, root := range c.TrustRoots {
if root.KeyID == bundle.SignatureKeyID && root.Digest == bundle.TrustRootDigest {
if strings.TrimSpace(root.Name) == "" {
return ManagedRuntimeTrustRoot{}, fmt.Errorf("managed runtime trust root for key %q has no object name", bundle.SignatureKeyID)
}
return root, nil
}
}
return ManagedRuntimeTrustRoot{}, fmt.Errorf("managed runtime trust root for signing key %q and digest %q not found", bundle.SignatureKeyID, bundle.TrustRootDigest)
}

func validateManagedRuntimeBundlePolicy(c ManagedRuntimeBundleCatalog, bundle core.ManagedRuntimeBundleDescriptor, now time.Time) error {
if err := bundle.ValidateAt(now); err != nil {
return err
Expand Down
Loading
Loading