2afdfd093b
Three files each appended /bootstrap.env to a value whose shape nobody had
pinned down, and they did not agree:
- the rotation scripts print the FULL file URL and say to store THAT in
Bitwarden, so that is what gets pasted
- dotup asked for the directory and appended /bootstrap.env itself
- .tests/e2e.sh independently duplicated dotup's assumption
Pasting the saved value made the request .../bootstrap.env/bootstrap.env. The
404 tripped curl --fail and surfaced as "endpoint refused the credentials. The
machine stays public-only" -- blaming the password for a URL shape, which is
about the most expensive wrong error message this path could produce.
dotup and the wrapper now both strip a trailing slash and a trailing
/bootstrap.env before building the request, so either form works and the
existing Bitwarden entry needs no editing.
Four assertions cover all four shapes -- directory and file URL, each with and
without a trailing slash. They eval the normalisation lifted straight out of
dotup rather than a copy, and that binding was mutation-tested: deleting the
line from dotup makes them fail with exactly the production symptom,
https://h/r/bootstrap.env/bootstrap.env. 101 -> 105.
The second instance, in e2e.sh, was found only by running the harness with the
file URL instead of the directory. Every earlier run passed because it was fed
the shape that happened to be in a variable, not the shape a person has in a
password manager. Both shapes now run end to end and pass.
The normalisation exists in two places because the harness cannot source
dotup's internals. That is the same duplication that caused this, and only
dotup's copy is covered by the suite.
97 lines
4.3 KiB
Bash
Executable File
97 lines
4.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# Phase 5 end-to-end against the live endpoint, in a throwaway container.
|
|
#
|
|
# RUN IT FROM A NORMAL TERMINAL, NOT FROM INSIDE A CLAUDE SESSION:
|
|
#
|
|
# bash .tests/e2e.sh
|
|
#
|
|
# Do NOT run it with the `!` prefix in Claude Code. The output is redacted, but
|
|
# the prompt is not worth risking -- and the whole point of this wrapper is that
|
|
# the password stays on your side.
|
|
#
|
|
# The password is never written to disk, never placed on any command line, and
|
|
# never printed. It is read from your terminal into a shell variable and handed
|
|
# to the container through the environment:
|
|
#
|
|
# `docker exec -e BOOT_PW` with NO `=value` tells docker to inherit the
|
|
# variable from this process. Writing `-e BOOT_PW=secret` would put it in
|
|
# docker's own argv, and /proc/<pid>/cmdline is world-readable -- the exact
|
|
# bug this test suite was just fixed to stop doing in dotup.
|
|
#
|
|
# What it proves that the unit suite cannot: that a machine which has only ever
|
|
# seen the public repo can reach the real endpoint, authenticate, clone the
|
|
# private tier, install bws, render secrets, and end up with no credential in
|
|
# its logs or its .git/config.
|
|
set -u
|
|
|
|
C=dotup-e2e
|
|
INNER=$(dirname "$0")/e2e-private-tier.sh
|
|
[ -r "$INNER" ] || { echo "missing $INNER"; exit 1; }
|
|
command -v docker >/dev/null || { echo "docker not installed"; exit 1; }
|
|
|
|
cleanup() { docker rm -f "$C" >/dev/null 2>&1 || :; unset BOOT_PW; }
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# ---- credentials, from your terminal only -----------------------------------
|
|
# No default URL, deliberately. Hardcoding the route here would copy it out of
|
|
# Bitwarden and into a git repository, where it would then have to be edited
|
|
# every time the route rotates -- and a stale default is worse than no default,
|
|
# because it fails looking like a password problem.
|
|
printf 'Bootstrap URL (paste from Bitwarden): ' >&2
|
|
IFS= read -r BOOT_URL
|
|
[ -n "$BOOT_URL" ] || { echo "no URL given"; exit 1; }
|
|
# Normalise exactly as dotup does, and for the same reason: the rotation scripts
|
|
# print the full file URL, so that is what Bitwarden holds and what gets pasted.
|
|
# This wrapper appends /bootstrap.env below, so without stripping it first the
|
|
# request becomes .../bootstrap.env/bootstrap.env and the preflight reports
|
|
# "wrong password, wrong route, or endpoint down" -- blaming the credentials for
|
|
# a URL shape, which is the precise failure dotup was just fixed to stop doing.
|
|
# Caught by running this harness with the file URL rather than the directory.
|
|
BOOT_URL=${BOOT_URL%/}
|
|
BOOT_URL=${BOOT_URL%/bootstrap.env}
|
|
|
|
printf 'Username [ben]: ' >&2
|
|
IFS= read -r BOOT_USER
|
|
BOOT_USER=${BOOT_USER:-ben}
|
|
|
|
printf 'Password: ' >&2
|
|
IFS= read -rs BOOT_PW; printf '\n' >&2
|
|
[ -n "$BOOT_PW" ] || { echo "empty password"; exit 1; }
|
|
export BOOT_URL BOOT_USER BOOT_PW
|
|
|
|
# ---- fail fast: do not spend ten minutes to discover a typo ------------------
|
|
# curl -K - reads credentials from stdin rather than argv.
|
|
printf 'checking the endpoint... ' >&2
|
|
code=$(printf 'user = %s:%s\nsilent\nwrite-out = "%%{http_code}"\noutput = "/dev/null"\n' \
|
|
"$BOOT_USER" "$BOOT_PW" | curl -K - -m 20 "${BOOT_URL%/}/bootstrap.env" || true)
|
|
if [ "$code" != 200 ]; then
|
|
echo "HTTP $code -- wrong password, wrong route, or endpoint down. Nothing was run." >&2
|
|
exit 1
|
|
fi
|
|
echo "200" >&2
|
|
|
|
# ---- the run ----------------------------------------------------------------
|
|
# A stock image with nothing preinstalled. If dotup needs a tool, dotup must
|
|
# install it -- that is half of what is being tested.
|
|
docker rm -f "$C" >/dev/null 2>&1 || :
|
|
docker run -d --name "$C" ubuntu:24.04 sleep infinity >/dev/null || exit 1
|
|
docker cp "$INNER" "$C":/root/e2e.sh >/dev/null || exit 1
|
|
|
|
# -e with a bare NAME inherits from this shell. Never NAME=value.
|
|
docker exec -e BOOT_URL -e BOOT_USER -e BOOT_PW "$C" bash /root/e2e.sh
|
|
rc=$?
|
|
|
|
echo
|
|
if [ "$rc" -eq 0 ]; then
|
|
echo "E2E exited 0"
|
|
else
|
|
echo "E2E exited $rc -- the container is left running as $C for inspection."
|
|
echo "If you shell into it, remember that /tmp/private.log inside contains the"
|
|
echo "credentials in cleartext: the inner script has a red() redactor, and the"
|
|
echo "one time it was bypassed for a quick tail, a live password was published"
|
|
echo "and had to be rotated. Pipe anything you read through it."
|
|
trap - EXIT INT TERM # leave the container up; still drop the password
|
|
unset BOOT_PW
|
|
fi
|
|
exit "$rc"
|