Skip to content

feat(workflows): http step type (webhook alias) with retries - #2641

Merged
Andriy Knysh (aknysh) merged 8 commits into
mainfrom
osterman/webhook-step-type
Jun 24, 2026
Merged

Andriy Knysh (aknysh) merged 8 commits into
mainfrom
osterman/webhook-step-type

Conversation

@osterman

@osterman Erik Osterman (Cloud Posse) (osterman) commented Jun 20, 2026 •

Copy link
Copy Markdown
Member

what

  • Add a native http workflow/custom-command step (type: http) that performs an HTTP request — any verb (GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS), query string parameters, headers, and a request body via body (raw) or form (urlencoded, or JSON when Content-Type is JSON).
  • Keep webhook as a first-class alias for http (type: webhook behaves identically) for the fire-a-notification use case. This adds alias support to the step registry: NewBaseHandler is variadic for aliases, Get() resolves aliases, and List/Count report only the canonical entry (no duplicate step type).
  • Per-attempt timeout and retry that composes with the existing retry: policy; retry is HTTP-aware (transport errors, 5xx, and 429 retry by default, other 4xx fail fast, and retry.conditions regexes force additional cases).
  • Configurable success criteria via expect.status (codes) and expect.response (regexes); the response body and status are captured as the step's value/metadata for downstream steps.
  • Schema fields on WorkflowStep and Task (so it works in both workflows and custom commands) plus the HTTPExpect struct, ErrHTTPStep* sentinels, JSON manifest updates, docs, an examples/http-webhooks example, a changelog blog post, and a roadmap milestone.

why

  • Calling external endpoints (notify a service, trigger a CI job, hit a deployment webhook, poll a health check) previously required shelling out to curl, which isn't portable (Windows), is awkward to template, and gets no first-class timeout/retry handling.
  • The step is a general-purpose, verb-agnostic outbound HTTP client, so http is the accurate name (an inbound callback receiver is what "webhook" conventionally means); webhook is retained as an alias so the evocative name still works.
  • Extended/registry step types are not wrapped by the legacy retry.Do path that shell/atmos use, so the handler applies retry itself via retry.WithPredicate — which is what enables status-code-aware retry decisions a generic wrapper can't make.

references

Add a native `type: webhook` step for workflows and custom commands that
performs an HTTP request (GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS) with
query-string parameters, headers, and a request body (raw or form/JSON).

Requests get a per-attempt timeout and retries that compose with the
existing `retry:` policy. Because extended/registry step types are not
wrapped by the legacy retry.Do path, the handler applies retry itself via
retry.WithPredicate with HTTP-aware classification: transport errors, 5xx,
and 429 retry by default; other 4xx fail fast; retry.conditions regexes
force additional cases. Success criteria are configurable via expect.status
and expect.response (regex). The response body and status are captured as
step value/metadata for downstream steps.

Includes schema fields on WorkflowStep and Task, JSON manifest updates,
docs, an example, a changelog blog post, and a roadmap milestone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@atmos-pro

atmos-pro Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

No affected stacks workflow was detected for this pull request.
If this is expected, no action is needed.
Learn More. Ask AI.

@osterman Erik Osterman (Cloud Posse) (osterman) added the minor New features that do not break anything label Jun 20, 2026
@github-actions github-actions Bot added the size/l Large size PR label Jun 20, 2026
@github-actions

github-actions Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 755e1d9d-ddf7-41ad-a261-c26d025f3875

📥 Commits

Reviewing files that changed from the base of the PR and between 1944bf7 and 6e96f6d.

📒 Files selected for processing (5)
  • errors/errors.go
  • pkg/schema/workflow.go
  • website/docs/workflows/_partials/_step-types.mdx
  • website/docs/workflows/workflows/workflow/steps/type.mdx
  • website/src/data/roadmap.js
✅ Files skipped from review due to trivial changes (3)
  • website/docs/workflows/workflows/workflow/steps/type.mdx
  • website/docs/workflows/_partials/_step-types.mdx
  • website/src/data/roadmap.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • errors/errors.go
  • pkg/schema/workflow.go

📝 Walkthrough

Walkthrough

Adds a native http workflow step type with alias webhook, request execution, retry handling, schema support, registry aliasing, tests, examples, and documentation.

Changes

HTTP Step Type

Layer / File(s) Summary
Schema contracts and sentinel errors
errors/errors.go, pkg/schema/workflow.go, pkg/schema/task.go
Adds HTTPExpect plus HTTP/webhook fields on WorkflowStep and Task, wires conversion between them, and defines sentinel errors for HTTP validation and execution failures.
JSON Schema for HTTP steps
pkg/datafetcher/schema/atmos/manifest/1.0.json
Extends the manifest schema with HTTP/webhook step properties, conditional required fields, and retry.conditions regex strings.
Step registry alias support
pkg/runner/step/handler_base.go, pkg/runner/step/registry.go
Adds alias storage to BaseHandler and registry alias lookup so webhook resolves to the HTTP handler.
HTTPHandler validation and execution
pkg/runner/step/http.go
Registers HTTPHandler, validates step config, runs HTTP requests with timeout and retry handling, and evaluates expected status/body outcomes.
Request building and retry helpers
pkg/runner/step/http.go
Builds request URLs, headers, query parameters, bodies, retry conditions, and timeout/client helpers.
HTTP handler unit tests
pkg/runner/step/http_test.go
Covers validation, request variants, expectation checks, retry behavior, templating, alias handling, timeout handling, and helper utilities.
End-to-end executor tests
pkg/runner/step/http_e2e_test.go
Runs HTTP workflows through StepExecutor against httptest servers and checks results, metadata, and retries.
Example workflows and docs
examples/http-webhooks/..., website/blog/..., website/docs/workflows/..., website/src/data/roadmap.js
Adds example workflows, step docs, retry docs, a blog post, and roadmap updates for the HTTP step type.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as Workflow Engine
  participant HTTPHandler
  participant RetryPolicy
  participant HTTPClient as http.Client
  participant Endpoint as Remote Endpoint

  Workflow->>HTTPHandler: Execute(ctx, step, vars)
  HTTPHandler->>HTTPHandler: buildHTTPRequest(step, vars)
  HTTPHandler->>HTTPHandler: resolveHTTPTimeout(step)
  HTTPHandler->>RetryPolicy: run with shouldRetryHTTP

  loop each attempt
    RetryPolicy->>HTTPHandler: performHTTPRequest(ctx + deadline)
    HTTPHandler->>HTTPClient: Do(req)
    HTTPClient->>Endpoint: HTTP request
    Endpoint-->>HTTPClient: response
    HTTPClient-->>HTTPHandler: response
    HTTPHandler->>HTTPHandler: read body, flatten headers
    HTTPHandler->>HTTPHandler: httpExpect.check(status, body)
    HTTPHandler-->>RetryPolicy: result or httpError
  end

  RetryPolicy-->>HTTPHandler: final result or error
  HTTPHandler->>HTTPHandler: buildHTTPError()
  HTTPHandler-->>Workflow: StepResult or sentinel error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • cloudposse/atmos#1899: Extends the same step-handler registry and base-handler aliasing model used here.
  • cloudposse/atmos#1901: Shares the Task/WorkflowStep model wiring that this PR extends with HTTP fields.
  • cloudposse/atmos#2114: Touches workflow-step retry schema support that this PR extends with retry.conditions.

Suggested reviewers

  • aknysh
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding an http workflow step type with webhook alias and retry support.
Docstring Coverage ✅ Passed Docstring coverage is 83.16% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch osterman/webhook-step-type

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
pkg/runner/step/webhook_test.go (1)

356-382: ⚡ Quick win

Add the matching negative-path test for custom retry conditions.

You validate recovery on 400 when retry.conditions includes ^400 , but there’s no paired case proving 400 does not retry when that condition is absent.

As per coding guidelines, “Include negative-path tests for recovery logic: whenever a test verifies that a recovery/fallback triggers under condition X, add a corresponding test that verifies the recovery does NOT trigger when condition X is absent.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/runner/step/webhook_test.go` around lines 356 - 382, Add a negative-path
test that verifies a 400 status code does NOT retry when the retry condition is
absent or does not match. Create a new test function similar to
TestWebhookHandler_RetryConditions that sets up the same webhook server
returning 400 on the first call, but configure the step with either no retry
conditions or retry conditions that do not match 400 (e.g., a pattern like `^500
`). Verify that the handler.Execute call fails or returns an error on the first
attempt without retrying (by asserting that calls equals 1).

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/runner/step/webhook_test.go`:
- Line 107: The Get("webhook") function returns both a handler and a boolean
indicating success, but the code is ignoring the boolean return value with an
underscore. In each test where Get("webhook") is called (at lines 107, 141, 172,
200, 224, 256, 289, 318, 341, 370, 401, and 421), capture the boolean return
value instead of ignoring it and add an assertion to verify it is true, so that
if the webhook handler registration fails the test will fail with a clear error
message rather than panicking later when methods like Validate() are called on
the nil handler.
- Around line 163-166: The require.NoError call inside the httptest handler
goroutine passed to httptest.NewServer is unsafe because FailNow cannot be
called from non-test goroutines and can cause flaky failures. Instead of calling
require.NoError directly in the handler when r.ParseForm() is executed, declare
an error variable outside the handler, capture any error from r.ParseForm() into
it within the handler, and then check that error variable with require.NoError
in the main test scope after the server request completes. This ensures all
assertion operations happen in the test goroutine where they are safe.

In `@pkg/runner/step/webhook.go`:
- Around line 379-382: Replace the dynamic fmt.Errorf call on line 381 (and
similar dynamic error returns on lines 414, 428, 439, and 446) with static
sentinel errors from errors/errors.go. For each failure path (headers resolution
via ResolveEnvMap, query resolution, body resolution, form resolution, and JSON
encoding), identify or create the appropriate static sentinel error and use it
to wrap the original error properly, maintaining error chain information using
the existing error wrapping pattern in the codebase. Ensure all error return
statements follow the static-error contract to enable consistent errors.Is
handling.
- Around line 365-373: After the successful url.Parse call in the webhook
validation logic, add an explicit check to ensure the parsed URL is absolute
(has a scheme). If the URL is not absolute, immediately return an error with the
same error building pattern used for the parse error, including appropriate
context about step name and URL value, to fail fast with clean config feedback
rather than allowing relative URLs to proceed and fail later during client.Do
execution.
- Around line 238-241: The io.ReadAll(resp.Body) call on line 238 reads the
entire response body without any size limit, which can cause memory spikes with
large responses. Wrap resp.Body with io.LimitReader before passing it to
io.ReadAll to enforce a maximum read size. This prevents unbounded memory
consumption when processing webhook responses. If needed, you can optionally
detect and return a dedicated sentinel value when the response exceeds the
configured limit to distinguish between truncation and genuine errors.

In `@pkg/schema/workflow.go`:
- Line 105: The comment for the Method field in the workflow schema is missing
OPTIONS from the list of supported HTTP methods. Update the comment string for
the Method field to include OPTIONS in the enumerated list of supported HTTP
verbs, keeping the list consistent with what the webhook schema actually
supports. This ensures the documentation and comments accurately reflect the
available functionality.

---

Nitpick comments:
In `@pkg/runner/step/webhook_test.go`:
- Around line 356-382: Add a negative-path test that verifies a 400 status code
does NOT retry when the retry condition is absent or does not match. Create a
new test function similar to TestWebhookHandler_RetryConditions that sets up the
same webhook server returning 400 on the first call, but configure the step with
either no retry conditions or retry conditions that do not match 400 (e.g., a
pattern like `^500 `). Verify that the handler.Execute call fails or returns an
error on the first attempt without retrying (by asserting that calls equals 1).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eb22eef0-b10c-46f9-9460-d308c3a39a2e

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9754b and 1c0a6f3.

📒 Files selected for processing (14)
  • errors/errors.go
  • examples/workflow-webhook/README.md
  • examples/workflow-webhook/atmos.yaml
  • examples/workflow-webhook/workflows/webhook.yaml
  • pkg/datafetcher/schema/atmos/manifest/1.0.json
  • pkg/runner/step/webhook.go
  • pkg/runner/step/webhook_e2e_test.go
  • pkg/runner/step/webhook_test.go
  • pkg/schema/task.go
  • pkg/schema/workflow.go
  • website/blog/2026-06-20-webhook-step-type.mdx
  • website/docs/workflows/_partials/_step-types.mdx
  • website/docs/workflows/workflows.mdx
  • website/src/data/roadmap.js

Comment thread pkg/runner/step/webhook_test.go Outdated
Comment thread pkg/runner/step/http_test.go
Comment thread pkg/runner/step/webhook.go Outdated
Comment thread pkg/runner/step/http.go
Comment thread pkg/runner/step/http.go
Comment thread pkg/schema/workflow.go Outdated
@codecov

codecov Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.35447% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.41%. Comparing base (33f92ff) to head (6e96f6d).

Files with missing lines Patch % Lines
pkg/runner/step/http.go 90.68% 21 Missing and 9 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2641      +/-   ##
==========================================
+ Coverage   80.36%   80.41%   +0.05%     
==========================================
  Files        1399     1400       +1     
  Lines      132224   132569     +345     
==========================================
+ Hits       106267   106611     +344     
+ Misses      20076    20066      -10     
- Partials     5881     5892      +11     
Flag Coverage Δ
unittests 80.41% <91.35%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
errors/errors.go 100.00% <ø> (ø)
pkg/runner/step/handler_base.go 98.73% <100.00%> (+0.06%) ⬆️
pkg/runner/step/registry.go 100.00% <100.00%> (ø)
pkg/schema/task.go 95.98% <100.00%> (+0.26%) ⬆️
pkg/schema/workflow.go 68.42% <ø> (ø)
pkg/runner/step/http.go 90.68% <90.68%> (ø)

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Replace dynamic fmt.Errorf returns with static sentinel errors
  (ErrTemplateEvaluation / ErrWebhookRequestFailed) per the static-error
  contract.
- Bound webhook response-body reads with io.LimitReader (4 MiB) to avoid
  memory blowups on large/error responses.
- Reject relative URLs in buildWebhookRequest so they fail fast instead of
  being retried as transport errors.
- Add OPTIONS to the Method field comment to match supported verbs.
- Add mustGetWebhookHandler helper asserting registration; move ParseForm
  assertion out of the httptest handler goroutine.
- Expand tests to cover error/helper paths, raising patch coverage above the
  80% gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 20, 2026
The step is a general-purpose, verb-agnostic outbound HTTP client, not an
inbound webhook receiver. Rename the canonical type to `http` and keep
`webhook` as a working alias for the fire-a-notification use case.

- Add first-class alias support to the step registry: NewBaseHandler is now
  variadic for aliases, Get() resolves aliases, and List/Count report only the
  canonical entry (no duplicate step). Aliases are exposed via an optional
  GetAliases() interface so the StepHandler interface (and its mock) are
  unchanged.
- Rename webhook.go/test/e2e -> http*.go and all Webhook*/webhook* symbols to
  HTTP*/http*; register as "http" with "webhook" alias.
- Rename WebhookExpect -> HTTPExpect (workflow.go, task.go) and the 7
  ErrWebhook* sentinels -> ErrHTTPStep* in errors/errors.go.
- JSON manifest: url-required conditional now matches type in [http, webhook];
  descriptions updated to "http step type".
- Rename example examples/workflow-webhook -> examples/http-webhooks (type:
  http, webhook noted as alias).
- Docs/blog/roadmap: step-types reference, retry.conditions link, blog slug
  http-step-type, roadmap changelog slug; all note the webhook alias.
- Add a contract test asserting the webhook alias resolves to the http handler
  and is not listed as a distinct step type.
- Drive-by: extract a const for a repeated "secret %s" literal in
  azure_keyvault_store.go to satisfy the repo-wide lint hook.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mergify

mergify Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Jun 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/runner/step/http.go (1)

532-540: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Reject non-positive timeouts so they fail fast.

If timeout resolves to 0s or a negative value, context.WithTimeout in Execute produces an already-expired context. Every attempt then returns DeadlineExceeded, which shouldRetryHTTP treats as a retryable transport error, so the step burns through all retries instantly and surfaces a misleading "request failed" message. A quick guard gives clear config feedback instead.

🛡️ Suggested guard
 	parsed, err := time.ParseDuration(resolved)
 	if err != nil {
 		return 0, errUtils.Build(errUtils.ErrInvalidDuration).
 			WithCause(err).
 			WithContext("step", step.Name).
 			WithContext("value", resolved).
 			Err()
 	}
+	if parsed <= 0 {
+		return 0, errUtils.Build(errUtils.ErrInvalidDuration).
+			WithContext("step", step.Name).
+			WithContext("value", resolved).
+			WithHint("Set 'timeout' to a positive duration (e.g. 30s)").
+			Err()
+	}
 	return parsed, nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/runner/step/http.go` around lines 532 - 540, The timeout parsing function
needs to validate that the parsed duration is positive before returning it.
After the time.ParseDuration call succeeds, add a guard check to ensure the
parsed duration is greater than zero. If the parsed duration is less than or
equal to zero, return an error using the same errUtils.Build pattern already
shown in the code, with appropriate context about the step name and invalid
timeout value. This guard should be placed immediately after the successful
parse and before the return statement to provide clear configuration feedback
instead of misleading retry failures.
🧹 Nitpick comments (2)
pkg/runner/step/http_test.go (1)

49-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add compile-time schema field sentinels for test contracts.

These tests rely heavily on schema.WorkflowStep/schema.HTTPExpect field names but do not include compile guards. Add package-level sentinels so schema field renames fail at compile time.

Suggested minimal guard block
+var (
+	_ = schema.WorkflowStep{
+		Name: "", Type: "", URL: "", Method: "",
+		Headers: map[string]string{}, Query: map[string]string{},
+		Body: "", Form: map[string]string{}, Timeout: "", Retry: &schema.RetryConfig{},
+		Expect: &schema.HTTPExpect{Status: []int{}, Response: []string{}},
+	}
+	_ = schema.HTTPExpect{Status: []int{}, Response: []string{}}
+)

As per coding guidelines, “Add compile-time sentinels for schema field references in tests … so a field rename immediately fails the build.”

Also applies to: 235-248, 470-470

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/runner/step/http_test.go` around lines 49 - 92, Add compile-time schema
field sentinels at the package level in the test file to ensure that schema
field renames fail the build immediately. Create a sentinel function that
references all the schema fields used in the TestHTTPHandler_Validate test (such
as Name, Type, URL, Method, Body, Form, Expect, Status, and Response fields from
schema.WorkflowStep and schema.HTTPExpect structs) by accessing them directly on
empty struct instances. This guard function will cause compilation to fail if
any of these field names are renamed in the schema, preventing silent test
failures. Add this sentinel function near the top of the test file after the
package declaration.

Source: Coding guidelines

pkg/runner/step/http.go (1)

543-556: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Release idle connections after each Execute.

A fresh http.Transport is built per Execute call, and nothing tears its connection pool down, so idle sockets linger until httpIdleTimeout (30s). A workflow with many http steps can stack these up. A one-liner in Execute keeps things tidy.

♻️ Suggested cleanup in Execute
 	client := newHTTPClient()
+	defer client.CloseIdleConnections()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/runner/step/http.go` around lines 543 - 556, Fresh http.Transport
instances are created per Execute call by the newHTTPClient() function, but
their connection pools are never cleaned up, causing idle sockets to linger
until the httpIdleTimeout expires. Add a call to CloseIdleConnections() on the
http.Transport in the Execute method after the HTTP request completes to
immediately release idle connections and prevent accumulation of sockets in
workflows with many HTTP steps.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/runner/step/http_test.go`:
- Around line 443-444: The hardcoded URL with port 1 is not deterministic across
different test runners and can cause intermittent failures. Replace the
`http://127.0.0.1:1` URL with a dynamically allocated but
guaranteed-to-be-closed port: create a temporary listener on `:0` which will be
assigned an available port, capture that address, close the listener, and then
use that address in the URL field for the test request. This ensures the port
will refuse connections deterministically since it was just released by the
closed listener.

---

Outside diff comments:
In `@pkg/runner/step/http.go`:
- Around line 532-540: The timeout parsing function needs to validate that the
parsed duration is positive before returning it. After the time.ParseDuration
call succeeds, add a guard check to ensure the parsed duration is greater than
zero. If the parsed duration is less than or equal to zero, return an error
using the same errUtils.Build pattern already shown in the code, with
appropriate context about the step name and invalid timeout value. This guard
should be placed immediately after the successful parse and before the return
statement to provide clear configuration feedback instead of misleading retry
failures.

---

Nitpick comments:
In `@pkg/runner/step/http_test.go`:
- Around line 49-92: Add compile-time schema field sentinels at the package
level in the test file to ensure that schema field renames fail the build
immediately. Create a sentinel function that references all the schema fields
used in the TestHTTPHandler_Validate test (such as Name, Type, URL, Method,
Body, Form, Expect, Status, and Response fields from schema.WorkflowStep and
schema.HTTPExpect structs) by accessing them directly on empty struct instances.
This guard function will cause compilation to fail if any of these field names
are renamed in the schema, preventing silent test failures. Add this sentinel
function near the top of the test file after the package declaration.

In `@pkg/runner/step/http.go`:
- Around line 543-556: Fresh http.Transport instances are created per Execute
call by the newHTTPClient() function, but their connection pools are never
cleaned up, causing idle sockets to linger until the httpIdleTimeout expires.
Add a call to CloseIdleConnections() on the http.Transport in the Execute method
after the HTTP request completes to immediately release idle connections and
prevent accumulation of sockets in workflows with many HTTP steps.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fe68410d-4772-496a-82d7-8074d62bed0e

📥 Commits

Reviewing files that changed from the base of the PR and between f3df30c and 955725f.

📒 Files selected for processing (17)
  • errors/errors.go
  • examples/http-webhooks/README.md
  • examples/http-webhooks/atmos.yaml
  • examples/http-webhooks/workflows/http.yaml
  • pkg/datafetcher/schema/atmos/manifest/1.0.json
  • pkg/runner/step/handler_base.go
  • pkg/runner/step/http.go
  • pkg/runner/step/http_e2e_test.go
  • pkg/runner/step/http_test.go
  • pkg/runner/step/registry.go
  • pkg/schema/task.go
  • pkg/schema/workflow.go
  • pkg/store/azure_keyvault_store.go
  • website/blog/2026-06-20-http-step-type.mdx
  • website/docs/workflows/_partials/_step-types.mdx
  • website/docs/workflows/workflows.mdx
  • website/src/data/roadmap.js
💤 Files with no reviewable changes (1)
  • examples/http-webhooks/atmos.yaml
✅ Files skipped from review due to trivial changes (5)
  • examples/http-webhooks/README.md
  • website/docs/workflows/_partials/_step-types.mdx
  • website/docs/workflows/workflows.mdx
  • pkg/store/azure_keyvault_store.go
  • website/blog/2026-06-20-http-step-type.mdx
🚧 Files skipped from review as they are similar to previous changes (3)
  • website/src/data/roadmap.js
  • pkg/datafetcher/schema/atmos/manifest/1.0.json
  • pkg/schema/task.go

Comment thread pkg/runner/step/http_test.go Outdated
…-type

# Conflicts:
#	pkg/store/azure_keyvault_store.go
@mergify mergify Bot removed the conflict This PR has conflicts label Jun 23, 2026
@osterman Erik Osterman (Cloud Posse) (osterman) changed the title feat(workflows): webhook step type with timeouts and retries feat(workflows): http step type (webhook alias) with retries Jun 23, 2026
@mergify

mergify Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Jun 24, 2026
…k-step-type

Integrates PR #2626, which deleted the monolithic workflows.mdx/commands.mdx
docs and replaced them with a nested per-topic structure where each step type
gets its own page under workflows/workflow/steps/type/<name>.mdx.

Conflict resolution:
- pkg/schema/{workflow,task}.go: keep both the HTTP step fields (URL/Method/
  Headers/Query/Body/Form/Expect) and main's new container step fields +
  Outputs, including the Task<->WorkflowStep conversions.
- Adopt main's new docs structure; drop the now-obsolete edits to the deleted
  monolithic workflows.mdx and the old _step-types.mdx layout.

Refactor the http step docs to the new convention:
- Add website/docs/workflows/workflows/workflow/steps/type/http.mdx (Intro +
  fields + polling + result, matching sibling pages).
- Register http in the _step-types.mdx overview and the steps/type.mdx Command
  Types table; note the webhook alias.
- Migrate the retry.conditions reference into steps/retry.mdx.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 24, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 24, 2026
@mergify

mergify Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Jun 24, 2026
@aknysh
Andriy Knysh (aknysh) merged commit a622ff6 into main Jun 24, 2026
69 checks passed
@aknysh
Andriy Knysh (aknysh) deleted the osterman/webhook-step-type branch June 24, 2026 21:10
@atmos-pro

atmos-pro Bot commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

No affected stacks workflow was detected for this pull request.
If this is expected, no action is needed.
Learn More. Ask AI.

@github-actions

Copy link
Copy Markdown

These changes were released in v1.222.0-rc.9.

This branch was successfully deployed

1 active deployment
preview — 6e96f6d6 Deployed Jun 24, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor New features that do not break anything size/l Large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants