Skip to content

test(api): RI-exchange carve-out test reaches a live AWS STS/IMDS call under mutation #175

Description

@cristim

Summary

TestExecuteExchange_PlainAdminIsRefused (internal/api/ri_exchange_carveout_test.go, added in PR LeanerCloud/cloud-commitments-cli#1758) is fast and offline in the state we ship. But under mutation — with {ActionExecute, ResourceRIExchange} removed from adminCarvedOuts, which is exactly how the test is verified — execution proceeds past the permission gate and attempts a live AWS call:

failed to resolve cloud account scope: resolve source aws account for reshape scope:
sts get-caller-identity: operation error STS: GetCallerIdentity, exceeded maximum number
of attempts, 3, get identity: get credentials: failed to refresh cached credentials,
no EC2 IMDS role found, operation error ec2imds: GetMetadata, exceeded maximum number of
attempts, 3, request send failed, Get "http://169.254.169.254/latest/meta-data/iam/
security-credentials/": dial tcp 169.254.169.254:80: connect: host is down

Unmutated the carve-out refuses at the gate in ~1.3s and no call is made. The exposure exists only while someone re-runs the mutation matrix — but that is a routine verification step for this test, not an exotic one.

Why it is worth fixing

  1. Correctness, not just slowness. The 9.7s figure is a network timeout on a machine with no credentials. On a machine that has AWS credentials in the environment, that path resolves a live account identity. Nobody re-running a mutation matrix should have to think about which credentials are loaded.
  2. It is the mirror of a positive we recorded recently. PR fix(cli): apply --max-instances once run-wide, not per service and region cloud-commitments-cli#1725's guard hoist was called out in review specifically because it removed a live DescribeReservedDBInstances from the unit suite. This is the same class, introduced rather than removed.
  3. It makes the mutation matrix environment-dependent, which is the property that makes a verification step untrustworthy.

Mechanism NOT traced — deliberately

I established where it is not and stopped there rather than guessing:

  • The failure is in cloud-account scope resolution, which happens upstream of the executeExchangeFn seam at internal/api/handler.go:126-130 ("the RI exchange execution function injected by tests"). Injecting that seam alone would not prevent the call.
  • It is not reached through h.config, so stubbing mockStore cannot block it either — which is the obvious first guess and is wrong.

I have not read what constructs the STS client, so I am not proposing a mechanism. That is the expensive half and can be done fresh.

Suggested direction (unvalidated)

Either an injectable scope resolver on Handler, or a fail-fast when no credential source is configured under test, so the path errors immediately and locally instead of attempting network I/O. Whoever picks this up should trace the constructor first; the above is a starting point, not a design.

Reproduction

  1. Remove {ActionExecute, ResourceRIExchange} from adminCarvedOuts in internal/auth/types.go.
  2. go test -count=1 -run '^TestExecuteExchange_PlainAdminIsRefused$' ./internal/api/
  3. Observe the STS/IMDS error above and the ~9.7s runtime (vs ~1.3s unmutated).

Found while mutation-verifying PR LeanerCloud/cloud-commitments-cli#1758 (issue LeanerCloud/cloud-commitments-cli#1644).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions