- Institutional / JVMTM / reserve-provenance / GRU transport + standards JSON - Validation and verify scripts (Blockscout labels, x402, GRU preflight, P1 local path) - Wormhole wiring in AGENTS, MCP_SETUP, MASTER_INDEX, 04-configuration README - Meta docs, integration gaps, live verification log, architecture updates - CI validate-config workflow updates Operator/LAN items, submodule working trees, and public token-aggregation edge routes remain follow-up (see TODOS_CONSOLIDATED P1). Made-with: Cursor
66 lines
2.5 KiB
Bash
Executable File
66 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Prove ACK instant is before journal credit (regulatory ordering: ack before credit).
|
|
# Usage: verify-ack-before-credit.sh <ack.json> <journalEntryId>
|
|
# ack.json: include "timestamp" or "ack_timestamp" as full ISO-8601 (UTC recommended).
|
|
# Fineract often returns transactionDate as YYYY-MM-DD only; we treat credit as end of that UTC day
|
|
# (conservative: ACK must be strictly before 23:59:59.999Z on that date unless you extend this script).
|
|
#
|
|
# Exit: 0 pass, 1 fail ordering, 2 usage/API/parse error.
|
|
set -eo pipefail
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
# shellcheck source=scripts/lib/load-project-env.sh
|
|
set +u
|
|
source "${REPO_ROOT}/scripts/lib/load-project-env.sh"
|
|
set -euo pipefail
|
|
|
|
ACK_FILE="${1:-}"
|
|
JE_ID="${2:-}"
|
|
if [[ -z "$ACK_FILE" || -z "$JE_ID" || ! -f "$ACK_FILE" ]]; then
|
|
echo "Usage: $0 <ack.json> <journalEntryId>" >&2
|
|
exit 2
|
|
fi
|
|
|
|
BASE_URL="${OMNL_FINERACT_BASE_URL:-}"
|
|
PASS="${OMNL_FINERACT_PASSWORD:-}"
|
|
USER="${OMNL_FINERACT_USER:-app.omnl}"
|
|
TENANT="${OMNL_FINERACT_TENANT:-omnl}"
|
|
if [[ -z "$BASE_URL" || -z "$PASS" ]]; then
|
|
echo "error: OMNL_FINERACT_BASE_URL and OMNL_FINERACT_PASSWORD required" >&2
|
|
exit 2
|
|
fi
|
|
|
|
ACK_TS="$(jq -r '.timestamp // .ack_timestamp // empty' "$ACK_FILE")"
|
|
[[ -z "$ACK_TS" ]] && echo "error: ack file missing timestamp / ack_timestamp" >&2 && exit 2
|
|
|
|
JE_JSON="$(curl -sS -H "Fineract-Platform-TenantId: ${TENANT}" -u "${USER}:${PASS}" "${BASE_URL}/journalentries/${JE_ID}")"
|
|
CREDIT_DATE="$(echo "$JE_JSON" | jq -r '.transactionDate // empty')"
|
|
[[ -z "$CREDIT_DATE" ]] && echo "error: journalentries/${JE_ID} missing transactionDate" >&2 && exit 2
|
|
|
|
ACK_TS="$ACK_TS" CREDIT_DATE="$CREDIT_DATE" python3 <<'PY'
|
|
import os, sys
|
|
from datetime import datetime, timezone
|
|
|
|
ack_s = os.environ["ACK_TS"].strip().replace("Z", "+00:00")
|
|
try:
|
|
ack = datetime.fromisoformat(ack_s)
|
|
except ValueError:
|
|
print("error: cannot parse ACK timestamp as ISO-8601", file=sys.stderr)
|
|
sys.exit(2)
|
|
if ack.tzinfo is None:
|
|
ack = ack.replace(tzinfo=timezone.utc)
|
|
|
|
d = os.environ["CREDIT_DATE"].strip()[:10]
|
|
try:
|
|
y, m, day = (int(d[0:4]), int(d[5:7]), int(d[8:10]))
|
|
credit_end = datetime(y, m, day, 23, 59, 59, 999000, tzinfo=timezone.utc)
|
|
except Exception:
|
|
print("error: bad transactionDate", file=sys.stderr)
|
|
sys.exit(2)
|
|
|
|
if ack < credit_end:
|
|
print(f"OK: ack {ack.isoformat()} is before credit value-date end {credit_end.isoformat()}")
|
|
sys.exit(0)
|
|
print(f"FAIL: ack {ack.isoformat()} is not before credit window end {credit_end.isoformat()}", file=sys.stderr)
|
|
sys.exit(1)
|
|
PY
|