Skip to content

RemoteStep: resolve template expressions in step config before gRPC call#217

Merged
intel352 merged 5 commits intomainfrom
copilot/resolve-template-expressions
Mar 1, 2026
Merged

RemoteStep: resolve template expressions in step config before gRPC call#217
intel352 merged 5 commits intomainfrom
copilot/resolve-template-expressions

Conversation

Copy link
Contributor

Copilot AI commented Mar 1, 2026

  • Modify plugin/external/proto/plugin.proto to add config field (field 6) to ExecuteStepRequest
  • Regenerate plugin.pb.go and plugin_grpc.pb.go from updated proto
  • Update RemoteStep struct to store raw config map; update NewRemoteStep to accept config
  • Update RemoteStep.Execute() to resolve template expressions using TemplateEngine.ResolveMap() and include resolved config in gRPC request
  • Update adapter.go to pass config to NewRemoteStep
  • Update sdk/interfaces.go StepInstance.Execute() to include config map[string]any parameter
  • Update sdk/grpc_server.go ExecuteStep to pass resolved config from request to inst.Execute()
  • Update examples/external-plugin/main.go to match new interface
  • Write tests for the template resolution in RemoteStep.Execute()
  • Update docs (PLUGIN_DEVELOPMENT_GUIDE.md, PLUGIN_ARCHITECTURE.md)
  • Skip ResolveMap when s.config == nil so Config proto field is nil (not empty struct) for steps with no config
  • Include step name and handle in config resolve error message
  • Assert Config == nil in TestRemoteStep_Execute_NilConfig
Original prompt

This section details on the original issue you should resolve

<issue_title>RemoteStep: resolve template expressions in step config before gRPC call</issue_title>
<issue_description>## Problem

External plugin steps (via RemoteStep) don't get their config templates resolved. The config parameter passed to StepInstance.Execute() contains raw YAML config from factory time with unresolved {{ ... }} template expressions.

Built-in steps handle this internally — each has its own TemplateEngine and resolves templates within Execute(). But external plugin steps receive their config at CreateStep() time (factory), and the values never get re-resolved before each execution.

Impact

Plugin steps that need dynamic config values (e.g., user ID from a previous DB query step) receive literal strings like {{ index .steps "fetch-user" "row" "id" }} instead of the actual value.

Current Workaround

Use step.set (which resolves templates) before the plugin step to flatten values into current, then have the plugin step read from the current parameter instead of config.

# step.set resolves templates and merges into current
- name: set-claims
  type: step.set
  config:
    values:
      user_id: '{{ index .steps "fetch-user" "row" "id" }}'
# Plugin step reads from current["user_id"]
- name: generate-token
  type: step.bmw.generate_token

Proposed Fix

In plugin/external/remote_step.go RemoteStep.Execute(), resolve template expressions in the step's config map using the pipeline context before sending via gRPC. The ExecuteStepRequest proto could include a config field with the resolved config, or the step config could be template-resolved and passed alongside the existing fields.

Files

  • plugin/external/remote_step.goRemoteStep.Execute() sends TriggerData, StepOutputs, Current, Metadata but NOT template-resolved config
  • module/pipeline_template.goTemplateEngine.templateData() builds template data from pipeline context</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI and others added 3 commits March 1, 2026 08:52
Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix RemoteStep to resolve template expressions in step config RemoteStep: resolve template expressions in step config before gRPC call Mar 1, 2026
@intel352 intel352 marked this pull request as ready for review March 1, 2026 09:35
Copilot AI review requested due to automatic review settings March 1, 2026 09:35
Copy link
Contributor

Copilot AI left a comment

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 functional gap in the external plugin step system by ensuring step config templates are resolved against the live PipelineContext on each execution (matching built-in step behavior), and delivering that resolved config to plugins over gRPC.

Changes:

  • Extend ExecuteStepRequest with a new config field to carry per-execution, template-resolved step config.
  • Update host RemoteStep.Execute() to resolve templates in stored raw config before making the gRPC call.
  • Update the plugin SDK StepInstance.Execute() signature and server wiring to pass the resolved config through to plugin implementations; add tests + docs + example updates.

Reviewed changes

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

Show a summary per file
File Description
plugin/external/proto/plugin.proto Adds ExecuteStepRequest.config protobuf field for resolved config.
plugin/external/proto/plugin.pb.go Regenerated protobuf Go types reflecting the new config field.
plugin/external/proto/plugin_grpc.pb.go Regenerated gRPC bindings reflecting the updated request message.
plugin/external/remote_step.go Resolves step config templates per execution and sends resolved config via gRPC.
plugin/external/adapter.go Passes raw step config into NewRemoteStep so it can be resolved at execution time.
plugin/external/remote_step_test.go Adds unit tests validating resolved config behavior for RemoteStep.
plugin/external/sdk/interfaces.go Breaking change: StepInstance.Execute() now accepts a config map[string]any param.
plugin/external/sdk/grpc_server.go Passes req.Config through to StepInstance.Execute() on the plugin side.
examples/external-plugin/main.go Updates example plugin step to match the new Execute() signature.
docs/PLUGIN_DEVELOPMENT_GUIDE.md Documents the updated external-step execution flow including config resolution.
docs/PLUGIN_ARCHITECTURE.md Updates architecture/proto documentation for the new request field.
go.mod Promotes github.com/xdg-go/scram to a direct dependency (likely via tidy).

@intel352
Copy link
Contributor

intel352 commented Mar 1, 2026

@copilot apply changes based on the comments in this thread

… config test

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

plugin/external/remote_step.go:71

  • RemoteStep.Execute errors from the gRPC call (err != nil) and from the plugin response (resp.Error) don’t include the step name/handle. This makes it hard to identify which remote step failed when multiple plugin steps are present in a pipeline. Consider including s.name and s.handleID in these error messages (similar to the config-resolve error above).
	if err != nil {
		return nil, fmt.Errorf("remote step execute: %w", err)
	}
	if resp.Error != "" {
		return nil, fmt.Errorf("remote step execute: %s", resp.Error)
	}

@intel352 intel352 merged commit 0915b86 into main Mar 1, 2026
18 checks passed
@intel352 intel352 deleted the copilot/resolve-template-expressions branch March 1, 2026 13:36
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.

RemoteStep: resolve template expressions in step config before gRPC call

3 participants