Skip to content

fix(dispatch): wire IaCProvider.BootstrapStateBackend in InvokeMethod (v0.7.5)#19

Merged
intel352 merged 1 commit into
mainfrom
fix/v0.7.5-bootstrap-grpc-dispatch
Apr 23, 2026
Merged

fix(dispatch): wire IaCProvider.BootstrapStateBackend in InvokeMethod (v0.7.5)#19
intel352 merged 1 commit into
mainfrom
fix/v0.7.5-bootstrap-grpc-dispatch

Conversation

@intel352

Copy link
Copy Markdown
Contributor

Summary

  • Adds missing case "IaCProvider.BootstrapStateBackend": to doModuleInstance.InvokeMethod — fixes "unknown method IaCProvider.BootstrapStateBackend" error blocking BMW deploy
  • Adds invokeProviderBootstrapStateBackend helper: extracts cfg from args (defaults to empty map if absent), calls provider, nil-safe returns empty map
  • Promotes fakeIaCProvider.BootstrapStateBackend from no-op stub to tracking stub (bootstrapCalled, bootstrapCfg, bootstrapResult)
  • Three new dispatch tests: dispatch+result shape, nil-result safety, nil-cfg-arg safety

Root cause

v0.7.4 added DOProvider.BootstrapStateBackend (the Go interface method and implementation) but did not add the corresponding InvokeMethod switch case. The gRPC layer routes calls by string method name — without the case, every call from wfctl hits the default branch and returns the "unknown method" error.

Test plan

  • GOWORK=off go test -race -short -count=1 ./internal/... — all pass
  • TestDoModuleInstance_InvokeMethod_BootstrapStateBackend_Dispatches — verifies routing + bucket/region in result
  • TestDoModuleInstance_InvokeMethod_BootstrapStateBackend_NilResult — no panic on nil provider result
  • TestDoModuleInstance_InvokeMethod_BootstrapStateBackend_NilCfgArg — missing cfg defaults to {}

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 23, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a missing gRPC dispatch route for IaCProvider.BootstrapStateBackend in the DigitalOcean plugin module invoker, unblocking state-backend bootstrapping calls that were previously failing with an “unknown method” error.

Changes:

  • Adds "IaCProvider.BootstrapStateBackend" handling to doModuleInstance.InvokeMethod.
  • Introduces invokeProviderBootstrapStateBackend to decode cfg, call the provider, and return a map result safely.
  • Extends the fakeIaCProvider and adds new tests covering dispatch and nil-result / missing-cfg behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/module_instance.go Wires IaCProvider.BootstrapStateBackend into InvokeMethod via a new helper.
internal/module_instance_test.go Adds dispatch tests and upgrades fakeIaCProvider to track Bootstrap calls/inputs/outputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/module_instance.go Outdated
Comment on lines +218 to +220
cfg, _ := args["cfg"].(map[string]any)
if cfg == nil {
cfg = map[string]any{}

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invokeProviderBootstrapStateBackend will panic if InvokeMethod is called with a nil args map (since it indexes args["cfg"]). Since other InvokeMethod callers/tests sometimes pass nil args, this method should defensively treat nil args the same as an empty map (and ideally also surface a clearer error if cfg is present but not a map, instead of silently defaulting to {}).

Suggested change
cfg, _ := args["cfg"].(map[string]any)
if cfg == nil {
cfg = map[string]any{}
cfg := map[string]any{}
if args != nil {
if rawCfg, ok := args["cfg"]; ok {
if rawCfg != nil {
typedCfg, ok := rawCfg.(map[string]any)
if !ok {
return nil, fmt.Errorf("IaCProvider.BootstrapStateBackend: cfg must be a map[string]any")
}
cfg = typedCfg
}
}

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5945ba2: guarded args[cfg] index behind if args != nil — nil args now treated as empty map, consistent with how other invoke* helpers handle missing optional fields.

Comment on lines +714 to +726
func TestDoModuleInstance_InvokeMethod_BootstrapStateBackend_NilCfgArg(t *testing.T) {
// Missing cfg arg should be treated as empty map, not panic.
fake := &fakeIaCProvider{bootstrapResult: &interfaces.BootstrapResult{Bucket: "b"}}
mi := &doModuleInstance{provider: fake}

_, err := mi.InvokeMethod("IaCProvider.BootstrapStateBackend", map[string]any{})
if err != nil {
t.Fatalf("nil cfg arg should not error: %v", err)
}
if fake.bootstrapCfg == nil {
t.Error("expected non-nil cfg passed to provider (empty map)")
}
}

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new BootstrapStateBackend dispatch tests cover empty args (map[string]any{}), but not the nil-args case (InvokeMethod called with args == nil). Adding a regression test for nil args would catch the potential panic path and document the expected behavior when no args are supplied by the host.

Copilot generated this review using guidance from organization custom instructions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5945ba2: added TestDoModuleInstance_InvokeMethod_BootstrapStateBackend_NilArgs — calls InvokeMethod with nil args, asserts no panic/error, result non-nil, and bootstrapCalled=true.

… (v0.7.5)

Adds the missing switch case and invokeProviderBootstrapStateBackend helper
to doModuleInstance.InvokeMethod. The case was absent from v0.7.4 causing
wfctl's gRPC caller to receive "unknown method" on every bootstrap call.

Also promotes fakeIaCProvider.BootstrapStateBackend from a no-op stub to a
tracking stub (bootstrapCalled + bootstrapCfg + bootstrapResult), and adds
three dispatch tests:
- Dispatches_Dispatches: verifies call routing + result serialisation
- NilResult: provider returning (nil,nil) yields empty map, not panic
- NilCfgArg: missing cfg arg treated as empty map, not panic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@intel352
intel352 force-pushed the fix/v0.7.5-bootstrap-grpc-dispatch branch from 29e9594 to 5945ba2 Compare April 23, 2026 23:41
@intel352
intel352 merged commit 7d1a248 into main Apr 23, 2026
3 checks passed
intel352 added a commit that referenced this pull request May 17, 2026
Addresses Copilot findings on the workflow_dispatch escape-hatch PR:
- Add explicit tag regex validation (^vN.N.N(-suffix)?$) before any
  shell/Python interpolation — addresses 3 shell-injection inlines
  raised by Copilot across the 4 plugin PRs (gcp #12 line 26, DO #122
  lines 29 + 43, aws #19 line 26).
- DO only: restore the downloads[*].url update block that the prior
  push clobbered. DO has a regression-gate test
  TestSyncPluginVersionWorkflowUpdatesDownloads asserting the python
  block updates dl['url'] per release tag.
- aws/gcp/azure: NOT adding downloads-update because their goreleaser
  binary naming convention differs (`{name}_{version}_{goos}_{goarch}`
  vs DO's `{name}-{goos}-{goarch}`) — would create broken URLs. The
  downloads[] staleness is cosmetic; workflow-registry has authoritative
  download URLs.
intel352 added a commit that referenced this pull request May 17, 2026
* ci: add workflow_dispatch escape hatch to sync-plugin-version.yml

Defensive fix for the failure mode surfaced by workflow-plugin-aws#18:
sync-plugin-version.yml did not fire on a v1.2.0 tag push despite the
matching `tags: ['v*']` trigger that worked on v1.1.0. Root cause was
not identified (likely transient GitHub Actions backend hiccup); the
workaround was a manual one-line plugin.json sync PR.

This change adds a workflow_dispatch trigger taking a tag input so the
sync workflow can be manually re-fired when the push-tag trigger
silently no-ops. The same patch is being applied across all 4 IaC
plugin repos (aws/gcp/azure/digitalocean) since they share the workflow
file pattern.

The push-tag trigger path is unchanged; the manual dispatch path uses
`inputs.tag` and falls back to `github.ref_name` otherwise via the
`inputs.tag || github.ref_name` expression.

Closes workflow-plugin-aws#18 (defensive fix; no root cause identified).

* ci: add tag-format validation + restore downloads-update (DO only)

Addresses Copilot findings on the workflow_dispatch escape-hatch PR:
- Add explicit tag regex validation (^vN.N.N(-suffix)?$) before any
  shell/Python interpolation — addresses 3 shell-injection inlines
  raised by Copilot across the 4 plugin PRs (gcp #12 line 26, DO #122
  lines 29 + 43, aws #19 line 26).
- DO only: restore the downloads[*].url update block that the prior
  push clobbered. DO has a regression-gate test
  TestSyncPluginVersionWorkflowUpdatesDownloads asserting the python
  block updates dl['url'] per release tag.
- aws/gcp/azure: NOT adding downloads-update because their goreleaser
  binary naming convention differs (`{name}_{version}_{goos}_{goarch}`
  vs DO's `{name}-{goos}-{goarch}`) — would create broken URLs. The
  downloads[] staleness is cosmetic; workflow-registry has authoritative
  download URLs.
@intel352
intel352 deleted the fix/v0.7.5-bootstrap-grpc-dispatch branch June 20, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants