This commit is contained in:
Harivansh Rathi 2026-03-15 14:09:37 -04:00
parent ba0f284dba
commit ff77053297
5 changed files with 183 additions and 3 deletions

View file

@ -96,6 +96,13 @@ export BW_SESSION="$(bw unlock --raw)"
just secrets-sync
```
Restore file-based secrets from Bitwarden:
```bash
export BW_SESSION="$(bw unlock --raw)"
just secrets-restore-files
```
## What Still Needs Manual Handling
- Promoting vault-backed secrets into Bitwarden Secrets Manager machine-account

View file

@ -20,8 +20,10 @@ secret values.
`~/.config/secrets/shell.zsh` when present
- [scripts/render-bw-shell-secrets.sh](/Users/rathi/Documents/GitHub/nix/scripts/render-bw-shell-secrets.sh)
renders that file from Bitwarden vault items
- [scripts/restore-bw-files.sh](/Users/rathi/Documents/GitHub/nix/scripts/restore-bw-files.sh)
restores file-based credentials and SSH material from Bitwarden vault items
- [justfile](/Users/rathi/Documents/GitHub/nix/justfile) exposes this as
`just secrets-sync`
`just secrets-sync` and `just secrets-restore-files`
## Daily Shell Flow
@ -60,7 +62,7 @@ For a fresh sandbox or new machine, the clean bootstrap is:
1. `darwin-rebuild switch` or Home Manager activation
2. authenticate `bw`
3. `just secrets-sync`
4. restore any file-based credentials you actually need from Bitwarden
4. `just secrets-restore-files`
That gives you a usable dev shell quickly without committing any secret values
into the repo.

View file

@ -15,3 +15,6 @@ fmt:
secrets-sync:
./scripts/render-bw-shell-secrets.sh
secrets-restore-files:
./scripts/restore-bw-files.sh

View file

@ -24,7 +24,13 @@ mkdir -p "${out_dir}"
read_note() {
local item_name="$1"
bw get item "${item_name}" --session "${BW_SESSION}" | jq -r '.notes'
local item_id
item_id="$(bw list items --session "${BW_SESSION}" | jq -r --arg n "${item_name}" '.[] | select(.name == $n) | .id' | head -1)"
if [[ -z "${item_id}" ]]; then
echo "Bitwarden item not found: ${item_name}" >&2
exit 1
fi
bw get item "${item_id}" --session "${BW_SESSION}" | jq -r '.notes'
}
extract_env_value() {

162
scripts/restore-bw-files.sh Executable file
View file

@ -0,0 +1,162 @@
#!/usr/bin/env bash
set -euo pipefail
if ! command -v bw >/dev/null 2>&1; then
echo "bw is not installed" >&2
exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
echo "jq is not installed" >&2
exit 1
fi
if [[ "${BW_SESSION:-}" == "" ]]; then
echo 'BW_SESSION is not set. Run: export BW_SESSION="$(bw unlock --raw)"' >&2
exit 1
fi
timestamp="$(date +%Y%m%d-%H%M%S)"
read_note() {
local item_name="$1"
local item_id
item_id="$(bw list items --session "${BW_SESSION}" | jq -r --arg n "${item_name}" '.[] | select(.name == $n) | .id' | head -1)"
if [[ -z "${item_id}" ]]; then
echo "Bitwarden item not found: ${item_name}" >&2
exit 1
fi
bw get item "${item_id}" --session "${BW_SESSION}" | jq -r '.notes'
}
backup_if_exists() {
local target="$1"
if [[ -e "${target}" || -L "${target}" ]]; then
mv "${target}" "${target}.bw-bak-${timestamp}"
fi
}
write_file() {
local target="$1"
local mode="$2"
local content="$3"
mkdir -p "$(dirname "${target}")"
backup_if_exists "${target}"
printf '%s' "${content}" > "${target}"
chmod "${mode}" "${target}"
printf 'restored %s\n' "${target}"
}
restore_plain_note() {
local item_name="$1"
local target="$2"
local mode="$3"
write_file "${target}" "${mode}" "$(read_note "${item_name}")"
}
restore_aws_credentials() {
local note
local access_key
local secret_key
note="$(read_note 'Machine: AWS Default Credentials')"
access_key="$(printf '%s\n' "${note}" | sed -n 's/^aws_access_key_id=//p' | head -1)"
secret_key="$(printf '%s\n' "${note}" | sed -n 's/^aws_secret_access_key=//p' | head -1)"
write_file "${HOME}/.aws/credentials" 600 "[default]
aws_access_key_id = ${access_key}
aws_secret_access_key = ${secret_key}
"
}
restore_gcloud_adc() {
local note
note="$(read_note 'Machine: GCloud ADC')"
local account
local client_id
local client_secret
local quota_project_id
local refresh_token
local type
local universe_domain
account="$(printf '%s\n' "${note}" | sed -n 's/^account=//p' | head -1)"
client_id="$(printf '%s\n' "${note}" | sed -n 's/^client_id=//p' | head -1)"
client_secret="$(printf '%s\n' "${note}" | sed -n 's/^client_secret=//p' | head -1)"
quota_project_id="$(printf '%s\n' "${note}" | sed -n 's/^quota_project_id=//p' | head -1)"
refresh_token="$(printf '%s\n' "${note}" | sed -n 's/^refresh_token=//p' | head -1)"
type="$(printf '%s\n' "${note}" | sed -n 's/^type=//p' | head -1)"
universe_domain="$(printf '%s\n' "${note}" | sed -n 's/^universe_domain=//p' | head -1)"
local json
json="$(
jq -n \
--arg account "${account}" \
--arg client_id "${client_id}" \
--arg client_secret "${client_secret}" \
--arg quota_project_id "${quota_project_id}" \
--arg refresh_token "${refresh_token}" \
--arg type "${type}" \
--arg universe_domain "${universe_domain}" \
'{
account: $account,
client_id: $client_id,
client_secret: $client_secret,
quota_project_id: $quota_project_id,
refresh_token: $refresh_token,
type: $type,
universe_domain: $universe_domain
}'
)"
write_file "${HOME}/.config/gcloud/application_default_credentials.json" 600 "${json}"
}
restore_ssh_key() {
local item_name="$1"
local rel_path="$2"
local note
local private_key
local public_key
note="$(read_note "${item_name}")"
private_key="$(
printf '%s\n' "${note}" | awk '
BEGIN {section="p"; started=0}
/^path=/ {next}
started==0 && /^$/ {started=1; next}
started==1 && /^public_key:$/ {section="u"; next}
started==1 && section=="p" {print}
'
)"
public_key="$(
printf '%s\n' "${note}" | awk '
BEGIN {capture=0}
/^public_key:$/ {capture=1; next}
capture==1 {print}
'
)"
write_file "${HOME}/.ssh/${rel_path}" 600 "${private_key}"
if [[ -n "${public_key}" ]]; then
write_file "${HOME}/.ssh/${rel_path}.pub" 644 "${public_key}"
fi
}
restore_plain_note 'Machine: SSH Config' "${HOME}/.ssh/config" 600
restore_plain_note 'Machine: SSH CSB Config' "${HOME}/.ssh/csb/config" 600
restore_ssh_key 'Machine: SSH Key atlas-ssh.txt' 'atlas-ssh.txt'
restore_ssh_key 'Machine: SSH Key csb_id_rsa_5m2zg4' 'csb/csb_id_rsa_5m2zg4'
restore_ssh_key 'Machine: SSH Key google_compute_engine' 'google_compute_engine'
restore_ssh_key 'Machine: SSH Key id_ed25519' 'id_ed25519'
restore_ssh_key 'Machine: SSH Key id_ed25519_uvacompute' 'id_ed25519_uvacompute'
restore_ssh_key 'Machine: SSH Key id_rsa_1024' 'id_rsa_1024'
restore_ssh_key 'Machine: SSH Key phinsta_ciuser' 'phinsta_ciuser'
restore_aws_credentials
restore_gcloud_adc
restore_plain_note 'Machine: Codex Auth' "${HOME}/.codex/auth.json" 600
restore_plain_note 'Machine: Vercel Auth' "${HOME}/Library/Application Support/com.vercel.cli/auth.json" 600