Compare commits

...

2 Commits

Author SHA1 Message Date
dd17021402 Merge branch 'rig-work' 2026-09-17 00:07:37 -03:00
19feac6d57 remove profile dependency 2026-09-17 00:07:24 -03:00
13 changed files with 221 additions and 37 deletions

View File

@@ -80,7 +80,7 @@ deps: ## install the toolchain [core|dev] (default de
# The one-file versions of rig's tools, one folder per profile, for machines the # The one-file versions of rig's tools, one folder per profile, for machines the
# full rig is not going to. Generated from rig as it is, never edited by hand; # full rig is not going to. Generated from rig as it is, never edited by hand;
# `check` is what selftest runs to catch a kit left behind by a change to rig. # `check` is what selftest runs to catch a kit left behind by a change to rig.
standalone: ## generate standalone/<profile>/ kits [write|check] (default write) standalone: ## single-file kits [write|check|export DIR] (default write)
bash ctrl/standalone.sh $(or $(ARGS),write) bash ctrl/standalone.sh $(or $(ARGS),write)
deps-image: ## build the installer image [full] deps-image: ## build the installer image [full]

View File

@@ -70,19 +70,39 @@ load_config() {
# Re-apply overrides now so PROFILE is the caller's before we pick the file. # Re-apply overrides now so PROFILE is the caller's before we pick the file.
_config_restore "$saved" _config_restore "$saved"
local profile="${PROFILE:-minimal}" # A profile is an optional overlay, never a prerequisite. rig assumes no
if [ ! -f "./env.d/${profile}.env" ]; then # configuration: with no profile named — or no env.d/ at all — it runs on the
echo "no such profile: env.d/${profile}.env" >&2 # built-in defaults below. What IS an error is naming a profile that does not
echo "available: $(ls env.d/*.env 2>/dev/null | xargs -n1 basename | sed 's/\.env$//' | tr '\n' ' ')" >&2 # exist, because a typo must not quietly fall back to something else.
exit 1 local profile="${PROFILE:-}"
if [ -n "$profile" ] && [ "$profile" != default ]; then
if [ ! -f "./env.d/${profile}.env" ]; then
echo "no such profile: env.d/${profile}.env" >&2
echo "available: $(config_profiles | tr '\n' ' ')" >&2
exit 1
fi
set -a
source "./env.d/${profile}.env"
if [ -z "${RIG_PORTABLE:-}" ] && [ -f ./.env ]; then source ./.env; fi
set +a
_config_restore "$saved"
fi fi
set -a # The defaults a profile would otherwise have to supply. Weakest of all: a
source "./env.d/${profile}.env" # profile, ctrl/.env and the caller each override them.
if [ -z "${RIG_PORTABLE:-}" ] && [ -f ./.env ]; then source ./.env; fi PROFILE_NAME="${PROFILE_NAME:-default}"
set +a ADDONS="${ADDONS-}"
# local, not none: with no registry an unqualified image name means
_config_restore "$saved" # docker.io/library/<name>, and a default must not make that disclosure.
REGISTRY_MODE="${REGISTRY_MODE:-local}"
INGRESS_MODE="${INGRESS_MODE:-hostport}"
DNS_MODE="${DNS_MODE:-hosts}"
# The newest node image versions.env pins, found rather than restated, so
# bumping the pins moves the default with them.
if [ -z "${K8S_VERSION:-}" ]; then
K8S_VERSION=$(compgen -v NODE_IMAGE_v | sort -V | tail -1)
K8S_VERSION="${K8S_VERSION#NODE_IMAGE_}"
fi
# Identity follows the FOLDER, so copying this directory somewhere else and # Identity follows the FOLDER, so copying this directory somewhere else and
# renaming it yields a distinct environment with no further edits. Without # renaming it yields a distinct environment with no further edits. Without
@@ -188,24 +208,44 @@ _config_restore() {
# layered and what is derived are this file's business and can change freely; # layered and what is derived are this file's business and can change freely;
# the generator only calls these. # the generator only calls these.
# Every profile rig can be run as, one per line. # Every configuration rig can be run as, one per line: each profile file, or —
# when there are none — `default`, the built-in configuration load_config uses
# when no profile is named. Never empty, because rig never needs a profile.
config_profiles() { config_profiles() {
local f local f found=""
for f in ./env.d/*.env; do for f in ./env.d/*.env; do
[ -e "$f" ] || continue [ -e "$f" ] || continue
f=${f##*/}; echo "${f%.env}" f=${f##*/}; echo "${f%.env}"; found=1
done done
[ -n "$found" ] || echo default
} }
# The resolved configuration for one profile, as `declare -p` lines — exactly # The resolved configuration, as `declare -p` lines — exactly what load_config
# what load_config leaves behind, minus the machine-local layer. A kit freezes # leaves behind, minus the machine-local layer. A kit freezes this in place of
# this in place of load_config, so it carries rig's decisions for that profile # load_config, so it carries rig's decisions and not this machine's secrets.
# and nothing about the machine it was generated on. #
# config_snapshot <profile> that profile, as any machine would resolve it
# config_snapshot --current what THIS machine runs: every overridable key as
# resolved here, handed back in as if typed on the
# command line, over the same portable resolution.
# Values derived from those choices follow them;
# anything else the local layer set — credentials —
# is not carried. config_left_out names it.
# #
# Found by difference, not by a list: whatever load_config sets today, it sets. # Found by difference, not by a list: whatever load_config sets today, it sets.
# A list here would be one more place to forget a variable. # A list here would be one more place to forget a variable.
config_snapshot() { config_snapshot() {
local _rig_snap_profile="$1" local _rig_snap_choices
if [ "$1" = --current ]; then
_rig_snap_choices=$( (
load_config >/dev/null || exit 1
for _rig_snap_n in $CONFIG_OVERRIDABLE; do
if [ -n "${!_rig_snap_n+x}" ]; then printf 'export %s=%q\n' "$_rig_snap_n" "${!_rig_snap_n}"; fi
done
) ) || return 1
else
_rig_snap_choices="export PROFILE=$(printf '%q' "$1")"
fi
( (
# Nothing from the caller's shell may leak into a kit. # Nothing from the caller's shell may leak into a kit.
for _rig_snap_n in $CONFIG_OVERRIDABLE; do unset "$_rig_snap_n"; done for _rig_snap_n in $CONFIG_OVERRIDABLE; do unset "$_rig_snap_n"; done
@@ -213,7 +253,8 @@ config_snapshot() {
for _rig_snap_n in $(compgen -v); do for _rig_snap_n in $(compgen -v); do
_rig_snap_was[$_rig_snap_n]="${!_rig_snap_n-}" _rig_snap_was[$_rig_snap_n]="${!_rig_snap_n-}"
done done
PROFILE="$_rig_snap_profile" RIG_PORTABLE=1 load_config >/dev/null eval "$_rig_snap_choices"
RIG_PORTABLE=1 load_config >/dev/null
for _rig_snap_n in $(compgen -v); do for _rig_snap_n in $(compgen -v); do
case "$_rig_snap_n" in case "$_rig_snap_n" in
_rig_snap_*|RIG_PORTABLE|BASH*|FUNCNAME|PIPESTATUS|LINENO|RANDOM|SRANDOM|\ _rig_snap_*|RIG_PORTABLE|BASH*|FUNCNAME|PIPESTATUS|LINENO|RANDOM|SRANDOM|\
@@ -227,7 +268,26 @@ config_snapshot() {
) )
} }
# A replacement for load_config with one profile's resolution frozen in, printed # The profile this machine runs, as load_config resolves it here.
config_current_profile() { ( load_config >/dev/null && echo "$PROFILE_NAME" ); }
# What an export of this machine's configuration does NOT carry, by name only:
# keys the machine-local layer sets that are not choices a caller may override.
# They are this machine's own — registry and mirror credentials, mostly — so the
# target has to be told to supply them. Values are never printed.
config_left_out() {
[ -f ./.env ] || return 0
local k
for k in $(sed -nE 's/^[[:space:]]*(export[[:space:]]+)?([A-Za-z_][A-Za-z0-9_]*)=.*/\2/p' ./.env | sort -u); do
case " $(echo $CONFIG_OVERRIDABLE) " in
*" $k "*) ;;
*) echo "$k" ;;
esac
done
}
# A replacement for load_config with a resolution frozen in (a profile, or
# --current — see config_snapshot), printed
# as a function definition for a standalone kit to carry. The generator embeds # as a function definition for a standalone kit to carry. The generator embeds
# whatever this prints and interprets none of it, so what "frozen" means stays # whatever this prints and interprets none of it, so what "frozen" means stays
# rig's decision. # rig's decision.

View File

@@ -42,6 +42,26 @@ resolved() {
} }
note "rig needs no profile"
# rig assumes no configuration. A profile is an overlay on built-in defaults, so
# a rig with no env.d/ at all must resolve, report, and still generate a kit —
# and naming a profile that does not exist must still be an error, because a
# typo that silently fell back to the defaults would be worse than a failure.
NP="$(mktemp -d)"
cp -r .. "$NP/rig"; rm -rf "$NP/rig/ctrl/env.d"; sed -i '/^PROFILE=/d' "$NP/rig/ctrl/.env" 2>/dev/null
check "no env.d: config resolves" "default" \
"$(cd "$NP/rig/ctrl" && bash -c 'source ./lib/config.sh; load_config >/dev/null && echo "$PROFILE_NAME"' 2>&1)"
check "no env.d: the k8s version comes from the pins" "yes" \
"$(cd "$NP/rig/ctrl" && bash -c 'source ./lib/config.sh; load_config >/dev/null && [ -n "$NODE_IMAGE" ] && echo yes' 2>&1)"
check "no env.d: ports.sh active works" "7" \
"$(cd "$NP/rig/ctrl" && bash ports.sh active 2>/dev/null | wc -w)"
check "no env.d: a kit is generated for the defaults" "yes" \
"$( (cd "$NP/rig/ctrl" && rm -rf ../standalone/*/ && bash standalone.sh write >/dev/null 2>&1) && [ -f "$NP/rig/standalone/default/rigdeps.sh" ] && echo yes || echo no)"
check "a profile that does not exist is still an error" "yes" \
"$( (cd "$NP/rig/ctrl" && PROFILE=no-such-profile bash -c 'source ./lib/config.sh; load_config' >/dev/null 2>&1) && echo no || echo yes)"
rm -rf "$NP"
note "the ports.sh active contract" note "the ports.sh active contract"
# ports.sh active is read POSITIONALLY by two other files — the Makefile takes # ports.sh active is read POSITIONALLY by two other files — the Makefile takes
# $(word 2) and $(word 5), the Tiltfile takes _facts[0]..[6]. Insert a field in # $(word 2) and $(word 5), the Tiltfile takes _facts[0]..[6]. Insert a field in
@@ -75,9 +95,11 @@ note "the caller's env beats the files"
# get a real alternative rather than a sentinel. # get a real alternative rather than a sentinel.
test_value() { test_value() {
case "$1" in case "$1" in
PROFILE) echo "client" ;; # env.d/client.env exists # Picked from what exists, never named: rig must not need any particular
K8S_VERSION) echo "v1_35" ;; # NODE_IMAGE_v1_35 is pinned # profile, template or pinned version to be present for this to run.
KIND_CONFIG) echo "kind-config.client.yaml.tpl" ;; # the shape must exist PROFILE) config_profiles | head -1 ;;
K8S_VERSION) (set -a; source ./versions.env; compgen -v NODE_IMAGE_v | sort -V | head -1 | sed 's/^NODE_IMAGE_//') ;;
KIND_CONFIG) ls k8s/kind-config*.yaml.tpl 2>/dev/null | sort | head -1 | xargs -r basename ;;
*_PORT) echo "19999" ;; *_PORT) echo "19999" ;;
CLUSTER) echo "selftest-name" ;; CLUSTER) echo "selftest-name" ;;
MANIFESTS_DIR) echo "../elsewhere/overlays/dev" ;; MANIFESTS_DIR) echo "../elsewhere/overlays/dev" ;;
@@ -200,6 +222,30 @@ for mk in ../standalone/*/Makefile; do
done done
check "there is a kit for every profile" "$(config_profiles | wc -l)" "$kits" check "there is a kit for every profile" "$(config_profiles | wc -l)" "$kits"
# An export is "take the setup I have here somewhere else", so it carries this
# machine's CHOICES — profile, ports, manifest dir — and never its credentials:
# ctrl/.env can hold registry and mirror logins next to those choices. The
# committed per-profile kits carry neither, since they must be the same on any
# machine. Proven with sentinel values in a scratch copy, because the real
# ctrl/.env may have those keys empty — and an empty value proves nothing.
SX="$TMP/export-proof"; mkdir -p "$SX"; cp -r .. "$SX/rig"
cat >> "$SX/rig/ctrl/.env" <<'EOF'
REGISTRY_USER=selftest-sentinel-user
REGISTRY_PASSWORD=selftest-sentinel-password
MANIFESTS_DIR=../selftest-sentinel-choice/overlays/dev
EOF
( cd "$SX/rig/ctrl" && bash standalone.sh export "$SX/out" >/dev/null 2>&1 )
count_in() { grep -rcF -- "$1" "$2" 2>/dev/null | awk -F: '{s+=$2} END{print s+0}'; }
check "export: carries this machine's choices" "yes" \
"$([ "$(count_in selftest-sentinel-choice "$SX/out")" -gt 0 ] && echo yes || echo no)"
check "export: carries no credential" "0" \
"$(( $(count_in selftest-sentinel-user "$SX/out") + $(count_in selftest-sentinel-password "$SX/out") ))"
check "per-profile kits: carry neither, whatever this machine has" "0" \
"$( (cd "$SX/rig/ctrl" && source ./lib/config.sh && for p in $(config_profiles); do config_snapshot "$p"; done) \
| grep -cE 'selftest-sentinel-(choice|user|password)')"
check "export: refuses to write inside the repository" "yes" \
"$( (bash standalone.sh export ../standalone/selftest-mine >/dev/null 2>&1) && echo no || echo yes)"
note "optional — needs tilt and this rig's cluster" note "optional — needs tilt and this rig's cluster"
# Parsing the Tiltfile for real is the only way to know it still evaluates, but # Parsing the Tiltfile for real is the only way to know it still evaluates, but

View File

@@ -20,8 +20,9 @@
# resolves relative to the entry point. Libraries may source further # resolves relative to the entry point. Libraries may source further
# libraries however they like — bash follows those itself. # libraries however they like — bash follows those itself.
# 3. Configuration enters through `load_config`, and the libraries provide # 3. Configuration enters through `load_config`, and the libraries provide
# `config_profiles` and `config_freeze <profile>` — the latter prints a # `config_profiles`, `config_freeze <profile|--current>` — which prints a
# replacement load_config with that profile resolved. How config is layered, # replacement load_config with that resolution frozen in — and, for an
# export, `config_current_profile` and `config_left_out`. How config is layered,
# stored, derived or frozen is rig's business; this only asks, and embeds # stored, derived or frozen is rig's business; this only asks, and embeds
# the answer without interpreting it. # the answer without interpreting it.
# #
@@ -36,8 +37,16 @@
# line and what is wrong. It never writes a kit that only looks finished. # line and what is wrong. It never writes a kit that only looks finished.
# #
# Usage: # Usage:
# standalone.sh write generate every kit into standalone/<profile>/ # standalone.sh write generate every kit into standalone/<profile>/
# standalone.sh check generate into a scratch dir and fail if any kit differs # standalone.sh check generate into a scratch dir and fail if any kit differs
# standalone.sh export DIR ONE kit for the configuration this machine runs —
# its profile plus the choices in its local config,
# WITHOUT its credentials — written outside the repo.
#
# write and check are what gets committed: one kit per profile, identical on any
# machine. export is the other question — "take the setup I have here somewhere
# else" — so it reflects this machine, and for exactly that reason it never lands
# in the repository.
set -euo pipefail set -euo pipefail
cd "$(dirname "$0")" cd "$(dirname "$0")"
@@ -47,6 +56,11 @@ OUT="$ROOT/standalone"
SELF_REL="ctrl/${0##*/}" SELF_REL="ctrl/${0##*/}"
GENERATED_TAG="GENERATED by make standalone — do not edit" GENERATED_TAG="GENERATED by make standalone — do not edit"
# The contract's own functions: questions rig answers FOR this generator. They
# are never carried into a kit — load_config is replaced by the frozen one, and
# the rest mean nothing without rig's tree. The only names this file knows.
CONTRACT_FUNCS="load_config config_profiles config_snapshot config_freeze config_current_profile config_left_out"
FROZEN_OPEN="# ── configuration, frozen" FROZEN_OPEN="# ── configuration, frozen"
FROZEN_CLOSE="# ── end of frozen configuration" FROZEN_CLOSE="# ── end of frozen configuration"
@@ -54,7 +68,7 @@ refuse() { echo >&2; echo "standalone: refusing — $*" >&2; exit 1; }
# A clean bash with nothing from the caller's shell in it. What the kit carries # A clean bash with nothing from the caller's shell in it. What the kit carries
# must not depend on who ran the generator or what they had exported. # must not depend on who ran the generator or what they had exported.
clean_bash() { env -i PATH="$PATH" HOME="$HOME" bash --noprofile --norc "$@"; } clean_bash() { env -i PATH="$PATH" HOME="$HOME" CONTRACT_FUNCS="$CONTRACT_FUNCS" bash --noprofile --norc "$@"; }
# ── 1. entry points ──────────────────────────────────────────────────────── # ── 1. entry points ────────────────────────────────────────────────────────
entries() { entries() {
@@ -104,7 +118,7 @@ libs_into() {
lib_defs() { # entry lib... -> declare -p globals, then declare -f functions lib_defs() { # entry lib... -> declare -p globals, then declare -f functions
local entry="$1"; shift local entry="$1"; shift
( cd "$(dirname "$entry")" && clean_bash -c ' ( cd "$(dirname "$entry")" && clean_bash -c '
skip_var() { case "$1" in BASH*|FUNCNAME|PIPESTATUS|LINENO|RANDOM|SRANDOM|SECONDS|EPOCH*|HISTCMD|COLUMNS|LINES|PWD|OLDPWD|_|SHLVL|OPTIND|OPTERR|IFS|PS4|PATH|HOME|v|f|l|before_v|before_f) return 0 ;; esac; return 1; } skip_var() { case "$1" in CONTRACT_FUNCS|BASH*|FUNCNAME|PIPESTATUS|LINENO|RANDOM|SRANDOM|SECONDS|EPOCH*|HISTCMD|COLUMNS|LINES|PWD|OLDPWD|_|SHLVL|OPTIND|OPTERR|IFS|PS4|PATH|HOME|v|f|l|before_v|before_f) return 0 ;; esac; return 1; }
before_v=" $(compgen -v | tr "\n" " ") " before_v=" $(compgen -v | tr "\n" " ") "
before_f=" $(compgen -A function | tr "\n" " ") " before_f=" $(compgen -A function | tr "\n" " ") "
for l in "$@"; do source "$l" || { echo "__FAIL__ sourcing $l" ; exit 1; }; done for l in "$@"; do source "$l" || { echo "__FAIL__ sourcing $l" ; exit 1; }; done
@@ -115,7 +129,7 @@ lib_defs() { # entry lib... -> declare -p globals, then declare -f functions
done done
for f in $(compgen -A function); do for f in $(compgen -A function); do
case "$before_f" in *" $f "*) continue ;; esac case "$before_f" in *" $f "*) continue ;; esac
case "$f" in skip_var|load_config|config_profiles|config_snapshot|config_freeze) continue ;; esac case " skip_var $CONTRACT_FUNCS " in *" $f "*) continue ;; esac
declare -f "$f" declare -f "$f"
done done
' _ "$@" ) || refuse "$entry: its libraries could not be sourced cleanly" ' _ "$@" ) || refuse "$entry: its libraries could not be sourced cleanly"
@@ -146,7 +160,7 @@ assemble() { # entry profile out-file lib...
echo '#!/usr/bin/env bash' echo '#!/usr/bin/env bash'
echo "# $GENERATED_TAG" echo "# $GENERATED_TAG"
echo "#" echo "#"
echo "# $(basename "$dest") for profile '$profile', flattened from:" echo "# $(basename "$dest") for ${KIT_LABEL:-profile '$profile'}, flattened from:"
echo "# ctrl/$entry" echo "# ctrl/$entry"
local l; for l in ${libs[@]+"${libs[@]}"}; do echo "# ctrl/$l"; done local l; for l in ${libs[@]+"${libs[@]}"}; do echo "# ctrl/$l"; done
echo "# Edit those and run \`make standalone\`. Changes made here are lost, and" echo "# Edit those and run \`make standalone\`. Changes made here are lost, and"
@@ -161,9 +175,9 @@ assemble() { # entry profile out-file lib...
if [ "$calls_config" = yes ]; then if [ "$calls_config" = yes ]; then
local frozen local frozen
frozen=$(ask "$entry" ${libs[@]+"${libs[@]}"} -- config_freeze "$profile") \ frozen=$(ask "$entry" ${libs[@]+"${libs[@]}"} -- config_freeze "${FREEZE_ARG:-$profile}") \
|| refuse "ctrl/$entry calls load_config, but its libraries do not answer config_freeze for '$profile'" || refuse "ctrl/$entry calls load_config, but its libraries do not answer config_freeze ${FREEZE_ARG:-$profile}"
echo "$FROZEN_OPEN for profile '$profile' ──" echo "$FROZEN_OPEN for ${KIT_LABEL:-profile '$profile'} ──"
printf '%s\n' "$frozen" printf '%s\n' "$frozen"
echo "$FROZEN_CLOSE ──" echo "$FROZEN_CLOSE ──"
echo echo
@@ -337,5 +351,44 @@ case "$cmd" in
[ "$stale" -eq 0 ] || { echo "run: make standalone"; exit 1; } [ "$stale" -eq 0 ] || { echo "run: make standalone"; exit 1; }
echo "every kit is current" echo "every kit is current"
;; ;;
*) echo "usage: $SELF_REL [write|check]" >&2; exit 1 ;; export)
dest="${1:-}"
[ -n "$dest" ] || refuse "export needs a directory, outside the repo: make standalone export ~/rig-kit"
dest=$(realpath -m "$dest")
top=$(git -C "$ROOT" rev-parse --show-toplevel 2>/dev/null || echo "$ROOT")
case "$dest/" in
"$top"/*) refuse "an export reflects this machine, so it does not go inside the repository — $dest is under $top. The committed per-profile kits are what standalone/ is for." ;;
esac
if [ -d "$dest" ] && [ -n "$(ls -A "$dest" 2>/dev/null)" ] && ! is_generated_dir "$dest"; then
refuse "$dest already holds something that is not a previous export — pick an empty directory"
fi
mapfile -t all_entries < <(entries)
[ ${#all_entries[@]} -gt 0 ] || refuse "no script under ctrl/ carries a '# rig:standalone <kit> <verb>' marker"
libs_into "${all_entries[0]}"
profile=$(ask "${all_entries[0]}" ${libs[@]+"${libs[@]}"} -- config_current_profile) \
|| refuse "this machine's configuration does not resolve — run make check"
left=$(ask "${all_entries[0]}" ${libs[@]+"${libs[@]}"} -- config_left_out | tr '\n' ' ')
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
echo "exporting the configuration this machine runs (profile '$profile')"
FREEZE_ARG=--current
KIT_LABEL="the configuration exported from $(hostname -s 2>/dev/null || echo this machine) (profile '$profile', local choices included, credentials not)"
for e in "${all_entries[@]}"; do
read -r kit verb <<< "$(marker_of "$e")"
libs_into "$e"
assemble "$e" "$profile" "$tmp/$kit.sh" ${libs[@]+"${libs[@]}"}
done
makefile "$tmp" "${all_entries[@]}"
verify_kit "$tmp" "export" "${all_entries[@]}"
rm -rf "$dest"; mkdir -p "$(dirname "$dest")"; cp -r "$tmp" "$dest"
echo " wrote $dest: $(cd "$dest" && ls | tr '\n' ' ')— verified to stand alone"
if [ -n "${left// /}" ]; then
echo
echo " NOT carried — this machine's own, set them on the target if it needs them:"
for k in $left; do echo " $k"; done
fi
;;
*) echo "usage: $SELF_REL [write|check|export DIR]" >&2; exit 1 ;;
esac esac

View File

@@ -25,6 +25,23 @@ make deps / make mem # the same, via the Makefile
`rigmini.sh push` and `all` deliberately consume memory. Run `status` first, and `rigmini.sh push` and `all` deliberately consume memory. Run `status` first, and
only run them somewhere other processes may be squeezed. only run them somewhere other processes may be squeezed.
## Your own setup, somewhere else — `export`
The folders here are rig's **profiles**, identical on any machine. To take the
setup **this machine runs** instead — its profile plus the choices in its local
`ctrl/.env` (ports, manifest directory, mirror mode) — export it:
```bash
make standalone export ~/rig-kit # one kit, outside the repository
```
An export carries your **choices, never your credentials**. Anything in `ctrl/.env`
that is not a setting a caller may override — registry logins, a mirror URL — is
left out, and the export lists those names so you know what to set on the target.
It refuses to write inside the repository: it reflects one machine, and the
repository holds what is true for every machine. `make selftest` proves both with
sentinel values.
## Why generated ## Why generated
These used to be hand-kept copies, and they drifted: the standalone memory tool These used to be hand-kept copies, and they drifted: the standalone memory tool

View File

@@ -85,6 +85,7 @@ load_config() {
declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5" declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5"
declare -g NODE_MB="800" declare -g NODE_MB="800"
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx PROFILE="client"
declare -gx PROFILE_NAME="client" declare -gx PROFILE_NAME="client"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"

View File

@@ -85,6 +85,7 @@ load_config() {
declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5" declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5"
declare -g NODE_MB="800" declare -g NODE_MB="800"
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx PROFILE="client"
declare -gx PROFILE_NAME="client" declare -gx PROFILE_NAME="client"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"

View File

@@ -90,6 +90,7 @@ load_config() {
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx POSTGRES_STORAGE="2Gi" declare -gx POSTGRES_STORAGE="2Gi"
declare -gx POSTGRES_USER="app" declare -gx POSTGRES_USER="app"
declare -gx PROFILE="data"
declare -gx PROFILE_NAME="data" declare -gx PROFILE_NAME="data"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"

View File

@@ -90,6 +90,7 @@ load_config() {
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx POSTGRES_STORAGE="2Gi" declare -gx POSTGRES_STORAGE="2Gi"
declare -gx POSTGRES_USER="app" declare -gx POSTGRES_USER="app"
declare -gx PROFILE="data"
declare -gx PROFILE_NAME="data" declare -gx PROFILE_NAME="data"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"

View File

@@ -85,6 +85,7 @@ load_config() {
declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5" declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5"
declare -g NODE_MB="800" declare -g NODE_MB="800"
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx PROFILE="minimal"
declare -gx PROFILE_NAME="minimal" declare -gx PROFILE_NAME="minimal"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"

View File

@@ -85,6 +85,7 @@ load_config() {
declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5" declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5"
declare -g NODE_MB="800" declare -g NODE_MB="800"
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx PROFILE="minimal"
declare -gx PROFILE_NAME="minimal" declare -gx PROFILE_NAME="minimal"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"

View File

@@ -85,6 +85,7 @@ load_config() {
declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5" declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5"
declare -g NODE_MB="800" declare -g NODE_MB="800"
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx PROFILE="offline"
declare -gx PROFILE_NAME="offline" declare -gx PROFILE_NAME="offline"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"

View File

@@ -85,6 +85,7 @@ load_config() {
declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5" declare -gx NODE_IMAGE_v1_36="kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5"
declare -g NODE_MB="800" declare -g NODE_MB="800"
declare -gx POSTGRES_IMAGE="postgres:16-alpine" declare -gx POSTGRES_IMAGE="postgres:16-alpine"
declare -gx PROFILE="offline"
declare -gx PROFILE_NAME="offline" declare -gx PROFILE_NAME="offline"
declare -gx REDIS_IMAGE="redis:7-alpine" declare -gx REDIS_IMAGE="redis:7-alpine"
declare -gx REGISTRY_IMAGE="registry:2" declare -gx REGISTRY_IMAGE="registry:2"