#!/usr/bin/env bash
# Verify the release before executing it; claim only, then wait for plan approval.
set -euo pipefail
base_url=""
public_key=""
claim_code=""
while [[ $# -gt 0 ]]; do
  case "$1" in
    --base-url) base_url="$2"; shift 2 ;;
    --public-key) public_key="$2"; shift 2 ;;
    --claim-code) claim_code="$2"; shift 2 ;;
    *) echo "Unknown argument: $1" >&2; exit 2 ;;
  esac
done
[[ "$base_url" == https://* && -n "$public_key" && -n "$claim_code" ]] || { echo 'HTTPS base URL, verification key and claim code are required.' >&2; exit 2; }
[[ "$(uname -s)" == Linux ]] || { echo 'This installer requires Linux.' >&2; exit 2; }
case "$(uname -m)" in x86_64) architecture=amd64 ;; aarch64|arm64) architecture=arm64 ;; *) exit 2 ;; esac
for program in curl python3 openssl docker systemctl; do command -v "$program" >/dev/null || { echo "$program is required" >&2; exit 2; }; done
base_url="${base_url%/}"
work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT
curl --fail --silent --show-error "$base_url/device-agent/v1/releases/linux/$architecture/manifest" -o "$work_dir/manifest.json"
curl --fail --silent --show-error "$base_url/device-agent/v1/releases/linux/$architecture/agent" -o "$work_dir/agent"
python3 - "$work_dir" "$public_key" <<'PY'
import base64, hashlib, json, pathlib, sys
root = pathlib.Path(sys.argv[1])
manifest = json.loads((root/'manifest.json').read_text())
key = base64.b64decode(sys.argv[2], validate=True)
if len(key) != 32 or manifest['public_key'] != sys.argv[2]:
    raise SystemExit('The release verification key differs from the approved CaseDesk key.')
digest = hashlib.sha256((root/'agent').read_bytes()).hexdigest()
if digest != manifest['sha256']:
    raise SystemExit('Agent checksum verification failed.')
(root/'digest').write_text(digest)
(root/'signature').write_bytes(base64.b64decode(manifest['signature'], validate=True))
(root/'key.der').write_bytes(bytes.fromhex('302a300506032b6570032100') + key)
PY
openssl pkeyutl -verify -pubin -keyform DER -inkey "$work_dir/key.der" -rawin -in "$work_dir/digest" -sigfile "$work_dir/signature"
chmod 0755 "$work_dir/agent"
# Never overwrite another claimed device's credential.
state=/var/lib/casedesk-cloud-vm-agent/state.json
sudo test ! -e "$state" || { echo 'An agent is already claimed. Use its service to reconnect.' >&2; exit 1; }
sudo install -d -m 0700 /var/lib/casedesk-cloud-vm-agent
sudo install -m 0755 "$work_dir/agent" /usr/local/bin/casedesk-cloud-vm-agent
identity="$(python3 -c 'import uuid; print(uuid.uuid4())')"
sudo /usr/local/bin/casedesk-cloud-vm-agent --device-agent-url "$base_url/cloud-vm-agent/v1" --device-agent-state "$state" --claim-code "$claim_code" --agent-identity "$identity"
# Values originate from the authenticated claim page; reject service-file control characters.
[[ "$base_url" =~ ^https://[a-zA-Z0-9.-]+(:[0-9]+)?$ ]] || exit 2
[[ "$public_key" =~ ^[a-zA-Z0-9+/=]+$ ]] || exit 2
sudo tee /etc/systemd/system/casedesk-cloud-vm-agent.service >/dev/null <<EOF
[Unit]
Description=CaseDesk approved AWS GPU VM runtime
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service
[Service]
Type=simple
ExecStart=/usr/local/bin/casedesk-cloud-vm-agent --device-agent-url $base_url/cloud-vm-agent/v1 --device-agent-state $state --device-agent-config-public-key $public_key
Restart=always
RestartSec=10
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now casedesk-cloud-vm-agent.service
echo 'Agent connected. Return to CaseDesk to review and approve the runtime plan.'
