Add the Bird Control Plane gateway, signed webhook ingestion, policy-gated writes, fail-closed production auto-activation, and RSA-OAEP bootstrap credential flow.
80 lines
3.3 KiB
Bash
80 lines
3.3 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
|
|
bootstrap_url='https://api.truckwash.io:4433/bird/control-plane/v1/bootstrap'
|
|
status_url='https://api.truckwash.io:4433/bird/control-plane/v1/status'
|
|
expected_algorithm='RSA-OAEP-256'
|
|
expected_fingerprint='6dc63c6ffe33b8de0b1396d7f529f56aea0a685ef98168016161cf721ddc8c21'
|
|
private_key='/home/jeppe/.openclaw/credentials/bird.bootstrap-private.pem'
|
|
credential_dir='/home/jeppe/.openclaw/credentials'
|
|
destination="$credential_dir/bird.gateway-token"
|
|
|
|
umask 077
|
|
mkdir -p "$credential_dir"
|
|
envelope_file="$(mktemp "$credential_dir/.bird-bootstrap-envelope.XXXXXX")"
|
|
candidate_file="$(mktemp "$credential_dir/.bird-gateway-token.XXXXXX")"
|
|
payload_file="$(mktemp "$credential_dir/.bird-bootstrap-payload.XXXXXX")"
|
|
status_file="$(mktemp "$credential_dir/.bird-bootstrap-status.XXXXXX")"
|
|
cleanup() {
|
|
rm -f "$envelope_file" "$candidate_file" "$payload_file" "$status_file"
|
|
}
|
|
trap cleanup EXIT HUP INT TERM
|
|
|
|
test -r "$private_key"
|
|
test "$(stat -c '%a' "$private_key")" = '600'
|
|
|
|
curl --proto '=https' --tlsv1.2 --fail --silent --show-error \
|
|
--max-time 30 "$bootstrap_url" > "$envelope_file"
|
|
|
|
test "$(jq -r '.success // false' "$envelope_file")" = 'true'
|
|
test "$(jq -r '.data.algorithm // empty' "$envelope_file")" = "$expected_algorithm"
|
|
test "$(jq -r '.data.keyFingerprint // empty' "$envelope_file")" = "$expected_fingerprint"
|
|
jq -e '.data | keys == ["algorithm","ciphertext","keyFingerprint","tokenVersion","updatedAt"]' \
|
|
"$envelope_file" >/dev/null
|
|
jq -e '.data.tokenVersion | type == "number" and . >= 1 and floor == .' \
|
|
"$envelope_file" >/dev/null
|
|
jq -e '.data.updatedAt | type == "string" and test("^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$")' \
|
|
"$envelope_file" >/dev/null
|
|
jq -e '.data.ciphertext | type == "string" and length == 512 and test("^[A-Za-z0-9+/]{512}$")' \
|
|
"$envelope_file" >/dev/null
|
|
|
|
jq -r '.data.ciphertext' "$envelope_file" \
|
|
| base64 -d \
|
|
| openssl pkeyutl -decrypt -inkey "$private_key" \
|
|
-pkeyopt rsa_padding_mode:oaep \
|
|
-pkeyopt rsa_oaep_md:sha256 \
|
|
-pkeyopt rsa_mgf1_md:sha256 > "$payload_file"
|
|
|
|
jq -e '. | keys == ["algorithm","keyFingerprint","token","tokenVersion","updatedAt"]' \
|
|
"$payload_file" >/dev/null
|
|
test "$(jq -r '.algorithm // empty' "$payload_file")" = "$expected_algorithm"
|
|
test "$(jq -r '.keyFingerprint // empty' "$payload_file")" = "$expected_fingerprint"
|
|
test "$(jq -r '.tokenVersion // empty' "$payload_file")" = \
|
|
"$(jq -r '.data.tokenVersion' "$envelope_file")"
|
|
test "$(jq -r '.updatedAt // empty' "$payload_file")" = \
|
|
"$(jq -r '.data.updatedAt' "$envelope_file")"
|
|
jq -j '.token' "$payload_file" > "$candidate_file"
|
|
|
|
test "$(wc -c < "$candidate_file")" = '64'
|
|
grep -Eq '^[A-Za-z0-9_-]{64}$' "$candidate_file"
|
|
chmod 600 "$candidate_file"
|
|
|
|
token="$(cat "$candidate_file")"
|
|
{
|
|
printf 'url = "%s"\n' "$status_url"
|
|
printf 'proto = "=https"\n'
|
|
printf 'tlsv1.2\n'
|
|
printf 'fail\nsilent\nshow-error\n'
|
|
printf 'max-time = 30\n'
|
|
printf 'header = "Authorization: Bearer %s"\n' "$token"
|
|
} | curl --config - > "$status_file"
|
|
unset token
|
|
|
|
jq -e '.success == true and .data.enabled == true and .data.webhookConfigured == true' \
|
|
"$status_file" >/dev/null
|
|
mv -f "$candidate_file" "$destination"
|
|
chmod 600 "$destination"
|
|
trap - EXIT HUP INT TERM
|
|
rm -f "$envelope_file" "$payload_file" "$status_file"
|
|
printf 'Bird gateway credential bootstrapped and authenticated.\n'
|