plugin-oci
| Version | 2026.194.1200 |
| Repo | box/github.com/opencharly/plugin-oci:v2026.270.1458 |
| Plugin | yes — see the plugin reference |
OUT-OF-TREE charly plugin serving the oci VERB (verb:oci) — the OCI IMAGE
ENGINE externalized from charly core (the P14a cutover). It OWNS the
go-containerregistry stack: the layer-MERGE engine (merge.go: planMerge →
executeMerge → mergeLayers with full whiteout handling, plus the podman/skopeo
daemon save/load) and the remote-image adopt-user PROBE (inspect_user.go:
/etc/passwd lookup at a configured uid). Both run HOST-SIDE and exec
podman/skopeo themselves — the verb:libvirt precedent — so go-containerregistry
lives HERE, and charly/go.mod links it NOWHERE.
It is DUAL-PLACEMENT: its importable provider package (NewProvider/NewMeta,
serving verb:oci) is COMPILED INTO charly when listed in charly.yml
compiled_plugins: (the DEFAULT — the merge + adopt-user probes sit on the
core BUILD PATH and must resolve project-lessly and reliably, mirroring the
compiled-in verb:libvirt / verb:tunnel / verb:enc profile; registered in-process
via registerCompiledPlugin), and the SAME provider is served OUT-OF-PROCESS over
go-plugin gRPC by the cmd/serve shim (host-built + connected via LocalTransport)
when it is not. Placement is invisible above the provider registry.
verb:oci is a pure INTERNAL RPC verb — NEVER authored as an oci: check step
(it declares no structured InputDef, and it ships its OWN self-contained CUE
schema, schema/oci.cue, served over Describe — there is NO schema-less plugin).
It is keyed by an OciOp env discriminator (mirroring the vm plugin’s
VmOp): oci_op=merge decodes a spec.MergeRequest and returns a spec.MergeReply
(layer counts + progress Notes the host prints; a per-merge failure rides
Reply.Error), oci_op=inspect-user decodes a spec.ImageUserInput and returns a
spec.UserInfo, and oci_op=cache-push / cache-pull move a whole named
spec/cache.ArtifactStore (already a standard OCI Image Layout) to and from an
OCI registry — the registry transport for the OCI-manifest-native cache
(opencharly/spec#148): push = layout.ImageIndex → remote.WriteIndex, pull =
remote.Index → layout.Write, auth via authn.DefaultKeychain. charly box merge
(candy/plugin-box’s mergeOneBox, P14) and candy/plugin-build’s drive both reach it
DIRECTLY via Executor.InvokeProvider (verb:oci) — the F10 peer-dispatch leg; the
ONE remaining core consumer is generate.go’s adopt-user resolution, reached via the
oci_plugin.go shim (still core-side, K1-gated — see that file’s own
migration-inventory note). The MERGE engine’s byte-identical relocation is locked
by the candy’s TestMergeEngineGoldenParity (the merged-layer DiffID golden); the
cache transport’s lossless round-trip by TestCacheTransportDeterministic and its live
push/pull by TestCachePushPullLiveRoundTrip (LIVE_REGISTRY-gated).
Acceptance plan
Section titled “Acceptance plan”This candy’s plan: — the runnable spec charly check executes against a live deployment. check: steps are idempotent probes; run: steps change state.
| Intent | Step |
|---|---|
check |
the out-of-tree plugin ships a buildable Go module providing verb:oci (the externalized OCI merge + adopt-user engine, carrying the go-containerregistry stack) the host can build, compile in, and serve; the merge engine’s byte-identical relocation is locked by TestMergeEngineGoldenParity |
check |
the plugin ships the verb:oci cache-push / cache-pull transport for a named spec/cache ArtifactStore (an OCI Image Layout) and its lossless layout round-trip is locked by TestCacheTransportDeterministic |