#!/bin/bash # Self-healing Grist API wrapper # Tries cached token first, auto-refreshes from Vault on failure TOKEN_DIR="/home/jcbeasley/.openclaw/workspace/.tokens" VAULT_URL="https://beavault.beawit.net:8200" GRIST_URL="https://grist.beawit.net" GRIST_TOKEN_FILE="$TOKEN_DIR/grist_token" METHOD="$1" API_PATH="$2" PAYLOAD_FILE="$3" if [ -z "$METHOD" ] || [ -z "$API_PATH" ]; then echo "Usage: bash grist_api.sh [payload_file]" exit 1 fi # Function to refresh tokens from Vault refresh_tokens() { mkdir -p "$TOKEN_DIR" # Vault auth curl -sk -X POST \ -d '{"role_id":"75d2dcfb-9c65-7f60-59b4-eee8c7f8dc0e","secret_id":"6202b465-2f25-547c-ec07-f47cfc4dda3e"}' \ "$VAULT_URL/v1/auth/approle/login" \ > "$TOKEN_DIR/vault_auth.json" python3 -c " import json with open('$TOKEN_DIR/vault_auth.json') as f: data = json.load(f) with open('$TOKEN_DIR/vault_token', 'w') as out: out.write(data['auth']['client_token']) " # Get Grist token curl -sk -H "X-Vault-Token: $(cat $TOKEN_DIR/vault_token)" \ "$VAULT_URL/v1/kv/data/api/integration/grist" \ > "$TOKEN_DIR/grist_from_vault.json" python3 -c " import json with open('$TOKEN_DIR/grist_from_vault.json') as f: data = json.load(f) with open('$TOKEN_DIR/grist_token', 'w') as out: out.write(data['data']['data']['token']) " rm -f "$TOKEN_DIR/vault_auth.json" "$TOKEN_DIR/grist_from_vault.json" } # Function to make Grist API call api_call() { local http_code if [ "$METHOD" = "GET" ]; then http_code=$(curl -sk -w "%{http_code}" -o "$TOKEN_DIR/last_response.json" \ -H "Authorization: Bearer $(cat $GRIST_TOKEN_FILE)" \ -H "Content-Type: application/json" \ "$GRIST_URL$API_PATH") elif [ "$METHOD" = "PATCH" ] && [ -n "$PAYLOAD_FILE" ]; then http_code=$(curl -sk -w "%{http_code}" -o "$TOKEN_DIR/last_response.json" \ -H "Authorization: Bearer $(cat $GRIST_TOKEN_FILE)" \ -H "Content-Type: application/json" \ -X PATCH \ -d "@$PAYLOAD_FILE" \ "$GRIST_URL$API_PATH") else echo "Error: Unsupported method or missing payload" return 1 fi echo "$http_code" } # Main logic: try cached token, refresh on failure, retry if [ ! -f "$GRIST_TOKEN_FILE" ]; then refresh_tokens fi HTTP_CODE=$(api_call) # If unauthorized (401) or forbidden (403), refresh and retry if [ "$HTTP_CODE" = "401" ] || [ "$HTTP_CODE" = "403" ]; then refresh_tokens HTTP_CODE=$(api_call) fi # Output response if [ -f "$TOKEN_DIR/last_response.json" ]; then cat "$TOKEN_DIR/last_response.json" rm -f "$TOKEN_DIR/last_response.json" fi # Return appropriate exit code if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "204" ]; then exit 0 else echo "Error: HTTP $HTTP_CODE" >&2 exit 1 fi