diff --git a/openchamber-boostrap.sh b/openchamber-boostrap.sh index be0cadd..5324941 100644 --- a/openchamber-boostrap.sh +++ b/openchamber-boostrap.sh @@ -17,9 +17,13 @@ # 4. Installs opencode (if missing) # 5. Installs/updates @openchamber/web to latest via bun (every run) # 6. Installs the enterprise policy file (/etc/openchamber/policy.json): -# enterprise mode + organization + pinned relay. Without root it -# falls back to OPENCHAMBER_ENTERPRISE_MODE=1 in the rc files -# (weaker lock — the user can edit those). Skip with --no-enterprise. +# enterprise mode + organization + pinned relay. Pass +# --enterprise to install your own policy (e.g. +# openchamber-policy.json from this repo); otherwise built-in +# defaults are used. --relay-url overrides the file's relayUrl. +# Without root it falls back to OPENCHAMBER_ENTERPRISE_MODE=1 in +# the rc files (weaker lock — the user can edit those). Skip with +# --no-enterprise. # 7. Syncs ~/.config/opencode/opencode.json from CONFIG_URL and injects # OpenCode provider policies: deny every provider, then allow the # ones derived from the config's own providers, the baseline list @@ -35,6 +39,10 @@ # --allow-provider allow an extra model provider in the # OpenCode policy (repeatable), e.g. # --allow-provider constellation +# --enterprise install this file as the OpenChamber +# enterprise policy (e.g. the +# openchamber-policy.json in this repo); +# without it, built-in defaults apply # --no-enterprise do not install the enterprise policy # file / env pin @@ -53,32 +61,73 @@ INVITE=0 INVITE_PORT=3000 NO_ENTERPRISE=0 ALLOW_PROVIDERS_STR="" +POLICY_SOURCE="" info() { printf '\033[1;34m[info]\033[0m %s\n' "$*"; } ok() { printf '\033[1;32m[ ok ]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[fail]\033[0m %s\n' "$*" >&2; exit 1; } -while [ $# -gt 0 ]; do - case "$1" in - --relay-url) RELAY_URL="$2"; shift 2 ;; - --invite) - INVITE=1 - if [ $# -ge 2 ] && [ "${2#--}" = "$2" ]; then INVITE_PORT="$2"; shift; fi - shift ;; - --allow-provider) - [ $# -ge 2 ] || die "--allow-provider needs a provider id" - ALLOW_PROVIDERS_STR="$ALLOW_PROVIDERS_STR $2" - shift 2 ;; - --no-enterprise) NO_ENTERPRISE=1; shift ;; - *) echo "unknown arg: $1 (usage: $0 [--relay-url wss://host/ws] [--invite [port]] [--allow-provider ] [--no-enterprise])" >&2; exit 1 ;; - esac -done + +# parse_args "$@" — set INVITE/INVITE_PORT/NO_ENTERPRISE/ALLOW_PROVIDERS_STR/ +# POLICY_SOURCE/RELAY_URL from the command line. +parse_args() { + while [ $# -gt 0 ]; do + case "$1" in + --relay-url) [ $# -ge 2 ] || die "--relay-url needs a value"; RELAY_URL="$2"; shift 2 ;; + --invite) + INVITE=1 + if [ $# -ge 2 ] && [ "${2#--}" = "$2" ]; then INVITE_PORT="$2"; shift; fi + shift ;; + --allow-provider) + [ $# -ge 2 ] || die "--allow-provider needs a provider id" + ALLOW_PROVIDERS_STR="$ALLOW_PROVIDERS_STR $2" + shift 2 ;; + --enterprise) + [ $# -ge 2 ] || die "--enterprise needs a policy file path" + [ -r "$2" ] || die "enterprise policy file not found: $2" + POLICY_SOURCE="$2" + shift 2 ;; + --no-enterprise) NO_ENTERPRISE=1; shift ;; + *) echo "unknown arg: $1 (usage: $0 [--relay-url wss://host/ws] [--invite [port]] [--allow-provider ] [--enterprise ] [--no-enterprise])" >&2; exit 1 ;; + esac + done +} # ---- helpers ---------------------------------------------------------------- -# policy_json — emit the enterprise policy file content on stdout +# policy_json — emit the enterprise policy file content on stdout. +# With POLICY_SOURCE set: the file is the source of truth, except --relay-url +# overrides its relayUrl key. Without it: built-in defaults. policy_json() { - printf '{\n "enterpriseMode": true,\n "organization": "%s",\n "relayUrl": "%s"\n}\n' \ - "$ORGANIZATION" "$RELAY_URL" + if [ -z "$POLICY_SOURCE" ]; then + printf '{\n "enterpriseMode": true,\n "organization": "%s",\n "relayUrl": "%s"\n}\n' \ + "$ORGANIZATION" "$RELAY_URL" + return 0 + fi + local tmp + tmp="$(mktemp)" + if command -v python3 >/dev/null 2>&1; then + python3 - "$POLICY_SOURCE" "$tmp" "$RELAY_URL" <<'PY' || { rm -f "$tmp"; die "invalid JSON in enterprise policy file: $POLICY_SOURCE"; } +import json, sys +src, dst, relay = sys.argv[1], sys.argv[2], sys.argv[3] +p = json.load(open(src)) +if relay and p.get("relayUrl") != relay: + p["relayUrl"] = relay +with open(dst, "w") as f: + json.dump(p, f, indent=2) + f.write("\n") +PY + elif command -v bun >/dev/null 2>&1; then + IN="$POLICY_SOURCE" OUT="$tmp" RELAY="$RELAY_URL" bun -e ' +const fs = require("fs"); +const p = JSON.parse(fs.readFileSync(process.env.IN, "utf8")); +if (process.env.RELAY && p.relayUrl !== process.env.RELAY) p.relayUrl = process.env.RELAY; +fs.writeFileSync(process.env.OUT, JSON.stringify(p, null, 2) + "\n"); +' || { rm -f "$tmp"; die "invalid JSON in enterprise policy file: $POLICY_SOURCE"; } + else + die "need python3 or bun to read the enterprise policy file" + fi + cat "$tmp" + rm -f "$tmp" } # write_policy_file — idempotently install the enterprise policy file @@ -230,7 +279,9 @@ except Exception: # ---- main ------------------------------------------------------------------- main() { -info "host: $(uname -srm)" + parse_args "$@" + + info "host: $(uname -srm)" [ "$(uname -s)" = "Linux" ] || die "this script targets Linux hosts" # ---- preflight ------------------------------------------------------------- diff --git a/openchamber-policy.json b/openchamber-policy.json new file mode 100644 index 0000000..09f28b4 --- /dev/null +++ b/openchamber-policy.json @@ -0,0 +1,5 @@ +{ + "enterpriseMode": true, + "organization": "Zuccaro", + "relayUrl": "wss://code.zuccaro.me/ws" +}