#!/usr/bin/env bash # End-to-end MVP demo for the whynot-design npm publish lane. # # Boots a throwaway OpenBao dev server, then drives the full secrets-engine chain: # plan (dry-run) -> apply -> provision (from mode-0600 file) -> verify +/- # -> exec (npm-config injection into a child) -> route -> revoke. # # Nothing here is production. The dev server is in-memory and discarded on exit. # The "token" is a throwaway local string written to a mode-0600 temp file. set -euo pipefail REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO" # shellcheck disable=SC1091 source .venv/bin/activate BAO_BIN="$(command -v bao)" WORK="$(mktemp -d)" export BAO_ADDR="http://127.0.0.1:8270" export BAO_TOKEN="se-demo-root" # Keep secret material OUTSIDE the repo worktree (engine enforces this). TOKENFILE="$WORK/whynot.token" cleanup() { set +e [[ -n "${BAO_PID:-}" ]] && kill "$BAO_PID" 2>/dev/null rm -rf "$WORK" } trap cleanup EXIT echo "### 0. boot throwaway OpenBao dev server (in-memory)" "$BAO_BIN" server -dev -dev-root-token-id="$BAO_TOKEN" \ -dev-listen-address="127.0.0.1:8270" >"$WORK/bao.log" 2>&1 & BAO_PID=$! for _ in $(seq 1 30); do "$BAO_BIN" status -address="$BAO_ADDR" >/dev/null 2>&1 && break sleep 0.2 done echo echo "### 1. plan (dry-run, no mutation)" secrets-engine plan whynot-design-npm-publish --stage prod | sed 's/^/ /' echo echo "### 2. apply approved metadata (policy + approle) to OpenBao" secrets-engine apply whynot-design-npm-publish --stage prod | sed 's/^/ /' echo echo "### 2b. apply is idempotent (re-run shows 'unchanged')" secrets-engine apply whynot-design-npm-publish --stage prod | sed 's/^/ /' echo echo "### 3. provision the token from a mode-0600 file outside the repo" printf 'npm_demoTOKENvalue1234567890abcd' > "$TOKENFILE" chmod 600 "$TOKENFILE" secrets-engine provision whynot-design-npm-publish --stage prod \ --field npm_token --from-file "$TOKENFILE" | sed 's/^/ /' echo echo "### 4. verify positive (approved consumer can read) + negative (others denied)" secrets-engine verify whynot-design-npm-publish --field npm_token --positive --negative | sed 's/^/ /' echo echo "### 5. exec-time delivery: child sees the token via a temp npmrc; parent never does" cat > "$WORK/fake-npm" <<'EOF' #!/usr/bin/env bash # Stand-in for 'npm publish' — proves the child can resolve the token and the # parent shell cannot. Prints only whether the token is reachable, never the value. if [[ -n "${NPM_CONFIG_USERCONFIG:-}" ]] && grep -q '_authToken' "$NPM_CONFIG_USERCONFIG"; then echo " [child] npm userconfig present; _authToken resolvable: yes" else echo " [child] NO token available"; exit 1 fi echo " [child] would run: npm $*" EOF chmod +x "$WORK/fake-npm" secrets-engine exec --catalog whynot-design-npm-publish -- "$WORK/fake-npm" publish echo " [parent] SE_NPM_TOKEN in parent shell: '${SE_NPM_TOKEN:-}'" echo echo "### 6. ops-warden routing pointer (ready=true expected)" secrets-engine route whynot-design-npm-publish --json | sed 's/^/ /' echo echo "### 7. revoke (deactivate the lane)" secrets-engine revoke whynot-design-npm-publish | sed 's/^/ /' echo echo "### DONE — full chain exercised against a live OpenBao."