Provision LOCALSTACK_AUTH_TOKEN for every repository

LocalStack is a common enough dependency that declaring it per repository is
busywork, and the token is already in the host environment when it is needed at
all. It is now provisioned host-wide, through the same custom-secret path as
the per-repository declarations, so the value stays out of the sandbox and the
proxy substitutes it on requests to localstack.cloud.

Provisioning is conditional on the sandbox having Docker. LocalStack runs as a
container, so on a sandbox created from a non-docker template the credential
would be dead weight, and the entry is skipped with a message rather than
stored. An unset variable is skipped silently, which costs nothing on a machine
that never uses LocalStack.

The provisioning body moves into provision_secret so the host-wide and
per-repository paths cannot drift apart.
This commit is contained in:
2026-07-31 12:09:56 -05:00
parent 93dc61a024
commit d2b7a5ef63
3 changed files with 116 additions and 36 deletions
+78 -36
View File
@@ -8,6 +8,13 @@ DEFAULT_MODE="${AI_SBX_MODE:-clone}"
DEFAULT_TOKEN_DAYS="${AI_SBX_TOKEN_DAYS:-30}"
DEFAULT_TEMPLATE="${AI_SBX_TEMPLATE:-}"
DEFAULT_TOOLS="${AI_SBX_TOOLS:-bun}"
# VAR|host[,host...]|requirement. Provisioned for every repository when the
# variable is present in the host environment. "docker" skips the entry on a
# sandbox that cannot run containers, where the credential would be useless.
HOST_WIDE_SECRETS=(
"LOCALSTACK_AUTH_TOKEN|localstack.cloud,*.localstack.cloud|docker"
)
CLAUDE_HOME="${CLAUDE_HOME:-$HOME/.claude}"
# Only these leave the host. ~/.claude also holds OAuth credentials, shell
@@ -76,6 +83,8 @@ Registry credentials are declared per repository in the user's config
directory as a "secrets" file, one line of VAR|host|command each. The command
runs on the host and its output becomes an sbx custom secret, so the sandbox
sees a placeholder and the proxy substitutes the real value.
LOCALSTACK_AUTH_TOKEN is provisioned for every repository when it is set on
the host and the sandbox has Docker to make use of it.
AI_SBX_TOOLS lists mise tools installed globally in the sandbox, defaulting
to bun because several Claude plugins run their hooks under it. Set it to an
@@ -780,14 +789,80 @@ secret_placeholder() {
printf 'sbx-cs-%s' "$digest"
}
sandbox_has_docker() {
sbx exec "$SANDBOX_NAME" \
bash -lc 'command -v docker >/dev/null' \
</dev/null >/dev/null 2>&1
}
provision_secret() {
local var="$1" hosts="$2" value="$3"
local placeholder
placeholder="$(secret_placeholder "$var")"
local -a host_args=()
local host
for host in ${hosts//,/ }; do
host_args+=(--host "$host")
done
# Piped rather than --value: the secret would otherwise be visible in the
# process list to anything running as this user.
printf '%s' "$value" |
sbx secret set-custom "$SANDBOX_NAME" \
"${host_args[@]}" \
--env "$var" \
--placeholder "$placeholder" >/dev/null 2>&1 ||
{
printf 'Could not store %s in the sandbox.\n' "$var" >&2
return 1
}
# A sandbox that already exists keeps whatever environment it was created
# with, so the placeholder is exported explicitly.
sbx exec "$SANDBOX_NAME" bash -c "
persistent=/etc/sandbox-persistent.sh
marker=$(printf '%q' "# ai-sbx secret $var")
grep -Fq \"\$marker\" \"\$persistent\" 2>/dev/null && exit 0
printf '%s\nexport %s=%s\n' \
\"\$marker\" $(printf '%q' "$var") $(printf '%q' "$placeholder") \
>>\"\$persistent\"
" </dev/null >/dev/null 2>&1 || true
printf 'Provisioned %s for %s\n' "$var" "${hosts//,/, }"
}
# Credentials worth provisioning for every repository rather than declaring per
# repository, taken straight from the host environment. LocalStack only matters
# when the agent can run containers, so it is skipped where Docker is absent.
install_host_wide_secrets() {
local entry var hosts requirement
for entry in "${HOST_WIDE_SECRETS[@]}"; do
IFS='|' read -r var hosts requirement <<<"$entry"
[[ -n "${!var:-}" ]] || continue
if [[ "$requirement" == docker ]] && ! sandbox_has_docker; then
printf 'Skipping %s: the sandbox has no Docker to run it.\n' "$var" >&2
continue
fi
provision_secret "$var" "$hosts" "${!var}" || true
done
}
install_sandbox_secrets() {
install_host_wide_secrets
local declarations
declarations="$(read_secret_declarations)" || return 0
[[ -n "$declarations" ]] || return 0
local var hosts command value placeholder
local -a host_args
local var hosts command value
while IFS='|' read -r var hosts command; do
[[ -n "$var" ]] || continue
@@ -804,40 +879,7 @@ install_sandbox_secrets() {
continue
}
placeholder="$(secret_placeholder "$var")"
host_args=()
local host
for host in ${hosts//,/ }; do
host_args+=(--host "$host")
done
# Piped rather than --value: the secret would otherwise be visible in
# the process list to anything running as this user.
if printf '%s' "$value" |
sbx secret set-custom "$SANDBOX_NAME" \
"${host_args[@]}" \
--env "$var" \
--placeholder "$placeholder" >/dev/null 2>&1; then
printf 'Provisioned %s for %s\n' "$var" "${hosts//,/, }"
else
printf 'Could not store %s in the sandbox.\n' "$var" >&2
continue
fi
# A sandbox that already exists keeps whatever environment it was
# created with, so the placeholder is exported explicitly.
sbx exec "$SANDBOX_NAME" bash -c "
persistent=/etc/sandbox-persistent.sh
marker=$(printf '%q' "# ai-sbx secret $var")
grep -Fq \"\$marker\" \"\$persistent\" 2>/dev/null && exit 0
printf '%s\nexport %s=%s\n' \
\"\$marker\" $(printf '%q' "$var") $(printf '%q' "$placeholder") \
>>\"\$persistent\"
" </dev/null >/dev/null 2>&1 || true
provision_secret "$var" "$hosts" "$value" || true
unset value
done <<<"$declarations"