Skip to content

feat: auth setup-aws, to add a credential_process profile to the AWS config - #51

Open
alukach wants to merge 2 commits into
mainfrom
feat/aws-profile-setup
Open

alukach wants to merge 2 commits into
mainfrom
feat/aws-profile-setup

Conversation

@alukach

@alukach alukach commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Why

The README's main setup step had people edit ~/.aws/config by hand. A profile that runs credential_process = source-coop creds lets the AWS CLI and SDKs renew credentials themselves, with no one-hour limit and no wrapper. Hand-written profiles had a gap: one without --proxy-url takes its environment from whatever SOURCE_PROXY_URL the calling shell has set, while its endpoint_url stays fixed.

source-coop auth setup-aws
aws s3 ls s3://my-org/my-product/ --profile source-coop
AWS_PROFILE=source-coop python my_script.py

What

  • source-coop auth setup-aws [--proxy-url] [--role-arn] [--profile NAME] [--json] adds or updates [profile source-coop] in ~/.aws/config, or in AWS_CONFIG_FILE if that's set:
    [profile source-coop]
    credential_process = source-coop creds --proxy-url https://data.source.coop
    endpoint_url = https://data.source.coop
    region = us-east-1
    • credential_process always passes --proxy-url, so the environment it gets credentials from always matches endpoint_url. It passes --role-arn only when that isn't the default.
    • Only credential_process and endpoint_url are managed. region is added only if the section has none. Everything else stays as it was: other profiles, comments, the section's other keys (including nested ones like s3 =), CRLF line endings and repeated keys.
    • The file is written in place, so a symlinked config (dotfiles) stays a symlink. A missing file or directory is created.
    • The profile is named source-coop in production and after the environment elsewhere (source-coop-staging), or anything given with --profile.
    • Output: the section as written, on stderr. With --json: {"profile", "config_file", "changed", "settings"}. Running it again reports changed: false.
  • auth login suggests the command until the environment's profile exists.
  • README:
    • setup step 2 now uses the command;
    • the multiple-roles and environments examples use it too;
    • a new "Using other tools" table covers DuckDB, s5cmd, GDAL, object_store and mc: which can use the profile's credentials, and how each takes the endpoint.

Name: auth setup-aws, modelled on gh auth setup-git. setup-profile could be read as your source.coop account profile.

Related: #43 (exec) covers the tools the table lists as unable to use the profile: GDAL before 3.12 and object_store. Once both are merged, that row can point to exec.

Testing

  • cargo test and cargo test --features staging: 74 passed, 1 ignored. New tests in aws_config cover:
    • a new file;
    • keeping other profiles and comments, and running twice;
    • an update in place with stray spacing in the header, a duplicate key, a nested key and a user-set region;
    • CRLF line endings;
    • profile names per environment.
  • cargo clippy --all-targets -- -D warnings and cargo fmt --check: clean.
  • Manual, with a temporary HOME:
    • a symlinked config with an old source-coop section was updated in place: it's still a symlink, [default] and the user's region were kept, and a second run reported changed: false;
    • staging added source-coop-staging;
    • AWS_CONFIG_FILE pointing into a directory that didn't exist yet created both.
  • AWS CLI end to end: aws s3 ls --profile … ran this build's creds with the profile's --proxy-url (a dummy local proxy, so no keychain entry was read). It got not logged in, as expected.
  • The "Using other tools" rows come from the tools' documentation and source code; they weren't run against the proxy.

🤖 Generated with Claude Code

alukach and others added 2 commits October 14, 2026 20:44
…config

Writes or updates `[profile source-coop]` (`source-coop-<environment>`
outside production) in `~/.aws/config` or `AWS_CONFIG_FILE`: a
credential_process running `source-coop creds --proxy-url …`, the proxy as
endpoint_url, and a region only if the section has none. Only those keys
change; the rest of the file is kept, symlinks included. `auth login`
suggests it until the profile exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C2VyGzXgtd9L6f6Rs9xDSZ
@claude

claude Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Claude finished @alukach's task in 25s —— View job


✅ No blocking issues — safe to merge.

I read the diff in src/aws_config.rs and src/main.rs. I did not run the tests.

Non-blocking notes:

  • src/main.rs:~728: --json rebuilds settings by re-parsing the section text. It takes any key = value line inside the section, including comments such as # note = x, which end up as keys like "# note". Better to build it from the managed settings plus the actual region value, or skip lines that start with # or ;.
  • src/aws_config.rs:~58: upsert and find match headers by splitting on whitespace. A --profile value with spaces, such as "a b", never matches its own header on the next run. The profile is then appended again each time and changed is never false. A value containing ] or a newline would produce a broken header. Rejecting names with whitespace, ] or control characters would avoid this.
  • endpoint_url at the profile level applies to every service, not just S3. With --profile source-coop, calls such as aws sts get-caller-identity also go to the proxy. This may be intended, but the README could say so. The alternative is a services section.
  • find's header() also treats an indented [x] line as a section header, because it trims before checking. This is rare, but it would cut a section short.

Simplify (ponytail)

  • src/main.rs (run_setup_aws): the JSON path calls section() and parses the text back into key/value pairs. Build the map from settings plus the region value instead, and drop the re-parse.
  • src/aws_config.rs (DEFAULTS): a one-element const slice, with chained iterators in two places. A single region constant or inline literal would do the same job.
  • src/aws_config.rs (section): it clones lines into a Vec<String> only so they can be printed. Return &[&str] or print directly.
  • src/aws_config.rs (find): &[impl AsRef<str>] exists only so it can be shared by Vec<String> and Vec<&str>. Making upsert and section both use Vec<&str> removes the generic.

💰 Estimated review cost: $0.15 · 0m24s · 5 turns

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.

1 participant