feat: add deployment foundation and cross-device handoff
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Local opt-in public deb download/hash test. No extraction, APT or installation.
|
||||
# Called by probe-docker-repository.sh after authenticated metadata verification.
|
||||
set -euo pipefail
|
||||
[[ $# == 3 && -f "$1" && -d "$2" ]]
|
||||
binary=$1
|
||||
metadata_dir=$2
|
||||
metadata_request=$3
|
||||
probe_dir=$(mktemp -d /tmp/server-deploy-artifacts.XXXXXX)
|
||||
chmod 700 "$probe_dir"
|
||||
artifact_dir="$probe_dir/debs"
|
||||
mkdir -m 700 "$artifact_dir"
|
||||
# Only authenticated lock paths, fixed origin, no caller-provided download URLs.
|
||||
python3 -I -c 'import json,re,sys; r=json.load(sys.stdin); assert r["repositoryAuthenticated"] is True; p=r["lock"]["packages"]; assert len(p)==5; [None if re.fullmatch(r"dists/resolute/pool/stable/amd64/[a-z0-9.+~_-]+\.deb",x["filename"]) and 0<x["size"]<=536870912 else sys.exit(1) for x in p]; [print(x["filename"],x["size"]) for x in p]' < "$metadata_dir/result.json" > "$probe_dir/downloads"
|
||||
while read -r filename size; do
|
||||
curl --fail --silent --show-error --proto '=https' --max-time 90 --max-filesize "$size" \
|
||||
"https://download.docker.com/linux/ubuntu/$filename" -o "$artifact_dir/${filename##*/}"
|
||||
done < "$probe_dir/downloads"
|
||||
request=$(printf '%s\n' "$metadata_request" | python3 -I -c 'import json,sys; r=json.load(sys.stdin); r["artifactDirectory"]=sys.argv[1]; print(json.dumps(r))' "$artifact_dir")
|
||||
printf '%s\n' "$request" | "$binary" verify-artifacts > "$probe_dir/result.json"
|
||||
python3 -I -c 'import json,sys; r=json.load(sys.stdin); assert r["repositoryAuthenticated"] is True; assert r["packageBytesVerified"] is True; assert r["executable"] is False; assert len(r["lock"]["packages"])==5' < "$probe_dir/result.json"
|
||||
cat "$probe_dir/result.json"
|
||||
# Same-size mutation: digest comparison, not an earlier size check, must reject.
|
||||
first=$(head -n 1 "$probe_dir/downloads")
|
||||
filename=${first% *}
|
||||
printf 'X' | dd of="$artifact_dir/${filename##*/}" bs=1 count=1 conv=notrunc status=none
|
||||
if printf '%s\n' "$request" | "$binary" verify-artifacts > "$probe_dir/rejected.json"; then
|
||||
printf 'ERROR: same-size deb tamper accepted\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ ! -s "$probe_dir/rejected.json" ]]
|
||||
printf 'Five real deb files verified; same-size tamper rejected. Local artifacts: %s\n' "$artifact_dir"
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
# Local metadata-only probe. No APT changes or software installation.
|
||||
set -euo pipefail
|
||||
task_dir=$(mktemp -d /tmp/server-deploy-repository.XXXXXX)
|
||||
chmod 700 "$task_dir"
|
||||
base=https://download.docker.com/linux/ubuntu
|
||||
curl --fail --silent --show-error --proto '=https' --max-time 45 --max-filesize 1048576 "$base/gpg" -o "$task_dir/docker.asc"
|
||||
curl --fail --silent --show-error --proto '=https' --max-time 45 --max-filesize 1048576 "$base/dists/resolute/Release" -o "$task_dir/Release"
|
||||
curl --fail --silent --show-error --proto '=https' --max-time 45 --max-filesize 65536 "$base/dists/resolute/Release.gpg" -o "$task_dir/Release.gpg"
|
||||
curl --fail --silent --show-error --proto '=https' --max-time 45 --max-filesize 16777216 "$base/dists/resolute/stable/binary-amd64/Packages" -o "$task_dir/Packages"
|
||||
gpg --batch --no-options --homedir "$task_dir" --with-colons --show-keys "$task_dir/docker.asc"
|
||||
sha256sum "$task_dir/docker.asc"
|
||||
gpg --batch --no-options --homedir "$task_dir" --dearmor --output "$task_dir/docker.gpg" "$task_dir/docker.asc"
|
||||
gpgv --homedir "$task_dir" --keyring "$task_dir/docker.gpg" --status-fd 1 "$task_dir/Release.gpg" "$task_dir/Release"
|
||||
head -n 12 "$task_dir/Release"
|
||||
awk '/^Package: (docker-ce|docker-ce-cli|containerd.io|docker-buildx-plugin|docker-compose-plugin)$/ {name=$2} /^Version:/ && name!="" {print name, $2; name=""}' "$task_dir/Packages"
|
||||
# Optional prebuilt local binary: verifies the same downloaded snapshots. This
|
||||
# selects explicit fixture versions, not an installation or latest-version policy.
|
||||
if [[ $# == 1 ]]; then
|
||||
engine=$(awk '/^Package: docker-ce$/ {p=1} p && /^Version:/ {print $2; exit}' "$task_dir/Packages")
|
||||
containerd=$(awk '/^Package: containerd.io$/ {p=1} p && /^Version:/ {print $2; exit}' "$task_dir/Packages")
|
||||
buildx=$(awk '/^Package: docker-buildx-plugin$/ {p=1} p && /^Version:/ {print $2; exit}' "$task_dir/Packages")
|
||||
compose=$(awk '/^Package: docker-compose-plugin$/ {p=1} p && /^Version:/ {print $2; exit}' "$task_dir/Packages")
|
||||
for version in "$engine" "$containerd" "$buildx" "$compose"; do
|
||||
[[ "$version" =~ ^[0-9A-Za-z.+:~_-]+$ ]] || exit 1
|
||||
done
|
||||
request=$(printf '{"directory":"%s","suite":"resolute","architecture":"amd64","versions":{"docker-ce":"%s","docker-ce-cli":"%s","containerd.io":"%s","docker-buildx-plugin":"%s","docker-compose-plugin":"%s"}}' "$task_dir" "$engine" "$engine" "$containerd" "$buildx" "$compose")
|
||||
printf '%s\n' "$request" | "$1" verify-repository > "$task_dir/result.json"
|
||||
python3 -I -c 'import json,sys; r=json.load(sys.stdin); p=sys.argv[1:]; assert r["repositoryAuthenticated"] is True; assert r["executable"] is False; assert r["packageBytesVerified"] is False; assert {x["name"]:x["version"] for x in r["lock"]["packages"]} == dict(zip(["docker-ce","docker-ce-cli","containerd.io","docker-buildx-plugin","docker-compose-plugin"],p)); assert len(r["lock"]["packages"])==5' "$engine" "$engine" "$containerd" "$buildx" "$compose" < "$task_dir/result.json"
|
||||
cat "$task_dir/result.json"
|
||||
if [[ -n "${DEPLOYCTL_TEST_GO:-}" ]]; then
|
||||
DEPLOYCTL_REPOSITORY_FIXTURE="$task_dir" "$DEPLOYCTL_TEST_GO" test ./internal/aptrepo -run TestStagedSignatureIntegration -count=1 -v
|
||||
fi
|
||||
if [[ "${DEPLOYCTL_ONLINE_ARTIFACT_PROBE:-0}" == 1 ]]; then
|
||||
bash scripts/probe-docker-artifacts.sh "$1" "$task_dir" "$request"
|
||||
fi
|
||||
cp -- "$task_dir/Packages" "$task_dir/Packages.original"
|
||||
awk '/^SHA256:/ && !changed {c=substr($2,1,1); $2=(c=="0" ? "1" : "0") substr($2,2); changed=1} {print}' "$task_dir/Packages.original" > "$task_dir/Packages"
|
||||
if printf '%s\n' "$request" | "$1" verify-repository > "$task_dir/rejected.json"; then
|
||||
printf 'ERROR: tampered Packages accepted\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ ! -s "$task_dir/rejected.json" ]]
|
||||
mv -- "$task_dir/Packages.original" "$task_dir/Packages"
|
||||
printf 'Tampered Packages rejected as expected.\n'
|
||||
cp -- "$task_dir/Release" "$task_dir/Release.original"
|
||||
awk '/^Date:/ {n=split($0,parts,":"); c=substr(parts[n],1,1); parts[n]=(c=="0" ? "1" : "0") substr(parts[n],2); line=parts[1]; for(i=2;i<=n;i++) line=line ":" parts[i]; print line; next} {print}' "$task_dir/Release.original" > "$task_dir/Release"
|
||||
if printf '%s\n' "$request" | "$1" verify-repository > "$task_dir/rejected.json"; then
|
||||
printf 'ERROR: tampered Release accepted\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ ! -s "$task_dir/rejected.json" ]]
|
||||
printf 'Tampered signed Release rejected as expected.\n'
|
||||
fi
|
||||
printf 'Local temporary probe directory: %s\n' "$task_dir"
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run on Linux/WSL with a previously SHA-256-verified official Go tarball.
|
||||
# The caller owns download provenance. No package installation or production SSH.
|
||||
set -euo pipefail
|
||||
if [[ $# != 1 || ! -f "$1" ]]; then
|
||||
printf 'usage: bash scripts/verify-linux.sh /path/to/verified-go.linux-amd64.tar.gz\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
task_dir=$(mktemp -d /tmp/server-deploy-test.XXXXXX)
|
||||
tar -xzf "$1" -C "$task_dir"
|
||||
export GOCACHE="$task_dir/cache"
|
||||
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||
"$task_dir/go/bin/go" test ./... -count=1 -v -timeout=60s
|
||||
"$task_dir/go/bin/go" vet ./...
|
||||
"$task_dir/go/bin/go" test -race ./... -count=1 -timeout=60s
|
||||
"$task_dir/go/bin/go" build -o "$task_dir/deployctl" ./cmd/deployctl
|
||||
"$task_dir/deployctl" plan < protocol/examples/plan-request.json
|
||||
"$task_dir/deployctl" inspect
|
||||
"$task_dir/deployctl" preflight
|
||||
if [[ "${DEPLOYCTL_ONLINE_REPOSITORY_PROBE:-0}" == 1 ]]; then
|
||||
DEPLOYCTL_TEST_GO="$task_dir/go/bin/go" bash scripts/probe-docker-repository.sh "$task_dir/deployctl"
|
||||
fi
|
||||
printf 'Verification artifacts retained at: %s\n' "$task_dir"
|
||||
Reference in New Issue
Block a user