Skip to content

ADR-0024: research a real AWS client for cloud-waste (Proposed) - #79

Merged
Nabzx merged 1 commit into
mainfrom
research/real-aws-client-78
Sep 5, 2026
Merged

Nabzx merged 1 commit into
mainfrom
research/real-aws-client-78

Conversation

@Nabzx

@Nabzx Nabzx commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Closes #78.

Research output only - ADR-0024, filed as Proposed. Not ready-for-agent yet; three genuine open questions need a grilling round first, same shape ADR-0021's research went through before its own build issue.

Findings

  • Address side unchanged from ADR-0020. DescribeAddresses/ReleaseAddress, both confirmed to support DryRun.
  • Instance/idle side: DescribeInstances, StopInstances, and CloudWatch GetMetricData (not GetMetricStatistics - it batches up to 500 metrics per call). Real shapes confirmed via botocore's service models.
  • A real gap, not just a number to re-check: AWS's own published Trusted Advisor algorithm counts a per-day CPU/network boolean across a 14-day lookback and flags on ≥4 days - not the single-average-checked-once shape IdleInstanceAdapter (Build idle-EC2-instance detection (v1.1) for cloud-waste, per ADR-0022 #73) actually implements. The 10%/5MB numbers were right; the shape around them wasn't. Likely a related naming gap too: the network threshold reads as a daily total (Sum), not the average avg_network_bytes implies.
  • Credentials: recommends NOT copying the Stripe-shaped pydantic-settings pattern. boto3's own credential chain already handles env vars/profiles/IAM roles/SSO correctly; re-wrapping it in a project-specific settings class would regress real users away from those.
  • Sandbox-first: DryRun gates the two mutating calls (confirmed present, plus on both read calls, though reads have no side effect to gate). GetMetricData has no DryRun at all (read-only). AWS gives a stronger double-gate than Stripe's key-prefix split - a real client can read a real account for real and still structurally never release/stop anything unless a second allow_live=True is passed.
  • Least-privilege IAM policy, concretely scoped: exactly ec2:DescribeAddresses, ec2:ReleaseAddress, ec2:DescribeInstances, ec2:StopInstances, cloudwatch:GetMetricData.
  • Testing: moto presented as a real alternative to ADR-0013's hand-monkeypatching pattern - a dedicated, actively-maintained library that simulates AWS at the transport layer, catching a class of bug hand-typed canned responses can't. Left open, not decided - a real dependency-vs-plumbing-coverage trade-off.

Open questions for a grilling round

  1. Faithful "≥4-of-14-days" algorithm vs. a documented v1 simplification - the one finding that touches already-shipped, tested code (Instance/IdleInstanceCandidate/detector.py).
  2. moto vs. hand-monkeypatching boto3.
  3. Whether the maintainer wants to spend anything running this for real - every call, including reads, is a genuinely billable AWS API call against a real account, unlike Stripe's free test-mode API.

FakeCloudClient stays the only thing any test, demo, or CI job in this repo talks to either way.

API mapping for both resource types, checked against the real botocore
service models: DescribeAddresses/ReleaseAddress unchanged from ADR-0020;
DescribeInstances/StopInstances/GetMetricData for the instance side -
GetMetricData, not GetMetricStatistics, since it batches up to 500 metrics
per call instead of one call per metric.

A real gap found, not just a number to re-check: AWS's own published Trusted
Advisor algorithm is a per-day boolean counted across a 14-day lookback
(flagged on >=4 days), not the single-average-checked-once shape
IdleInstanceAdapter actually implements today. The 10%/5MB numbers were
right; the shape of the check around them wasn't. Also likely a naming gap:
the network threshold reads as a daily total (CloudWatch Sum), not the
average avg_network_bytes implies.

Credentials: recommends NOT copying ADR-0003/0013's Stripe-shaped
pydantic-settings pattern - boto3's own credential chain already handles
profiles/IAM roles/SSO correctly, and re-wrapping it would regress real
users away from those. Sandbox-first: DryRun gates the two mutating calls
(confirmed present on both, plus on the two Describe calls); GetMetricData
has no DryRun at all since it's read-only - AWS gives a stronger double-gate
than Stripe's key-prefix split ever could, for free.

Left open for a grilling round, not decided here: faithful 4-of-14-days
algorithm vs. a documented v1 simplification (the one finding that touches
already-shipped code); moto vs. hand-monkeypatching boto3 for tests; and
whether the maintainer wants to spend anything running this for real, since
even a read is a billable AWS API call unlike Stripe's free test-mode API.

Filed as #78 (wayfinder:research). Not ready-for-agent yet.

Closes #78
@Nabzx
Nabzx merged commit 7f2b3d6 into main Sep 5, 2026
7 checks passed
@Nabzx
Nabzx deleted the research/real-aws-client-78 branch September 5, 2026 13:33
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.

Research a real AWS client for cloud-waste: API mapping, credentials, testing

1 participant