Skip to content

fix: Validate the wait_for_action_attempt option - #573

Merged
razor-x merged 1 commit into
mainfrom
claude/ruby-sdk-audit-xbhaia-wait-option-validation
Nov 5, 2026
Merged

razor-x merged 1 commit into
mainfrom
claude/ruby-sdk-audit-xbhaia-wait-option-validation

Conversation

@razor-x

@razor-x razor-x commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

SDK audit finding M2. ActionAttemptResolver.wait_options returned nil for any value that was not a Hash or DeepHashAccessor, so:

  • wait_for_action_attempt: 1 or "true" (an env string) silently skipped waiting and skipped raising ActionAttemptFailedError on a failed attempt. The caller believed the door unlocked.
  • A string-keyed hash ({"timeout" => 120}) was accepted and read with symbol keys, so its options were ignored and the 5s / 0.5s defaults applied.
  • Seam.new(wait_for_action_attempt: nil) meant "don't wait" while nil on a route call meant "use the default".

Fix

Ported from seamapi/python#637. The resolver validates at construction (both Http::SingleWorkspace and Http::WithoutWorkspace) and again on every route call, raising Seam::Http::Options::SeamInvalidOptionsError with:

  • The wait_for_action_attempt option must be true, false, or a hash with "timeout" and "polling_interval" keys, got Integer
  • The wait_for_action_attempt option got an unknown key :poll_interval, expected "timeout" or "polling_interval"
  • The wait_for_action_attempt option :timeout must be a number, got String

Option keys are symbolized before being read, and a nil constructor value normalizes to the default (true). Also adds the missing require_relative "deep_hash_accessor" the resolver relied on transitively.

Stacked on #572 (both change action_attempt_resolver.rb).

Tests

New spec/seam_client/wait_for_action_attempt_option_spec.rb: constructor and per-call rejection with exact messages and no poll request, nil as default, string keys honored on the client and per call.

Revert-check against the previous source: 10 failures, including string-keyed options polling nine times against a 0.1s timeout and junk values returning without an error.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SQW83gyXeUG61RDrHEky97


Generated by Claude Code

Base automatically changed from claude/ruby-sdk-audit-xbhaia-poll-deadline to main November 5, 2026 19:39
Any wait_for_action_attempt value other than true, a Hash, or the client's
DeepHashAccessor fell through the resolver and returned the unresolved
action attempt, so 1 or "true" silently skipped both waiting and raising
on a failed attempt. A string-keyed options hash was accepted and then
read with symbol keys, so its timeout and polling_interval were ignored in
favor of the defaults, and passing nil to the constructor meant "do not
wait" while nil on a route call meant "use the default".

Reject anything but true, false, or a hash with numeric timeout and
polling_interval values, at construction on both clients and again on
each route call, symbolize the option keys before reading them, and
normalize a nil constructor value to the default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQW83gyXeUG61RDrHEky97
@razor-x
razor-x force-pushed the claude/ruby-sdk-audit-xbhaia-wait-option-validation branch from dcbcf13 to f064171 Compare November 5, 2026 19:55
@razor-x
razor-x merged commit 693fe99 into main Nov 5, 2026
30 checks passed
@razor-x
razor-x deleted the claude/ruby-sdk-audit-xbhaia-wait-option-validation branch November 5, 2026 20:41
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