Skip to content

Commit 9bf88e3

Browse files
strefethenclaude
andcommitted
feat(examples): add comprehensive httpbin workflow examples
Five new Arazzo specs targeting httpbin.org for live integration testing: - httpbin-auth: basic auth, bearer tokens, 401 error recovery - httpbin-conditions: ==, !=, <, >=, contains, &&, || operators - httpbin-error-handling: retry exhaustion, criteria routing, workflow- level failureActions, goto error recovery - httpbin-methods: POST/PUT/PATCH/DELETE with JSON request bodies - httpbin-data-flow: output chaining, {$expr} interpolation, custom headers, cookie parameters, sub-workflow invocation 20 workflows pass, 3 expected-fail (retry exhaustion, workflow-level end, bearer-no-token). Updated FINDINGS.md with float input bug (P2). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2b0dd69 commit 9bf88e3

File tree

6 files changed

+541
-10
lines changed

6 files changed

+541
-10
lines changed

FINDINGS.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
# Findings
22

3-
## P1 — Nil pointer panic in handleStepResult when sub-workflow fails criteria with no OnFailure handler
4-
- **File**: `runtime/engine.go`, ~line 482
5-
- **Severity**: P1 (broken functionality)
6-
- **Repro**: Sub-workflow step returns `stepResult{success: false}` (no response) → no OnFailure handler → `result.response.Body` panics
7-
- **Fix**: Add nil guard for `result.response` before accessing `.Body` and `.StatusCode`
3+
## P2 — Numeric CLI inputs serialize as floats in URL paths
84

9-
## P2 — getCompiledRegex double-compile in parallel mode
10-
- **File**: `runtime/engine.go`, ~line 715-724
11-
- **Severity**: P2 (wasted work, no correctness impact)
12-
- **Repro**: Two goroutines miss cache simultaneously, both compile and store the same pattern
13-
- **Fix**: Use `regexCache.LoadOrStore` instead of separate `Load` + `Store`
5+
- **Files:** `crates/arazzo-cli/src/main.rs` (input parsing), `crates/arazzo-runtime/src/runtime_core/engine_impl.rs` (path param interpolation)
6+
- **Severity:** P2 (degraded behavior — workflows with numeric path inputs produce invalid URLs)
7+
- **Repro:** `cargo run -p arazzo-cli -- run examples/httpbin-get.arazzo.yaml status-check -i code=200` → URL becomes `/status/200.0` instead of `/status/200`
8+
- **Root cause:** The `-i key=value` flag parses values through serde_yaml, which converts `200` to `f64(200.0)`. When interpolated into URL path parameters, the float renders as `"200.0"`.
9+
- **Fix:** Either parse CLI input values as raw strings, or add integer-aware formatting in the path parameter interpolation (`value_to_string` should format whole floats without `.0` suffix).

examples/httpbin-auth.arazzo.yaml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
arazzo: 1.0.0
2+
info:
3+
title: HTTPBin Authentication Tests
4+
version: 1.0.0
5+
description: >
6+
Tests authentication patterns against httpbin.org including basic auth,
7+
bearer tokens, and auth failure handling with error recovery.
8+
sourceDescriptions:
9+
- name: httpbin
10+
url: https://httpbin.org
11+
type: openapi
12+
workflows:
13+
- workflowId: basic-auth-success
14+
summary: Correct basic auth credentials return 200
15+
steps:
16+
- stepId: authenticate
17+
operationPath: /basic-auth/{user}/{passwd}
18+
parameters:
19+
- name: user
20+
in: path
21+
value: "testuser"
22+
- name: passwd
23+
in: path
24+
value: "testpass"
25+
- name: Authorization
26+
in: header
27+
value: "Basic dGVzdHVzZXI6dGVzdHBhc3M="
28+
successCriteria:
29+
- condition: $statusCode == 200
30+
outputs:
31+
authenticated: $response.body.authenticated
32+
user: $response.body.user
33+
outputs:
34+
authenticated: $steps.authenticate.outputs.authenticated
35+
user: $steps.authenticate.outputs.user
36+
37+
- workflowId: basic-auth-failure
38+
summary: Wrong credentials trigger 401, error handler recovers
39+
steps:
40+
- stepId: bad-auth
41+
operationPath: /basic-auth/{user}/{passwd}
42+
parameters:
43+
- name: user
44+
in: path
45+
value: "testuser"
46+
- name: passwd
47+
in: path
48+
value: "testpass"
49+
- name: Authorization
50+
in: header
51+
value: "Basic d3Jvbmc6Y3JlZHM="
52+
successCriteria:
53+
- condition: $statusCode == 200
54+
onFailure:
55+
- type: goto
56+
stepId: handle-auth-error
57+
criteria:
58+
- condition: $statusCode == 401
59+
- type: end
60+
- stepId: handle-auth-error
61+
operationPath: /get
62+
successCriteria:
63+
- condition: $statusCode == 200
64+
outputs:
65+
recovery: $response.body.url
66+
outputs:
67+
recovery: $steps.handle-auth-error.outputs.recovery
68+
69+
- workflowId: bearer-auth
70+
summary: Bearer token authentication succeeds
71+
steps:
72+
- stepId: auth-with-token
73+
operationPath: /bearer
74+
parameters:
75+
- name: Authorization
76+
in: header
77+
value: "Bearer my-secret-api-token"
78+
successCriteria:
79+
- condition: $statusCode == 200
80+
outputs:
81+
authenticated: $response.body.authenticated
82+
token: $response.body.token
83+
outputs:
84+
authenticated: $steps.auth-with-token.outputs.authenticated
85+
token: $steps.auth-with-token.outputs.token
86+
87+
- workflowId: bearer-no-token
88+
summary: Missing bearer token triggers 401 and workflow ends cleanly
89+
steps:
90+
- stepId: no-token
91+
operationPath: /bearer
92+
successCriteria:
93+
- condition: $statusCode == 200
94+
onFailure:
95+
- type: end
96+
outputs: {}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
arazzo: 1.0.0
2+
info:
3+
title: HTTPBin Condition Expression Tests
4+
version: 1.0.0
5+
description: >
6+
Tests the full range of Arazzo condition expressions: comparison operators,
7+
string operators (contains, matches), and compound conditions (&&, ||).
8+
sourceDescriptions:
9+
- name: httpbin
10+
url: https://httpbin.org
11+
type: openapi
12+
workflows:
13+
- workflowId: status-code-comparisons
14+
summary: Test numeric comparison operators on status codes
15+
steps:
16+
- stepId: check-200
17+
operationPath: /status/200
18+
successCriteria:
19+
- condition: $statusCode == 200
20+
- condition: $statusCode != 404
21+
- condition: $statusCode < 300
22+
- condition: $statusCode >= 200
23+
- condition: $statusCode <= 200
24+
- condition: $statusCode > 199
25+
outputs: {}
26+
27+
- workflowId: body-string-equality
28+
summary: Verify response body string field equality
29+
steps:
30+
- stepId: fetch-data
31+
operationPath: /get
32+
parameters:
33+
- name: fruit
34+
in: query
35+
value: "apple"
36+
successCriteria:
37+
- condition: $statusCode == 200
38+
outputs:
39+
fruit: $response.body.args.fruit
40+
- stepId: verify-value
41+
operationPath: /get
42+
parameters:
43+
- name: check
44+
in: query
45+
value: $steps.fetch-data.outputs.fruit
46+
successCriteria:
47+
- condition: $statusCode == 200
48+
- condition: $response.body.args.check == "apple"
49+
outputs:
50+
fruit: $steps.fetch-data.outputs.fruit
51+
52+
- workflowId: contains-operator
53+
summary: Test the contains operator on response body strings
54+
steps:
55+
- stepId: fetch-url
56+
operationPath: /get
57+
successCriteria:
58+
- condition: $statusCode == 200
59+
- condition: '$response.body.url contains "httpbin"'
60+
- condition: '$response.body.headers.Host contains "httpbin"'
61+
outputs: {}
62+
63+
- workflowId: compound-conditions
64+
summary: Test && and || compound conditions
65+
steps:
66+
- stepId: success-range
67+
operationPath: /status/200
68+
successCriteria:
69+
- condition: $statusCode >= 200 && $statusCode < 300
70+
- stepId: fetch-with-or
71+
operationPath: /get
72+
successCriteria:
73+
- condition: $statusCode == 200 || $statusCode == 201
74+
outputs: {}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
arazzo: 1.0.0
2+
info:
3+
title: HTTPBin Data Flow, Chaining, and Sub-Workflows
4+
version: 1.0.0
5+
description: >
6+
Tests multi-step data chaining (output of one step feeds the next),
7+
expression interpolation in parameter values, custom headers,
8+
cookie parameters, and sub-workflow invocation with input/output passing.
9+
sourceDescriptions:
10+
- name: httpbin
11+
url: https://httpbin.org
12+
type: openapi
13+
workflows:
14+
- workflowId: chained-outputs
15+
summary: Step 1 output feeds into step 2 as a query parameter
16+
steps:
17+
- stepId: get-origin
18+
operationPath: /get
19+
successCriteria:
20+
- condition: $statusCode == 200
21+
outputs:
22+
origin: $response.body.origin
23+
- stepId: echo-origin
24+
operationPath: /get
25+
parameters:
26+
- name: caller_ip
27+
in: query
28+
value: $steps.get-origin.outputs.origin
29+
successCriteria:
30+
- condition: $statusCode == 200
31+
outputs:
32+
echoed_ip: $response.body.args.caller_ip
33+
outputs:
34+
origin: $steps.get-origin.outputs.origin
35+
echoed_ip: $steps.echo-origin.outputs.echoed_ip
36+
37+
- workflowId: interpolation
38+
summary: Expression interpolation in string values using {$expr} syntax
39+
inputs:
40+
type: object
41+
properties:
42+
greeting:
43+
type: string
44+
required:
45+
- greeting
46+
steps:
47+
- stepId: greet
48+
operationPath: /get
49+
parameters:
50+
- name: message
51+
in: query
52+
value: "{$inputs.greeting} from arazzo-cli"
53+
successCriteria:
54+
- condition: $statusCode == 200
55+
outputs:
56+
message: $response.body.args.message
57+
outputs:
58+
message: $steps.greet.outputs.message
59+
60+
- workflowId: custom-headers-and-cookies
61+
summary: Send custom headers and cookie parameters, verify they echo back
62+
steps:
63+
- stepId: send-headers
64+
operationPath: /headers
65+
parameters:
66+
- name: X-Custom-Header
67+
in: header
68+
value: "arazzo-test-value"
69+
- name: X-Arazzo-Test
70+
in: header
71+
value: "req-12345"
72+
successCriteria:
73+
- condition: $statusCode == 200
74+
outputs:
75+
custom_header: $response.body.headers.X-Custom-Header
76+
arazzo_test: $response.body.headers.X-Arazzo-Test
77+
- stepId: send-cookies
78+
operationPath: /cookies
79+
parameters:
80+
- name: session_id
81+
in: cookie
82+
value: "abc-123-def"
83+
- name: theme
84+
in: cookie
85+
value: "dark"
86+
successCriteria:
87+
- condition: $statusCode == 200
88+
outputs:
89+
session: $response.body.cookies.session_id
90+
theme: $response.body.cookies.theme
91+
outputs:
92+
custom_header: $steps.send-headers.outputs.custom_header
93+
arazzo_test: $steps.send-headers.outputs.arazzo_test
94+
session: $steps.send-cookies.outputs.session
95+
theme: $steps.send-cookies.outputs.theme
96+
97+
- workflowId: parent-workflow
98+
summary: Calls child-workflow with inputs and reads its outputs
99+
steps:
100+
- stepId: call-child
101+
workflowId: child-workflow
102+
parameters:
103+
- name: item_name
104+
value: "test-widget"
105+
- stepId: verify-child
106+
operationPath: /get
107+
parameters:
108+
- name: from_child
109+
in: query
110+
value: $steps.call-child.outputs.created_url
111+
successCriteria:
112+
- condition: $statusCode == 200
113+
outputs:
114+
child_result: $steps.call-child.outputs.created_url
115+
116+
- workflowId: child-workflow
117+
summary: Receives item_name input, creates it via POST, returns the URL
118+
inputs:
119+
type: object
120+
properties:
121+
item_name:
122+
type: string
123+
required:
124+
- item_name
125+
steps:
126+
- stepId: create-item
127+
operationPath: POST /post
128+
requestBody:
129+
contentType: application/json
130+
payload:
131+
name: $inputs.item_name
132+
successCriteria:
133+
- condition: $statusCode == 200
134+
outputs:
135+
created_url: $response.body.url
136+
outputs:
137+
created_url: $steps.create-item.outputs.created_url

0 commit comments

Comments
 (0)