Something went wrong. Try again.
Self-hosted Tangled spindle
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117#!/usr/bin/env bashset +xset -euo pipefail
cd "$(dirname "$0")/.."
umask 077tmp=$(mktemp -d "${TMPDIR:-/tmp}/spindle-mill.XXXXXXXX")name="spindle-mill-smoke-${tmp##*.}"volume="$name-data"cleanup() { docker rm -f "$name" >/dev/null 2>&1 || true docker volume rm "$volume" >/dev/null 2>&1 || true rm -rf "$tmp"}trap cleanup EXITtrap 'exit 130' INTtrap 'exit 143' TERM
openssl ecparam -name prime256v1 -genkey -noout -out "$tmp/key.pem"openssl ec -in "$tmp/key.pem" -pubout -conv_form compressed -outform DER \ -out "$tmp/public.der" 2>/dev/nullexport SPINDLE_SIGNING_KEY_PEMSPINDLE_SIGNING_KEY_PEM=$(cat "$tmp/key.pem")docker run --detach --platform linux/amd64 --name "$name" \ --publish 127.0.0.1::6555 \ --mount "type=volume,source=$volume,target=/data,volume-nocopy=true" \ --tmpfs /run/spindle:rw,noexec,nosuid,size=64k,uid=10001,gid=10001,mode=0700 \ --env SPINDLE_SIGNING_KEY_PEM \ --env SPINDLE_ROLE=mill \ --env SPINDLE_SERVER_DEV=true \ --env SPINDLE_SERVER_HOSTNAME=localhost \ --env SPINDLE_SERVER_OWNER=did:plc:zld4i3c3iacwpxsuwcko5yuz \ --env SPINDLE_CONTACT_EMAIL=smoke@example.invalid \ --env SPINDLE_ARTIFACT_STORES_DISK_DIR=/data/artifacts \ --env SPINDLE_MILL_ARTIFACT_STORE=disk \ spindle-mill:v1.20.0 >/dev/nullunset SPINDLE_SIGNING_KEY_PEM
port=$(docker port "$name" 6555/tcp)url="http://$port"ready=falsefor ((attempt = 0; attempt < 60; attempt++)); do if [ "$(curl --silent --output "$tmp/health.json" --write-out '%{http_code}' \ --max-time 2 "$url/_health")" = 200 ]; then ready=true break fi if [ "$(docker inspect --format '{{.State.Running}}' "$name")" != true ]; then break fi sleep 1doneif [ "$ready" != true ]; then echo 'mill: /_health did not return HTTP 200' >&2 exit 1fiecho 'GET /_health: 200'
curl --fail --silent --show-error --max-time 5 \ "$url/.well-known/did.json" --output "$tmp/did.json"python3 - "$tmp/did.json" "$tmp/public.der" <<'PY'import jsonimport pathlibimport sys
with open(sys.argv[1], encoding="utf-8") as f: doc = json.load(f)# P-256 public multicodec (0x1200 as a varint), then the compressed EC point.public = b"\x80\x24" + pathlib.Path(sys.argv[2]).read_bytes()[-33:]alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"value = int.from_bytes(public, "big")encoded = ""while value: value, digit = divmod(value, 58) encoded = alphabet[digit] + encodedexpected = "z" + encodedvalid = doc.get("id") == "did:web:localhost" and any( method.get("type") == "Multikey" and method.get("controller") == "did:web:localhost" and method.get("publicKeyMultibase") == expected for method in doc.get("verificationMethod", []))if not valid: sys.exit("mill: DID document does not contain did:web:localhost and the generated P-256 public key")print("GET /.well-known/did.json: did:web:localhost, matching P-256 public key")PY
mode=$(docker exec "$name" stat -c '%a' /run/spindle/key.pem)if [ "$mode" != 600 ]; then echo "mill: signing key mode is $mode, expected 600" >&2 exit 1fiecho 'Signing key permissions: 600'
uid=$(docker exec "$name" awk '/^Uid:/ { print $2, $3, $4, $5 }' /proc/1/status)if [ "$uid" != '10001 10001 10001 10001' ]; then echo "mill: PID 1 UIDs are $uid, expected 10001 for all four IDs" >&2 exit 1fiecho 'PID 1 UIDs: 10001 (real, effective, saved, filesystem)'
docker stop --signal SIGTERM --timeout 30 "$name" >/dev/nullstatus=$(docker inspect --format '{{.State.ExitCode}}' "$name")if [ "$status" != 0 ]; then echo "mill: SIGTERM exit code is $status, expected 0" >&2 exit 1fiecho 'SIGTERM: clean exit (0)'docker logs "$name" > "$tmp/container.log" 2>&1leaks=$(grep -c 'BEGIN EC PRIVATE KEY' "$tmp/container.log" || true)echo "Private-key markers in container output: $leaks"if [ "$leaks" != 0 ]; then exit 1fiecho 'mill: smoke passed'