feat(mvp): working secrets-engine CLI for the whynot-design npm publish lane
Implements SECRETS-WP-0002 end to end as a uv-managed Python package: - catalog: non-secret lane registry + strict validator (build/test/prod) - stage roles + OpenBao ACL policies; guards refuse wildcards, sys/, identity/, admin names, and cross-stage paths before any backend call - plan/apply: dry-run-first, idempotent policy + approle apply, decision-gated - decisions: State Hub lookup with local-fixture fallback; non-secret evidence to JSONL + hub progress, scrubbed of any value - provision/verify: mode-0600 file import + generated test values; positive/ negative checks that never print the value - exec delivery: `exec --catalog ... -- npm publish` injects the token via a temp .npmrc for the child only, cleaned up on exit/failure/interrupt - ops-warden routing contract + hardening backlog docs - 34 tests incl. live OpenBao integration; scripts/demo-e2e.sh runs the full chain against a throwaway bao dev server Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
58c24cff53
commit
a852d3f1ff
47 changed files with 3743 additions and 122 deletions
91
scripts/demo-e2e.sh
Executable file
91
scripts/demo-e2e.sh
Executable file
|
|
@ -0,0 +1,91 @@
|
|||
#!/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:-<unset>}'"
|
||||
|
||||
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."
|
||||
Loading…
Add table
Add a link
Reference in a new issue