diff --git a/.gitignore b/.gitignore index 17768a1..2f646f4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,9 @@ obsidian-web-clipper-settings.json # Machine-local: pins per-machine plugin versions/cache paths, churns on autoUpdate factory/.factory/plugins/installed_plugins.json + +# AWS credentials and the SSO token cache. Only aws/.aws/config is tracked; +# these are listed so a stray copy into the package can never be committed. +aws/.aws/credentials +aws/.aws/sso/ +aws/.aws/cli/ diff --git a/CLAUDE.md b/CLAUDE.md index 0123b0b..b81c39a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,6 +10,7 @@ GNU Stow-based dotfiles for macOS. Each top-level directory is a stow package mi Library/... # macOS paths (cursor/, vscode/, nightly-maintenance/) .claude/ # claude code settings (claude/) .cargo/, .docker/ # tool config (cargo/, docker/) + .aws/config # aws cli profiles (aws/) — credentials and SSO cache untracked .githooks/ # git hooks (core.hooksPath); post-merge updates submodules .claude/skills/ # repo-committed Claude Code skills (deploy — roll main out to all machines) .retired/ # reference-only packages (yabai, skhd-zig); dot-dirs aren't stowed @@ -27,3 +28,4 @@ bootstrap.sh # installs deps, stows packages, git hooks, tailnet ssh, mac - XDG paths (`.config/`) where the app supports it, macOS `Library/` paths otherwise. - Every top-level directory is a stow package. - The `claude/` package has a `.stow-local-ignore` — check it before adding files. +- Packages listed in `bootstrap.sh`'s `NO_FOLDING` (`aws`, `codex`) target directories that also hold host-local state; stow links their files individually so the directory itself is never replaced. diff --git a/README.md b/README.md index 3fb73ff..5762e86 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ GNU Stow-based dotfiles for macOS (with Linux support for the CLI packages). Eac | Package | What it configures | |---------|--------------------| | alacritty | Alacritty terminal | +| aws | AWS CLI profiles and Identity Center session | | cargo | Cargo (Rust) | | claude | Claude Code settings and permissions | | codex | Codex global instructions, portable defaults, and core plugins | @@ -42,6 +43,8 @@ cd ~/.dotfiles `bootstrap.sh` installs cross-platform dependencies (stow, zsh, neovim, gh, starship, mise, and Claude Code). On macOS it also installs the Coder CLI and brew casks. It then stows all packages, configures git hooks, and authorizes tailnet SSH between machines. Safe to re-run. macOS-only packages (cursor, duti, nightly-maintenance, teams-link, vscode, wallpapers) are skipped on Linux. +The `aws` package tracks only `~/.aws/config`. Credentials and the Identity Center token cache stay host-local and untracked, so bootstrap stows this package without folding, like `codex`. Account IDs mirror the infra repo's `data/accounts.json`, which is their source of truth. + Codex portable defaults live in `codex/system/config.toml` and bootstrap installs them as `/etc/codex/config.toml`. Codex owns `~/.codex/config.toml` as host-local mutable state for project trust, UI preferences, local runtimes, connectors, and plugin metadata; dotfiles never links or edits it. Bootstrap updates the AWS and Tractorbeam plugin marketplaces, removes Tractorbeam plugins absent from `codex/system/plugins.txt`, and installs every plugin listed there for the ChatGPT desktop app and Codex CLI. To stow manually: diff --git a/aws/.aws/config b/aws/.aws/config new file mode 100644 index 0000000..db82c23 --- /dev/null +++ b/aws/.aws/config @@ -0,0 +1,103 @@ +# AWS CLI profiles. Only this file is stowed — ~/.aws/sso, ~/.aws/cli, and +# ~/.aws/credentials are host-local cache and secrets, never tracked. +# +# Account IDs come from the infra repo's data/accounts.json, which is the +# single source of truth. Add an account there first, then mirror it here. + +[default] +region = us-east-1 + +# Every profile below authenticates through this one Identity Center session, +# so `aws sso login` once covers all of them. +[sso-session tractorbeam] +sso_start_url = https://tractorbeam.awsapps.com/start/# +sso_region = us-east-1 +sso_registration_scopes = sso:account:access + +# ── ORGANIZATION ───────────────────────────────────────────────────────────── + +[profile root] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 891377101660 +sso_role_name = AdministratorAccess + +[profile production] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 575108936009 +sso_role_name = AdministratorAccess + +# Nonprod resolves by assuming OrganizationAccountAccessRole from root rather +# than by a direct Identity Center login. That exact role ARN is what the +# cross-account CodeArtifact trust policies match on (codeartifact-npm-read in +# shared-services, codeartifact-read in distribution), so constellation's +# `mise run secrets:fetch` and a scaffolded project's `mise run +# codeartifact:login` both break if this becomes an ordinary SSO profile. +# +# sso_session is declared alongside the chain purely so `aws sso login` can find +# the session when this profile is active — credentials still resolve through +# assume-role, which precedes sso in the provider chain. Without it, any tool +# that offers to re-authenticate (fnox does) fails on a profile that has no +# sso_start_url of its own. +[profile nonprod] +sso_session = tractorbeam +source_profile = root +role_arn = arn:aws:iam::716174523075:role/OrganizationAccountAccessRole +region = us-east-1 + +[profile shared-services] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 707264479446 +sso_role_name = AdministratorAccess + +[profile audit] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 216989103601 +sso_role_name = AdministratorAccess + +[profile log-archive] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 565393051614 +sso_role_name = AdministratorAccess + +[profile sandbox] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 545009842244 +sso_role_name = AdministratorAccess + +# ── PRODUCTS ───────────────────────────────────────────────────────────────── + +[profile mailman] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 343508908860 +sso_role_name = AdministratorAccess + +# ── TESTBEDS ───────────────────────────────────────────────────────────────── +# +# BrizzCo is a fictional customer used to exercise bring-your-own-cloud +# deployments; it holds no real client data. + +[profile brizzco] +region = us-east-1 +sso_session = tractorbeam +sso_account_id = 237303364471 +sso_role_name = AdministratorAccess + +# Qualification profiles reach a testbed through the organization role instead +# of an Identity Center assignment, matching how deployment automation lands +# in these accounts. +[profile brizzco-qualification] +source_profile = root +role_arn = arn:aws:iam::237303364471:role/OrganizationAccountAccessRole +region = us-east-1 + +[profile distribution-qualification] +source_profile = root +role_arn = arn:aws:iam::797601397665:role/OrganizationAccountAccessRole +region = us-east-1 diff --git a/bootstrap.sh b/bootstrap.sh index f87015d..dbe6749 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -11,6 +11,11 @@ export PATH="$HOME/.local/bin:$PATH" # macOS-only stow packages (contain Library/ paths or macOS-only tools) MACOS_ONLY="cursor duti nightly-maintenance teams-link vscode wallpapers" +# Stow packages whose target directory also holds host-local state, so the +# tracked files must be linked individually rather than by folding the +# directory itself into a symlink. +NO_FOLDING="aws codex" + # CLI packages to install (must exist in brew + apt/dnf/yum/pacman) PACKAGES=(git neovim stow zsh eza) @@ -327,9 +332,11 @@ stow_packages() ( # Pin target to $HOME. Stow's default target is the parent of the stow # dir, which works when this repo is cloned at ~/dotfiles but not when # it's elsewhere. - if [[ "$pkg" == "codex" ]]; then - # Codex owns mutable host state under ~/.codex. Link individual global - # instructions without ever replacing the host-local directory. + if [[ " $NO_FOLDING " == *" $pkg "* ]]; then + # These packages sit beside mutable host state — Codex's global + # instructions under ~/.codex, the AWS CLI's SSO token cache and + # credentials under ~/.aws. Link the tracked files individually so stow + # never replaces the host-local directory with a symlink to the repo. backup_conflicts "$pkg" --no-folding stow -t "$HOME" --restow --no-folding "$pkg" else