Repository navigation
feat(plugin): populate ProvisionRequest.dependency_outputs_json from params.ResourceOutputs - #571
Merged
Merged
Conversation
…params.ResourceOutputs Mirrors the `parent_info_json` wire-protocol fix in #567. The pre-existing `dependency_outputs = 5` field on ProvisionRequest was declared (flat `map<string, string>`) but never populated by any sidecar — the string-only shape couldn't carry the per-value secret flag or the nested outputs map #569 introduced. A new JSON-blob field `dependency_outputs_json = 12` carries `map[resourceName]*api.PluginResourceOutput` across the bus. ## What - **proto**: new `bytes dependency_outputs_json = 12` on ProvisionRequest with doc comment pointing at the roadmap item and the #569 shape it carries. - **sidecar**: `makeResourceSidecar`'s ProvisionRequest literal populates the field by walking `params.ResourceOutputs` and picking up every entry whose `.Ref` is a `*api.PluginResourceOutput` (the shape `harvestPluginOutputs` publishes post-#569). In-tree dependencies (typed Go struct Refs) are dropped silently — the plugin side can't unmarshal unknown struct shapes, and the receiving Provision body already errors clearly when an expected sibling is absent from its outputs map. - **runtime**: new `DependencyOutputsFromProvisionRequest(req)` helper sits next to `ParentInfoFromProvisionRequest` in `pkg/plugin/runtime`. Decodes the JSON into `map[string]*api.ResourceOutput` with `Ref: *api.PluginResourceOutput`, which is exactly what sibling consumers' Provision bodies already type-assert on post-#569. Plugin dispatch threads this onto `ProvisionParams.ResourceOutputs` before the body runs. - **tests**: `runtime.DependencyOutputsFromProvisionRequest` round-trip + empty-means-nil + malformed-JSON rejection. Sidecar packing test verifies mixed input (one plugin-owned, one in-tree) lands only the plugin-owned entry in the outbound JSON. ## Why Surfaced 2026-11-08 by the sc-plugin-gcp phase-5 tier-2 smoke: `gcp-docker-image-push` reads the artifact-registry URL via `params.ResourceOutputs[registryResource].Ref.(*ArtifactRegistryOut)` inside its Provision body. In-tree, SC core populated that map before dispatching; post-extraction the map arrived empty and the plugin errored with `expected registry resource %q to be present in outputs for %q in %q`. Any plugin resource across the fleet that depends on another resource's output breaks the same way post- extraction — not GCP-specific. ## Backwards compatibility Additive proto field. Older plugins ignore the field and see nil `params.ResourceOutputs` — same silent-drop shape that today's broken state exhibits. Newer plugins receive the typed map. Preserves wire- protocol version. ## Follow-up (not in this PR) sc-plugin-gcp's `docker_image.go` currently type-asserts `.Ref.(*ArtifactRegistryOut)` — the internal GCP struct. Switch it to the `*api.PluginResourceOutput` shape (read the URL via `.Outputs["url"].Value.(string)` or the `api.PluginOutputsOf` helper) in a sc-plugin-gcp PR once this merges + an api release cuts. ## Roadmap - `forge/docs/roadmap/items/sc-plugin-dependency-outputs-not-populated.md` ## Test plan - [x] `go build ./...` - [x] `go test ./pkg/plugin/runtime/... ./pkg/clouds/pulumi/... -count=1` — all green locally including the three new runtime tests + two new sidecar tests. - [ ] Downstream sc-plugin-gcp update: switch docker_image.go to the PluginResourceOutput shape; rerun tier-2 smoke with docker-image-push back in the fixture end-to-end. Signed-off-by: Ilya Sadykov <smecsia@gmail.com>
smecsia
requested review from
Cre-eD,
Laboratory and
universe-ops
as code owners
November 8, 2026 16:43
Semgrep Scan ResultsRepository:
Scanned at 2026-11-08 18:23 UTC |
Security Scan ResultsRepository:
Scanned at 2026-11-08 18:23 UTC |
baasforger
approved these changes
Nov 8, 2026
universe-ops
approved these changes
Nov 8, 2026
universe-ops
enabled auto-merge (squash)
November 8, 2026 18:13
…le-container-com/api into feat/plugin-dependency-outputs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Mirrors the
parent_info_jsonwire-protocol fix in #567. Fills the gap thatbroke
gcp-docker-image-push(and will break any future plugin resourcethat reads a sibling's output) post the GCP extraction. Fleet-wide, not
GCP-specific.
What
bytes dependency_outputs_json = 12on ProvisionRequest.The pre-existing flat
dependency_outputs = 5field couldn't carry theper-value secret flag or the nested outputs map plugin: let a sibling read a plugin-owned resource's outputs, not just its URN #569 introduced; the JSON
blob does.
pkg/clouds/pulumi/plugin_sidecars.go):makeResourceSidecarwalksparams.ResourceOutputs, picks up everyentry whose
.Refis a*api.PluginResourceOutput(whatharvestPluginOutputsproduces post-plugin: let a sibling read a plugin-owned resource's outputs, not just its URN #569), andjson.Marshals theresult. In-tree typed Refs are dropped silently (the plugin can't
unmarshal unknown Go struct shapes) — matches the pre-field silent-drop
behaviour.
pkg/plugin/runtime/compute.go): newDependencyOutputsFromProvisionRequest(req)helper, mirror ofParentInfoFromProvisionRequest. Decodes intomap[string]*api.ResourceOutputwithRef: *api.PluginResourceOutput,which is exactly what sibling-reading bodies already type-assert on
after plugin: let a sibling read a plugin-owned resource's outputs, not just its URN #569.
malformed-JSON) + two sidecar tests (packs mixed inputs correctly /
empty outputs → empty field).
Why
Live-caught 2026-11-08 by the sc-plugin-gcp phase-5 tier-2 smoke:
The in-tree code read
params.ResourceOutputs[dep]and type-asserted ona sibling resource's internal typed struct. Post-extraction, the map was
empty because the sidecar never populated the wire field. Any plugin
resource across the fleet that implements
api.WithParentDependenciesand reads a sibling output hits the same gap.
Backwards compatibility
Additive proto field. Older plugins ignore it and get
nilparams.ResourceOutputs— the current (broken) silent-drop shape. Newerplugins receive the typed map. Wire-protocol version unchanged.
Companion follow-up
sc-plugin-gcp's
docker_image.gostill type-asserts on the internal*ArtifactRegistryOut; the sc-plugin-gcp side of the fix will switch itto
*api.PluginResourceOutputand re-read the URL via.Outputs["url"].Value.(string)once this merges + an api release cuts.Tier-2 smoke will then put docker-image-push back in the fixture
end-to-end.
Roadmap
Test plan
go build ./...go test ./pkg/plugin/runtime/... ./pkg/clouds/pulumi/... -count=1— allgreen locally including the 5 new tests
gofumpt+gci(this repo's 6-section config) applied to alltouched files
PluginResourceOutputshape, then tier-2 smoke re-runs withdocker-image-push live