Problem
The CLI stores access tokens as plaintext in .mappsrc, a known dotfile path. This creates two concerns:
- Supply chain risk -- malicious npm packages can trivially scrape plaintext tokens from known dotfile paths (as demonstrated by recent supply chain attacks targeting developer machines)
- No multi-account support -- developers working with multiple environments (dev/prod/staging) must re-run
mapps init to switch tokens
Proposal
Add named credential profiles to .mappsrc. Each profile maps a name to a shell command that prints an access token to stdout at runtime:
{
"profiles": {
"dev": "op read 'op://CarbonWeb/dev/credential'",
"prod": "aws ssm get-parameter --name /app/token --query Parameter.Value --output text"
},
"defaultProfile": "dev"
}
Supported providers (examples)
| Provider |
Example command |
| 1Password |
op read 'op://vault/item/field' |
| Bitwarden |
bw get password item-id |
| HashiCorp Vault |
vault kv get -field=token secret/myapp |
| AWS SSM |
aws ssm get-parameter --name /path --query Parameter.Value --output text |
| macOS Keychain |
security find-generic-password -s mapps -a dev -w |
| Named plaintext |
echo my-token-here |
New CLI surface
# Interactive management
mapps profile
# Subcommands
mapps profile:add --name dev --command "op read op://vault/dev/token" --set-as-default
mapps profile:remove --name dev
mapps profile:list
mapps profile:set-default --name dev
mapps profile:clear-default
mapps profile:remove-token # Remove legacy plaintext accessToken
# Runtime override on any command
mapps code:push --profile prod
mapps code:push --ignore-profiles
Token resolution precedence
--profile flag -- runs the named profile command
defaultProfile in config -- runs that profile command
- No profile specified, no default set -- falls through silently to static token
accessToken in .mappsrc -- plaintext fallback
Error handling
- Profile command failure -- aborts with error, suggests
--ignore-profiles
- Empty output -- aborts with error
- Profile name not found -- aborts with error listing available profiles
Security
Profile commands execute arbitrary shell code — this is by design, as it's how they delegate to secrets managers. To prevent a malicious repository from injecting attacker-controlled commands via a committed .mappsrc, profiles are only loaded from the global config. If a local project .mappsrc contains profiles, they are ignored with a warning.
Backwards compatibility
Fully backwards compatible. Existing .mappsrc files with only accessToken continue to work unchanged. Profiles are opt-in. The goal is not to remove the plaintext option, but to ensure developers have a secure alternative available so that storing credentials on disk becomes an informed choice rather than the only path offered by the tool.
Prior art
- pnpm ships
tokenHelper -- same "run a command, use stdout as token" pattern
- npm has an open feature request for the same capability
- AWS CLI uses named profiles for credential management
- Docker uses credential helpers for registry authentication
Problem
The CLI stores access tokens as plaintext in
.mappsrc, a known dotfile path. This creates two concerns:mapps initto switch tokensProposal
Add named credential profiles to
.mappsrc. Each profile maps a name to a shell command that prints an access token to stdout at runtime:{ "profiles": { "dev": "op read 'op://CarbonWeb/dev/credential'", "prod": "aws ssm get-parameter --name /app/token --query Parameter.Value --output text" }, "defaultProfile": "dev" }Supported providers (examples)
op read 'op://vault/item/field'bw get password item-idvault kv get -field=token secret/myappaws ssm get-parameter --name /path --query Parameter.Value --output textsecurity find-generic-password -s mapps -a dev -wecho my-token-hereNew CLI surface
Token resolution precedence
--profileflag -- runs the named profile commanddefaultProfilein config -- runs that profile commandaccessTokenin.mappsrc-- plaintext fallbackError handling
--ignore-profilesSecurity
Profile commands execute arbitrary shell code — this is by design, as it's how they delegate to secrets managers. To prevent a malicious repository from injecting attacker-controlled commands via a committed
.mappsrc, profiles are only loaded from the global config. If a local project.mappsrccontains profiles, they are ignored with a warning.Backwards compatibility
Fully backwards compatible. Existing
.mappsrcfiles with onlyaccessTokencontinue to work unchanged. Profiles are opt-in. The goal is not to remove the plaintext option, but to ensure developers have a secure alternative available so that storing credentials on disk becomes an informed choice rather than the only path offered by the tool.Prior art
tokenHelper-- same "run a command, use stdout as token" pattern