rq-historical: add READ-ONLY code/hashes/code-list (allowlist) for RQ Phase 13.5
This commit is contained in:
parent
a0c388ab18
commit
bbfd85e472
1 changed files with 132 additions and 0 deletions
132
red-queen-architecture/control-plane/cp2a2_2b/rq-historical
Normal file
132
red-queen-architecture/control-plane/cp2a2_2b/rq-historical
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# ============================================================================
|
||||||
|
# rq-historical — eng begrenzter root-Wrapper fuer Red Queen (rq-host)
|
||||||
|
# RED-QUEEN-VPS-HOST-ACCESS + PHASE-13.5-READONLY | Rain Ocampo (Hermes) | 2026-08-29
|
||||||
|
#
|
||||||
|
# EINZIGER ZWECK: kontrollierter READ-ONLY-Zugriff + freigegebener Backfill-
|
||||||
|
# Start ausschliesslich auf den Historical-Service. Least-Privilege.
|
||||||
|
#
|
||||||
|
# SICHERHEIT:
|
||||||
|
# - Container-/Skript-Namen sind FEST im Script (kein Benutzer-Argument
|
||||||
|
# fuer Container/Skript/Pfad).
|
||||||
|
# - Alle Subkommandos akzeptieren NUR strikt validierte, vollstaendig
|
||||||
|
# konsumierte Argumente; unbekannte/ueberzaehlige Argumente -> ERR.
|
||||||
|
# - code/hashes/code-list nutzen eine FESTE Allowlist: User uebergibt nur
|
||||||
|
# einen Key, der intern auf einen festen Containerpfad gemappt wird.
|
||||||
|
# KEIN frei durchgereichter Pfad, KEIN Shell-String aus User-Input.
|
||||||
|
# - Argumente werden als argv-Array an `docker exec` uebergeben
|
||||||
|
# (KEINE Shell-Interpolation von Benutzereingaben).
|
||||||
|
# - KEIN sudo ALL / NOPASSWD ALL / keine Root-Shell / kein docker run.
|
||||||
|
#
|
||||||
|
# AUFRUF (ueber /etc/sudoers.d/rq-historical, NUR als root):
|
||||||
|
# sudo rq-historical ps
|
||||||
|
# sudo rq-historical inspect
|
||||||
|
# sudo rq-historical logs [--tail N]
|
||||||
|
# sudo rq-historical run [--start YYYY-MM-DD] [--end YYYY-MM-DD] [--limit-days N]
|
||||||
|
# sudo rq-historical code <runner|backfill|pipeline|repository|provenance|trust|sanity|trust_gate>
|
||||||
|
# sudo rq-historical hashes
|
||||||
|
# sudo rq-historical code-list
|
||||||
|
# ============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CONTAINER=historical-service
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ Allowlist
|
||||||
|
# FESTE Mapping-Tabelle (Key -> Containerpfad). Read-only, hart im Script.
|
||||||
|
# Keys NICHT benutzerdefiniert erweiterbar.
|
||||||
|
# NOTE: Bei assign-assoc-array die Assignments OHNE Leerzeichen um '=' schreiben,
|
||||||
|
# sonst Syntaxfehler. (Korrektur unten: einzeilig mit declare -A init.)
|
||||||
|
declare -A CODE_FILES=(
|
||||||
|
[runner]="/app/app/run_backfill_year.py"
|
||||||
|
[backfill]="/app/app/backfill.py"
|
||||||
|
[pipeline]="/app/app/pipeline_v2.py"
|
||||||
|
[repository]="/app/app/persistence/repository.py"
|
||||||
|
[provenance]="/app/app/trust/provenance.py"
|
||||||
|
[trust]="/app/app/trust/trust.py"
|
||||||
|
[sanity]="/app/app/trust/sanity.py"
|
||||||
|
[trust_gate]="/app/app/trust/trust_gate.py"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Relevanter Pfad fuer den 'run'-Subbefehl (Backfill-Entrypoint)
|
||||||
|
SCRIPT=/app/app/run_backfill_year.py
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- Validierung
|
||||||
|
die() { echo "ERR: $*" >&2; exit 2; }
|
||||||
|
req_ok() {
|
||||||
|
docker inspect -f '{{.State.Running}}' "$CONTAINER" >/dev/null 2>&1 \
|
||||||
|
|| die "Container '$CONTAINER' nicht vorhanden oder nicht am Laufen"
|
||||||
|
}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------- dispatch
|
||||||
|
SUBCMD="${1:-}"
|
||||||
|
shift || true
|
||||||
|
|
||||||
|
case "$SUBCMD" in
|
||||||
|
ps)
|
||||||
|
[ $# -eq 0 ] || die "unerlaubtes Argument 'ps $*'"
|
||||||
|
exec docker ps
|
||||||
|
;;
|
||||||
|
inspect)
|
||||||
|
req_ok
|
||||||
|
[ $# -eq 0 ] || die "unerlaubtes Argument 'inspect $*'"
|
||||||
|
exec docker inspect "$CONTAINER"
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
req_ok
|
||||||
|
tail_n=200
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--tail)
|
||||||
|
[ $# -ge 2 ] || die "--tail braucht Wert"
|
||||||
|
[[ "$2" =~ ^[0-9]+$ ]] || die "ungueltiges --tail"
|
||||||
|
tail_n="$2"; shift 2 ;;
|
||||||
|
*) die "unerlaubtes Argument 'logs $1'" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
exec docker logs --tail "$tail_n" "$CONTAINER"
|
||||||
|
;;
|
||||||
|
run)
|
||||||
|
req_ok
|
||||||
|
declare -a RUN=()
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--start) [[ "${2:-}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] || die "ungueltiges --start"; RUN+=("--start" "$2"); shift 2 ;;
|
||||||
|
--end) [[ "${2:-}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] || die "ungueltiges --end"; RUN+=("--end" "$2"); shift 2 ;;
|
||||||
|
--limit-days) [[ "${2:-}" =~ ^[0-9]+$ ]] || die "ungueltiges --limit-days"; RUN+=("--limit-days" "$2"); shift 2 ;;
|
||||||
|
*) die "unerlaubtes Argument 'run $1'" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo "[rq-historical] Start: docker exec $CONTAINER python $SCRIPT ${RUN[*]}" >&2
|
||||||
|
exec docker exec "$CONTAINER" python "$SCRIPT" "${RUN[@]}"
|
||||||
|
;;
|
||||||
|
code)
|
||||||
|
# Fester Allowlist-Key -> fester Containerpfad. KEIN frei gereichter Pfad.
|
||||||
|
req_ok
|
||||||
|
[ $# -eq 1 ] || die "code braucht genau EINEN Key (siehe code-list)"
|
||||||
|
key="$1"
|
||||||
|
path="${CODE_FILES[$key]:-}"
|
||||||
|
[ -n "$path" ] || die "unbekannter Key 'code $key' (siehe code-list)"
|
||||||
|
exec docker exec "$CONTAINER" cat "$path"
|
||||||
|
;;
|
||||||
|
hashes)
|
||||||
|
# SHA256 der festen Allowlist-Dateien aus dem laufenden Container.
|
||||||
|
req_ok
|
||||||
|
[ $# -eq 0 ] || die "unerlaubtes Argument 'hashes $*'"
|
||||||
|
# Feste, vollstaendig konsumierte Dateiliste -> argv-Array (keine Interpolation).
|
||||||
|
declare -a PATHS=()
|
||||||
|
for k in "${!CODE_FILES[@]}"; do PATHS+=("${CODE_FILES[$k]}"); done
|
||||||
|
exec docker exec "$CONTAINER" sha256sum "${PATHS[@]}"
|
||||||
|
;;
|
||||||
|
code-list)
|
||||||
|
# Nur die verfuegbaren fixen Keys + Containerpfade anzeigen. Kein FS-Zugriff.
|
||||||
|
req_ok
|
||||||
|
[ $# -eq 0 ] || die "unerlaubtes Argument 'code-list $*'"
|
||||||
|
echo "Verfuegbare READ-ONLY-Code-Keys (historical-service):"
|
||||||
|
for k in "${!CODE_FILES[@]}"; do
|
||||||
|
printf ' %-11s -> %s\n' "$k" "${CODE_FILES[$k]}"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Aufruf: rq-historical {ps|inspect|logs [--tail N]|run [--start --end --limit-days]|code <KEY>|hashes|code-list}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Loading…
Reference in a new issue