Skip to content

Stop reimplementing region resolution; let the boto3 session do it - #29

Merged
art-dsit merged 9 commits into
mainfrom
region-handling-cleanup
Jul 9, 2026
Merged

Stop reimplementing region resolution; let the boto3 session do it#29
art-dsit merged 9 commits into
mainfrom
region-handling-cleanup

Conversation

@art-dsit

@art-dsit art-dsit commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Region was resolved by a hand-rolled os.getenv("AWS_REGION", os.getenv("AWS_DEFAULT_REGION", ...)) ladder in two places. It reimplements botocore's own resolution chain incompletely — it skips the active profile's ~/.aws/config — and schema.from_settings turned "no region configured" into a ValueError instead of the loud NoRegionError boto3 raises.

Fix: let the session resolve region. Build the client with region_name=config.region (an explicit override, or None to fall through the standard chain) and read the concrete value back off client.meta.region_name for the AMI lookup, the SSM client, and ProvisionedInstance/SandboxInstanceInfo. region stays instance data (kept on both dataclasses).

  • schema.from_settings: drop the AWS_REGION ladder and the required-region ValueError; region is now an optional override (None → session resolves).
  • DefaultEc2InstanceProvider: region is no longer a required config field; resolved off the ec2 client in create_instance and find_sandbox_instances (the latter's ladder was added by Bundle ProvisionedInstance through the sandbox env #16 and is now unnecessary).

Behavioural change (intentional)

boto3 reads the region from AWS_DEFAULT_REGION and ~/.aws/config, not AWS_REGION — unlike the AWS CLI and the JS/Go/Java SDKs. So anyone who was relying on AWS_REGION alone now gets a NoRegionError instead of a silently-defaulted region. This is the point of the change (fail loud, not wrong), and it's called out in the README and CHANGELOG. Set AWS_DEFAULT_REGION or INSPECT_EC2_SANDBOX_REGION.

Why AMI-error handling is in a "region" PR

The title is about region resolution, but the diff also translates InvalidAMIID.* (and empty-describe_images) into a clear ValueError with a fix hint. That's deliberate: a hardcoded AMI from another region is exactly the silent failure the old "eu-west-2"-style default masked — once region comes from the session, an eval that pins ami_id only runs in that AMI's region, and the raw boto error (InvalidAMIID.NotFound) doesn't say why. Covered by four new tests (both the ClientError and empty-Images paths, run-instances and describe-images).

@art-dsit
art-dsit force-pushed the bundle-provisioned-instance branch from 7e61f51 to fe39de8 Compare July 8, 2026 15:58
@art-dsit
art-dsit force-pushed the region-handling-cleanup branch from ca444c6 to 0d89f7b Compare July 9, 2026 08:29
art-dsit and others added 2 commits July 9, 2026 09:01
Region was resolved by a hand-rolled os.getenv("AWS_REGION",
"AWS_DEFAULT_REGION") ladder in ~two places. That reimplements botocore's
own chain incompletely (it skips the active profile's ~/.aws/config), and
schema.py turned "no region configured" into a ValueError instead of the
loud NoRegionError boto3 raises.

Let the session resolve region: build the client with
region_name=config.region (an explicit override, or None to fall through
the chain) and read the concrete value back off client.meta.region_name
for the AMI lookup, SSM client, and ProvisionedInstance/SandboxInstanceInfo.
region stays instance data.

- schema.from_settings: drop the AWS_REGION ladder + the required-region
  ValueError; region is now an optional override (None -> session resolves).
- DefaultEc2InstanceProvider: region no longer a required config field;
  resolve it off the ec2 client in create_instance and find_sandbox_instances.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Now that region is resolved from the boto3 chain rather than a required
config field, an eval that hardcodes ami_id (the README's recommended
"portable eval" shape) but is silent on region will pick up the runner's
AWS_DEFAULT_REGION. If that differs from the AMI's region, run_instances
fails with a raw InvalidAMIID.NotFound — opaque to someone running an eval
they didn't write.

Translate the AMI-not-found ClientError (and the empty describe_images
result on the volume_size path) into a ValueError naming the AMI, the
resolved region, and the fix (set INSPECT_EC2_SANDBOX_REGION, or omit
ami_id to auto-resolve for the region).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@art-dsit
art-dsit force-pushed the region-handling-cleanup branch from 0d89f7b to dadf275 Compare July 9, 2026 09:01
@art-dsit
art-dsit changed the base branch from bundle-provisioned-instance to main July 9, 2026 09:01
art-dsit added 2 commits July 9, 2026 09:05
Both spots explained an absence rather than adding information beyond
what the surrounding code already shows.
Each call site already explains the resolve-then-read-back pattern
inline; the docstring version just repeated it while emphasizing what
used to be required.
@art-dsit
art-dsit marked this pull request as ready for review July 9, 2026 09:21
art-dsit and others added 4 commits July 9, 2026 10:02
The README and the config comment listed the resolution chain as
"AWS_REGION / AWS_DEFAULT_REGION / ~/.aws/config", but boto3 does not read
AWS_REGION — botocore binds the region config variable to AWS_DEFAULT_REGION
only (unlike the AWS CLI and the JS/Go/Java SDKs). A user setting only
AWS_REGION gets a NoRegionError, not the region they expect.

Signpost boto3's own configuration guide for the chain rather than
duplicating it, and state the AWS_REGION gotcha once, prominently, in the
README. Drop the enumerated chain from the schema comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The AMI/region-mismatch translation lived only on the run_instances path.
When volume_size is set, create_instance first calls describe_images (via
_root_device_name) to find the root device, and a foreign-region AMI makes
describe_images *raise* InvalidAMIID.NotFound rather than return an empty
list — so the raw botocore ClientError leaked with a traceback instead of
the region-scoped hint. (The old comment claimed describe_images returns []
for a foreign-region AMI; that's actually the private/deregistered case.)

Wrap describe_images with the same _AMI_NOT_FOUND_CODES translation and keep
the empty-list branch for the can't-see-this-AMI case. Verified e2e against a
real eu-west-1 AMI requested in eu-west-2 with volume_size set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/ec2sandbox/schema.py

# Optional explicit region override. None -> the boto3 session resolves the
# region when it builds a client (see README); a set value overrides that.
region: Optional[str] = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: i think the Optional[str] syntax is out-of-date and str | None is favoured (although I can see this line is just moved from below)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'll leave it for now as it would need changing everywhere, but maybe do as a later refactor

@dpolatajko-aisi dpolatajko-aisi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lgtm

Comment thread src/ec2sandbox/_instance_provider.py Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: the comment here is no longer accurate

@art-dsit
art-dsit merged commit 1c75eba into main Jul 9, 2026
3 checks passed
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