Add step.http_proxy for transparent reverse proxy in pipelines#226
Add step.http_proxy for transparent reverse proxy in pipelines#226
Conversation
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>
There was a problem hiding this comment.
Pull request overview
Adds a new pipeline step type (step.http_proxy) to transparently forward an incoming HTTP request to a backend resolved at runtime from the pipeline context, enabling “API-gateway-in-a-pipeline” patterns without JSON re-marshalling.
Changes:
- Introduces
module.HTTPProxyStep+ factory and a comprehensive test suite for proxy behavior. - Registers
step.http_proxyacross plugin manifest/factories, schema registries, andwfctltype registry. - Extends core step type lists / expectations to include the new step.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| schema/schema.go | Adds step.http_proxy to core module/step type list. |
| schema/module_schema.go | Registers schema metadata/config fields for step.http_proxy. |
| plugins/pipelinesteps/plugin.go | Exposes the new step type in plugin manifest and factory map. |
| plugins/pipelinesteps/plugin_test.go | Updates expected step list to include step.http_proxy. |
| module/pipeline_step_http_proxy.go | Implements the HTTP proxy pipeline step (request forwarding + response writing). |
| module/pipeline_step_http_proxy_test.go | Adds test coverage for proxying behavior, headers, query strings, and fallbacks. |
| cmd/wfctl/type_registry.go | Adds step.http_proxy to CLI-known step types and config keys. |
Comments suppressed due to low confidence (5)
schema/module_schema.go:959
- The Outputs description says the step returns only status/target URL, but the implementation returns headers/body when no _http_response_writer is present. Update the schema description to reflect the conditional outputs so users relying on schema generation aren't misled.
Outputs: []ServiceIODef{{Name: "result", Type: "StepResult", Description: "Proxy response status and target URL; Stop is always true"}},
ConfigFields: []ConfigFieldDef{
module/pipeline_step_http_proxy.go:88
- Target URL construction is done via string concatenation. This breaks for valid backend URLs that include query/fragment components (and can produce incorrectly escaped paths). Prefer parsing backendURL with net/url and joining paths via ResolveReference/url.JoinPath (and validate the URL is absolute) before creating the proxy request.
// Build the target URL
targetURL := strings.TrimRight(backendURL, "/")
if resource != "" {
targetURL += "/" + strings.TrimLeft(resource, "/")
}
module/pipeline_step_http_proxy.go:96
- Query string forwarding always appends with "?". If the backend URL already has query params, this will produce an invalid URL (multiple '?') and drop/override existing params. Build the target URL via net/url and merge queries instead of concatenation.
// Append original query string
if origReq != nil && origReq.URL.RawQuery != "" {
targetURL += "?" + origReq.URL.RawQuery
}
module/pipeline_step_http_proxy.go:145
- The proxy reads the entire upstream response into memory (io.ReadAll) before writing it to the client. For a transparent proxy step this can cause high memory usage and latency for large/binary responses. When a ResponseWriter is present, stream the response body to the client (e.g., io.Copy) instead of buffering it all first.
// Read the backend response body
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("http_proxy step %q: failed to read proxy response: %w", s.name, err)
}
module/pipeline_step_http_proxy.go:155
- Copying all upstream response headers directly to the client can forward hop-by-hop headers (e.g., Connection/Transfer-Encoding/Upgrade) that should not be relayed, and using Add can also duplicate headers unexpectedly. Consider filtering hop-by-hop headers (or using httputil.ReverseProxy) to match standard reverse-proxy behavior.
// Copy backend response headers
for k, vals := range resp.Header {
for _, v := range vals {
w.Header().Add(k, v)
}
}
|
@copilot apply changes based on the comments in this thread Also address failing build, failing lint, and config validation |
Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Fixed in 95d5f72. The schema |
Breaking CI build and config validation. |
Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
module/pipeline_step_http_proxy.go- the step implementationmodule/pipeline_step_http_proxy_test.go- comprehensive tests (13 test cases)plugins/pipelinesteps/plugin.go(StepTypes manifest + StepFactories map)schema/module_schema.goschema/schema.go(coreModuleTypes list)cmd/wfctl/type_registry.gogo mod tidyon example module to sync transitive dependencies (eventbus/v2 v2.1.0, sarama v1.47.0)Original prompt
🔒 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.