#!/usr/bin/env bash # Seed a git recipe repo (recipes-production / recipes-playground) from # the current launcher repo state (specs/tech-architecture/ # ha-addon-recipe-repos.md, step 6). # # The operator creates the bare repo on git.kilork.org FIRST; this script # builds the layout, commits it, and prints the push command: # # scripts/seed-recipe-repos.sh [git-url] # # the repo name (recipes-production | recipes-playground) # git-url the git URL of the repo the operator created (printed in the # push instructions; a local path also works for a dry run) # # Layout (a subset of the launcher repo, per the spec): # recipes//… # tracked recipe dirs (machine state like .lock is # # gitignored → excluded by `git archive` for free) # docker-images// # build contexts (source of truth; optional when # # the image is prebuilt in the registry) # # NOTE: no config.toml is copied. A recipe repo's config.toml is # operator-curated and must be CREDENTIAL-FREE (the repo may be shared # with other users): clusters/nccl only. Secrets (ssh user/key, HA # url/token, mikrotik password, registry base) come from the add-on # options, never from the repo — see the curated example in # git.kilork.org/sm121/recipes. set -euo pipefail cd "$(dirname "$0")/.." NAME="${1:-}" URL="${2:-}" if [ -z "$NAME" ]; then echo "usage: scripts/seed-recipe-repos.sh [git-url]" >&2 echo " e.g. scripts/seed-recipe-repos.sh recipes-production https://git.kilork.org/sm121/recipes-production.git" >&2 exit 1 fi if ! git rev-parse --git-dir >/dev/null 2>&1; then echo "error: run this from the sm121-launcher repo (it reads the tracked state via git archive)" >&2 exit 1 fi PARENT="$(dirname "$(pwd)")" OUT="$PARENT/$NAME" if [ -e "$OUT" ]; then echo "error: $OUT already exists — refusing to clobber" >&2 exit 1 fi TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT # The tracked state of the launcher repo (gitignored machine state — # .lock ledgers, target/, scratch — is excluded for free). git archive --prefix=repo/ HEAD | tar -x -C "$TMP" mkdir -p "$OUT" # NOTE: no config.toml is seeded — it is operator-curated and must stay # credential-free (the repo may be shared with other users). The launcher # repo's config.toml carries secrets (HA token, mikrotik password, ssh # key path) and must never be copied into a shared repo. [ -d "$TMP/repo/recipes" ] && cp -R "$TMP/repo/recipes" "$OUT/recipes" [ -d "$TMP/repo/docker-images" ] && cp -R "$TMP/repo/docker-images" "$OUT/docker-images" # A minimal README so the repo documents its own layout. cat > "$OUT/README.md" </recipe.toml` — the recipes - `docker-images//` — image build contexts (source of truth; optional when the image is prebuilt in the registry) - `config.toml` (operator-curated, NOT seeded by the script) — the shared cluster/config source of truth. CREDENTIAL-FREE by contract (this repo may be shared with other users): clusters/nccl only; the secrets (ssh user/key, HA url/token, mikrotik password, registry base) come from the add-on options (sm121_ssh_user, sm121_ssh_key_b64, sm121_ha_url, sm121_ha_token, sm121_registry_base, sm121_config_extra) Seeded from the sm121-launcher repo on $(date -u +%Y-%m-%d). EOF git -C "$OUT" init -q git -C "$OUT" add -A git -C "$OUT" commit -qm "seed $NAME from sm121-launcher @ $(git rev-parse --short HEAD)" N_RECIPES=$(find "$OUT/recipes" -name recipe.toml 2>/dev/null | wc -l | tr -d ' ') N_IMAGES=$(find "$OUT/docker-images" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | wc -l | tr -d ' ') echo "seeded $OUT:" echo " recipes: $N_RECIPES" echo " docker-images: $N_IMAGES dirs" echo echo "push it (the operator creates the repo first):" if [ -n "$URL" ]; then echo " git -C $OUT remote add origin $URL" echo " git -C $OUT push -u origin $(git -C "$OUT" symbolic-ref --short HEAD)" else echo " git -C $OUT remote add origin " echo " git -C $OUT push -u origin main" fi echo echo "then add it to the launcher config (order = priority, first wins):" echo " [[recipe_repos]]" echo " url = \"${URL:-}\""