Files
erp/.claude/skills/dolibarr-sandbox-write/scripts/dol-prod-write.sh
Gabriel Radureau 00d86b47a3 feat(skills,cli): promote-to-prod replay (ADR-0003 capstone) + supplier payment fix
The human-gated path that carries a reviewed sandbox change to prod.

- promote-plan.sh: render a manifest (JSON array of write ops with symbolic @refs
  instead of ids — portable sandbox->prod) as a human-readable change-set.
- promote-apply.sh <manifest> --target sandbox|prod: replay it, resolving each
  @ref to the id actually created during the run (dependent ops wire up). sandbox
  rehearses via dol-write.sh; prod via dol-prod-write.sh.
- dol-prod-write.sh: the ONLY prod-write path. Prod key read from the ENVIRONMENT
  only (DOLIBARR_PROD_WRITE_KEY, never a stored .env); every write refused unless
  ARCO_PROMOTE_CONFIRM=I-UNDERSTAND-THIS-WRITES-PROD.
- create scripts take a DOL_WRITE override so promote-apply reuses them per target.
- bin/arcodange: `promote {plan|apply}` group + example manifest.
- payment-record.sh: fixed supplier payments (payment_mode_id + closepaidinvoices).

Proven live: plan renders; apply --target sandbox replays a 3-op chain with refs
resolved (@tp1->id, invoice socid=@tp1, payment invoice=@inv1); --target prod
without the confirm flag is REFUSED before sending. Supplier payment now works
end-to-end via the script.

Limitation (documented): manifests reference entities they create (@ref);
pre-existing prod entities need business-key resolution (follow-up).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-29 23:48:47 +02:00

40 lines
2.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# GATED prod-write wrapper — the ONLY path in this skill that writes PRODUCTION.
#
# Used solely by promote-apply.sh --target prod, at promotion time. Two deliberate
# frictions make accidental or autonomous prod writes impossible (ADR-0003):
# 1. The prod write key is read from the ENVIRONMENT (DOLIBARR_PROD_WRITE_KEY),
# never from a stored .env — a human must supply it per invocation.
# 2. Any write method (POST/PUT/DELETE/PATCH) is REFUSED unless ARCO_PROMOTE_CONFIRM
# equals exactly "I-UNDERSTAND-THIS-WRITES-PROD".
# GET is allowed (id read-back) but still needs the key.
#
# DOLIBARR_PROD_WRITE_KEY=… ARCO_PROMOTE_CONFIRM=I-UNDERSTAND-THIS-WRITES-PROD \
# dol-prod-write.sh POST /thirdparties '{...}'
set -euo pipefail
PROD_URL="${DOLIBARR_PROD_URL:-https://erp.arcodange.lab}"
: "${DOLIBARR_PROD_WRITE_KEY:?dol-prod-write.sh: DOLIBARR_PROD_WRITE_KEY must be supplied in the environment (never stored)}"
if [[ $# -lt 2 ]]; then echo "usage: dol-prod-write.sh <METHOD> <path> [body]" >&2; exit 2; fi
METHOD="$1"; API_PATH="$2"; BODY="${3-}"
case "${METHOD}" in
GET) ;;
POST|PUT|DELETE|PATCH)
if [[ "${ARCO_PROMOTE_CONFIRM:-}" != "I-UNDERSTAND-THIS-WRITES-PROD" ]]; then
echo "dol-prod-write.sh: REFUSING ${METHOD} ${API_PATH} on PRODUCTION (${PROD_URL})." >&2
echo " Set ARCO_PROMOTE_CONFIRM=I-UNDERSTAND-THIS-WRITES-PROD to authorize prod writes." >&2
exit 3
fi ;;
*) echo "dol-prod-write.sh: unsupported method '${METHOD}'" >&2; exit 2 ;;
esac
CURL_ARGS=( -sS -X "${METHOD}" -H "DOLAPIKEY: ${DOLIBARR_PROD_WRITE_KEY}" -H "Accept: application/json" --max-time 30 )
[[ -n "${BODY}" ]] && CURL_ARGS+=( -H "Content-Type: application/json" --data "${BODY}" )
BODY_FILE="$(mktemp -t dolprod.XXXXXX)"; trap 'rm -f "${BODY_FILE}"' EXIT
HTTP_CODE=$(curl "${CURL_ARGS[@]}" -o "${BODY_FILE}" -w "%{http_code}" "${PROD_URL}/api/index.php${API_PATH}")
cat "${BODY_FILE}"
if [[ "${HTTP_CODE}" -ge 400 ]]; then
echo "" >&2; echo "dol-prod-write.sh: HTTP ${HTTP_CODE} on ${METHOD} ${API_PATH}" >&2; exit 1
fi