Skip to content

cloud: cover the GCS external-account federation edge cases (URL source, workforce, impersonation, rejections) #338

Description

@smiggleworth

Gap cloud-24 · missing-coverage · confidence: verified · tracked in #242
Baseline: Midge 7d39f86 (0.1.1) vs Pants 2507c66. Midge paths are relative to the midge repo, Pants paths to this repo. Midge behavior is used as the proxy for the not-yet-extracted lsm-spec behavioral contract.

Prior: G10 (partially fixed: code is present, tests are missing), #7 (related)

Midge: src/storage/providers/gcs.rs tests
should_read_url_sourced_external_account_subject_token_with_headers (:3220),
should_send_workforce_user_project_in_sts_options (:3129),
should_follow_external_account_impersonation_contract (:3168; STS scope becomes cloud-platform, the
impersonation call carries Authorization: Bearer <sts token>, "lifetime":"900s", and devstorage scope),
should_reject_empty_json_external_account_subject_token (:3245),
should_reject_missing_malformed_or_expired_impersonation_expiry (:3405),
should_reject_executable_external_account_credentials (:3285),
should_reject_aws_external_account_before_treating_metadata_url_as_subject_token (:3267).
Implementation: external_account_subject_token gcs.rs:414-456.

Pants: every path exists in
src/Pants.Core/Cloud/Internal/Providers/Credentials/Gcs/GcsExternalAccountTokenProvider.cs:
URL source plus headers at :132-180, workforce options={"userProject":..} at :76-84, impersonation
scope/bearer/lifetime at :60-65, :201-225 and :302-322, and impersonation expiry validation at :345-359.
Executable rejection is at :33-37 and :103-109. The AWS environment_id source is rejected before the URL
branch at :103-109. An empty JSON subject token is rejected at :279-298 because GetRequiredString treats
whitespace as missing (RefreshingGcsTokenProvider.cs:324-331), but the error says the field is "missing"
rather than "empty". The only external-account test is
test/Pants.Tests/Cloud/GcsCredentialSourceTests.cs ShouldExchangeFileSourcedExternalAccountCredentialFromAdc,
which covers a file-sourced text token only.

Why it matters: federated identity runs on every GKE, EKS, and Azure-hosted deployment that uses workload identity. A
regression would either break authentication or silently send the wrong scope or billing project, and no test would catch it.

Acceptance criteria:

  • A URL-sourced JSON subject token is fetched with each configured header, and the test asserts both the header and the parsed token.
  • A workforce_pool_user_project produces the form field options={"userProject":"..."} on the STS request.
  • With impersonation, the STS request uses the cloud-platform scope. The impersonation POST carries the Bearer STS token,
    lifetime taken from token_lifetime_seconds, and devstorage scope. Lifetimes outside 600-43200 are rejected.
  • Impersonation responses with a missing, malformed, or past expireTime, or an empty accessToken, fail with PantsIOException.
  • Whitespace-only JSON and text subject tokens fail before any STS request is sent.
  • executable at the root or in the source, and environment_id together with a url, are rejected with no HTTP request issued.
  • No test output or exception message contains the subject token, the STS token, or header values.

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

    Labels

    area:cloudReal cloud provider backendsarea:correctnessTransaction/CF/config behavioral hardeningparity-gapFeature not yet at parity with Midgepriority:P2Normal: bounded hardening, coverage, maintainability, or non-critical behavior gap

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions