64 lines
2.8 KiB
Bash
64 lines
2.8 KiB
Bash
# Shared container-side primitives. Secret JSON travels through stdin or private files.
|
|
set -eu
|
|
set -o pipefail
|
|
umask 077
|
|
STATE="$PWD/.local/dev"
|
|
TOOL_STATE=$STATE
|
|
mkdir -p "$STATE"
|
|
WORK=$(mktemp -d)
|
|
cleanup() {
|
|
rm -rf "$WORK"
|
|
chown -R "${LOCAL_UID:-0}:${LOCAL_GID:-0}" "$TOOL_STATE"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
fail() { echo "$*" >&2; exit 1; }
|
|
compose() { docker compose --project-directory . -f infra/local/compose.yml --env-file "$STATE/images.env" "$@"; }
|
|
write() {
|
|
target=$1; mode=${2:-600}
|
|
mkdir -p "$(dirname "$target")"
|
|
cat > "$target.tmp"
|
|
chmod "$mode" "$target.tmp"
|
|
mv "$target.tmp" "$target"
|
|
}
|
|
# Token is never placed in curl's arguments, errors or response logs.
|
|
vault() (
|
|
path=$1; method=${2:-GET}; missing=${3:-no}
|
|
header=$(mktemp "$WORK/header.XXXXXX")
|
|
response=$(mktemp "$WORK/response.XXXXXX")
|
|
trap 'rm -f "$header" "$response"' EXIT
|
|
printf 'Content-Type: application/json\n' > "$header"
|
|
if [ -n "${VAULT_TOKEN:-}" ]; then printf 'X-Vault-Token: %s\n' "$VAULT_TOKEN" >> "$header"; fi
|
|
if [ "$method" = GET ]; then
|
|
code=$(curl -s --connect-timeout 5 --max-time 30 -H "@$header" -o "$response" -w '%{http_code}' "http://vault:8200/v1/$path") || exit 1
|
|
else
|
|
code=$(curl -s --connect-timeout 5 --max-time 30 -H "@$header" -X "$method" --data-binary @- -o "$response" -w '%{http_code}' "http://vault:8200/v1/$path") || exit 1
|
|
fi
|
|
case "$code" in
|
|
200|204) if [ -s "$response" ]; then cat "$response"; else printf '{}'; fi;;
|
|
404) if [ "$missing" = yes ]; then printf 'null'; else echo "Vault $path returned HTTP $code" >&2; exit 1; fi;;
|
|
*) echo "Vault $path returned HTTP $code" >&2; exit 1;;
|
|
esac
|
|
)
|
|
existing() {
|
|
[ -f "$STATE/admin/init.json" ] || fail 'Missing .local/dev/admin/init.json; restore matching bootstrap material'
|
|
VAULT_TOKEN=$(jq -er '.root_token' "$STATE/admin/init.json")
|
|
export VAULT_TOKEN
|
|
}
|
|
kv() { vault "kv/data/$1" GET yes | jq 'if . == null then null else .data.data end'; }
|
|
put() { jq '{data:.}' | vault "kv/data/$1" POST >/dev/null; }
|
|
random() { printf '{"bytes":%s,"format":"hex"}' "${1:-32}" | vault sys/tools/random POST | jq -er '.data.random_bytes'; }
|
|
ensure() (
|
|
path=$1
|
|
value=$(kv "$path")
|
|
if [ "$value" = null ]; then put "$path"; fi
|
|
)
|
|
# Never forward mongosh errors: authentication/command errors may include secrets.
|
|
mongo() { compose exec -T mongo mongosh --quiet --file /dev/stdin > "$WORK/mongo-result" 2> "$WORK/mongo-error" || return 1; cat "$WORK/mongo-result"; }
|
|
admin_auth() { kv infrastructure/mongo/bootstrap | jq -r '"const admin=db.getSiblingDB(\"admin\"); admin.auth(\"local-admin\","+(.password|tojson)+");"'; }
|
|
email_valid() { jq -e '(.api_key|type=="string") and (.api_key|test("\\S"))' >/dev/null; }
|
|
export_ca() {
|
|
compose exec -T frontend cat /data/caddy/pki/authorities/local/root.crt | write "$STATE/ca.pem" 644
|
|
}
|