Archived
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5990ccf7d | ||
|
|
17dd00bee1 | ||
|
|
b3c81453e4 | ||
|
|
656dd975f0 |
No files matched your search
Submodule
+1
Submodule .claude/worktrees/scripts-dedup added at e578443914.
+3
-1
@@ -5,8 +5,9 @@ keys:
|
|||||||
- &nix-cache age120le4a5l8dh3lyfgvmj3d9ksmej6ajs5mer5y7r0vfg3x9fn69dqf8xgzu
|
- &nix-cache age120le4a5l8dh3lyfgvmj3d9ksmej6ajs5mer5y7r0vfg3x9fn69dqf8xgzu
|
||||||
- &lxc-minimal age1qz9d4ka4xgexujyd247s7lp737sulp5fhxl5d65fj2ykvc4j4edqrsdks8
|
- &lxc-minimal age1qz9d4ka4xgexujyd247s7lp737sulp5fhxl5d65fj2ykvc4j4edqrsdks8
|
||||||
- &nix-minimal age120whqj96g26lsgy4udvgsn8dc9lumh8jeu3a564fx79rjr5lxffqmrljuu
|
- &nix-minimal age120whqj96g26lsgy4udvgsn8dc9lumh8jeu3a564fx79rjr5lxffqmrljuu
|
||||||
- &lxc-nix-cache age164px2a8e48ptsf9ngtan38aa6jls4jdl26mzrgzf6sn3vcvt49hqjrgr8w
|
|
||||||
- &proxmox-minimal age10at8862478urh0eeuwh8hzln6ck78jgwtztgxatwqlzwagg77y5snm4xzg
|
- &proxmox-minimal age10at8862478urh0eeuwh8hzln6ck78jgwtztgxatwqlzwagg77y5snm4xzg
|
||||||
|
- &lxc-nix-cache age1xjst4frdh0th6q8m7p7u9g5af7ty5jqeum0p6z8a52a9q7st7ewqw8yl9j
|
||||||
|
- &lxc-docker age1ezk9x53zt8kcnscdm80jcyf0xq97vndv7jsn3rl8cc0cwm2jmpmq372dzs
|
||||||
|
|
||||||
creation_rules:
|
creation_rules:
|
||||||
# Shared across every currently-deployed host: root/nixos password hash,
|
# Shared across every currently-deployed host: root/nixos password hash,
|
||||||
@@ -24,6 +25,7 @@ creation_rules:
|
|||||||
- *nix-minimal
|
- *nix-minimal
|
||||||
- *lxc-nix-cache
|
- *lxc-nix-cache
|
||||||
- *proxmox-minimal
|
- *proxmox-minimal
|
||||||
|
- *lxc-docker
|
||||||
|
|
||||||
- path_regex: secrets/nix-cache\.yaml$
|
- path_regex: secrets/nix-cache\.yaml$
|
||||||
key_groups:
|
key_groups:
|
||||||
|
|||||||
@@ -114,9 +114,10 @@ Three different paths depending on target, none of them involving a manual
|
|||||||
`docs/proxmox-images.md`.
|
`docs/proxmox-images.md`.
|
||||||
|
|
||||||
`scripts/create-proxmox-resource.sh --type lxc|vm --host <name>` automates
|
`scripts/create-proxmox-resource.sh --type lxc|vm --host <name>` automates
|
||||||
either of the last two end to end (build, host-key registration, upload,
|
either of the last two end to end (host-key registration, building the
|
||||||
`pct create`/`qm create`), with `--dry-run` and a guard against duplicating
|
image directly on the Proxmox node itself, `pct create`/`qm create`), with
|
||||||
an already-deployed host's identity. See its `--help`.
|
`--dry-run` and a guard against duplicating an already-deployed host's
|
||||||
|
identity. See its `--help`.
|
||||||
|
|
||||||
## Security Notes
|
## Security Notes
|
||||||
|
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ booting one:
|
|||||||
First boot runs `boot.postBootCommands` (registers the Nix store DB and
|
First boot runs `boot.postBootCommands` (registers the Nix store DB and
|
||||||
system profile) — there's no separate activation step to run yourself.
|
system profile) — there's no separate activation step to run yourself.
|
||||||
`scripts/create-proxmox-resource.sh --type lxc --host <name>` automates all
|
`scripts/create-proxmox-resource.sh --type lxc --host <name>` automates all
|
||||||
of this (build, host-key handling, upload, `pct create` with the flags
|
of this (host-key handling, building the tarball directly on the Proxmox
|
||||||
above) — see its `--help`.
|
node itself, `pct create` with the flags above) — see its `--help`.
|
||||||
|
|
||||||
Host keys still need pre-seeding the same way as any other host — the
|
Host keys still need pre-seeding the same way as any other host — the
|
||||||
sops-nix activation-vs-first-boot race is identical regardless of how the
|
sops-nix activation-vs-first-boot race is identical regardless of how the
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ install, so there's nothing host-specific to write; it's available for every
|
|||||||
|
|
||||||
`scripts/create-proxmox-resource.sh --type vm --host <name>` automates the
|
`scripts/create-proxmox-resource.sh --type vm --host <name>` automates the
|
||||||
whole walkthrough below (and the equivalent LXC one) end to end, including
|
whole walkthrough below (and the equivalent LXC one) end to end, including
|
||||||
host-key handling and upload — see its `--help`. The steps here are what it
|
host-key handling and building the image directly on the Proxmox node
|
||||||
runs under the hood, useful for doing any of it by hand or understanding
|
itself (no local build, no image transfer) — see its `--help`. The steps
|
||||||
what it does before you trust it against real infrastructure.
|
here are what it runs under the hood, useful for doing any of it by hand
|
||||||
|
or understanding what it does before you trust it against real
|
||||||
|
infrastructure.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,15 @@
|
|||||||
# existing ones -- the manual workflows in docs/proxmox-images.md (VM) and
|
# existing ones -- the manual workflows in docs/proxmox-images.md (VM) and
|
||||||
# docs/auto-installer.md's "LXC hosts" section (container), automated.
|
# docs/auto-installer.md's "LXC hosts" section (container), automated.
|
||||||
#
|
#
|
||||||
|
# Images are built directly on the Proxmox node (PROXMOX_REMOTE_REPO_DIR /
|
||||||
|
# --remote-repo-dir in scripts/env.sh), not on whatever machine runs this
|
||||||
|
# script -- there's no multi-gigabyte image to transfer afterward. The first
|
||||||
|
# time a node doesn't have that repo path yet, it's bootstrapped: cloned from
|
||||||
|
# this checkout's own `origin` remote, then scripts/codex-setup.sh installs
|
||||||
|
# the build tooling (Nix, etc.). Every run after that just `git pull`s it and
|
||||||
|
# copies over the locally-managed host-keys/ (gitignored, so a git pull
|
||||||
|
# alone wouldn't carry it) before building.
|
||||||
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# scripts/create-proxmox-resource.sh --type lxc|vm --host <name> [options]
|
# scripts/create-proxmox-resource.sh --type lxc|vm --host <name> [options]
|
||||||
# scripts/create-proxmox-resource.sh --type lxc|vm --list
|
# scripts/create-proxmox-resource.sh --type lxc|vm --list
|
||||||
@@ -55,11 +64,15 @@ Create mode (default):
|
|||||||
Refuses to run if this ID already exists.
|
Refuses to run if this ID already exists.
|
||||||
--disk-size <GB> lxc only: rootfs size for \`pct create\`
|
--disk-size <GB> lxc only: rootfs size for \`pct create\`
|
||||||
(default: \$PROXMOX_DEFAULT_LXC_DISK_GB, ${PROXMOX_DEFAULT_LXC_DISK_GB}).
|
(default: \$PROXMOX_DEFAULT_LXC_DISK_GB, ${PROXMOX_DEFAULT_LXC_DISK_GB}).
|
||||||
--image <path> Use this local image/tarball instead of
|
--image <path> Use this local image/tarball (uploaded to the
|
||||||
checking the node / building one from the flake.
|
node via scp) instead of checking the node /
|
||||||
|
building one there from the flake.
|
||||||
--force-rebuild Skip the "does the node already have this
|
--force-rebuild Skip the "does the node already have this
|
||||||
image" check -- always build fresh and
|
image" check -- always build fresh and
|
||||||
overwrite what's there.
|
overwrite what's there.
|
||||||
|
--remote-repo-dir <path> Where this flake repo lives (or gets
|
||||||
|
cloned) on the node, and is built from
|
||||||
|
(default: \$PROXMOX_REMOTE_REPO_DIR, ${PROXMOX_REMOTE_REPO_DIR}).
|
||||||
--allow-duplicate-host Required if a VM/CT identified as --host
|
--allow-duplicate-host Required if a VM/CT identified as --host
|
||||||
already exists on the node (checked live via
|
already exists on the node (checked live via
|
||||||
qm/pct, not any file in this repo) --
|
qm/pct, not any file in this repo) --
|
||||||
@@ -116,6 +129,7 @@ storage="$PROXMOX_STORAGE"
|
|||||||
iso_storage="$PROXMOX_ISO_STORAGE"
|
iso_storage="$PROXMOX_ISO_STORAGE"
|
||||||
bridge="$PROXMOX_BRIDGE"
|
bridge="$PROXMOX_BRIDGE"
|
||||||
node="$PROXMOX_HOST"
|
node="$PROXMOX_HOST"
|
||||||
|
remote_repo_dir="$PROXMOX_REMOTE_REPO_DIR"
|
||||||
do_list=0
|
do_list=0
|
||||||
allow_duplicate_host=0
|
allow_duplicate_host=0
|
||||||
force_rebuild=0
|
force_rebuild=0
|
||||||
@@ -136,6 +150,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--iso-storage) iso_storage="$2"; shift 2 ;;
|
--iso-storage) iso_storage="$2"; shift 2 ;;
|
||||||
--bridge) bridge="$2"; shift 2 ;;
|
--bridge) bridge="$2"; shift 2 ;;
|
||||||
--node) node="$2"; shift 2 ;;
|
--node) node="$2"; shift 2 ;;
|
||||||
|
--remote-repo-dir) remote_repo_dir="$2"; shift 2 ;;
|
||||||
--list) do_list=1; shift ;;
|
--list) do_list=1; shift ;;
|
||||||
--allow-duplicate-host) allow_duplicate_host=1; shift ;;
|
--allow-duplicate-host) allow_duplicate_host=1; shift ;;
|
||||||
--force-rebuild) force_rebuild=1; shift ;;
|
--force-rebuild) force_rebuild=1; shift ;;
|
||||||
@@ -409,6 +424,57 @@ if [[ "$type" == "lxc" ]]; then
|
|||||||
fi
|
fi
|
||||||
remote_path="${remote_dir}/${remote_filename}"
|
remote_path="${remote_dir}/${remote_filename}"
|
||||||
|
|
||||||
|
# --- ensure the flake repo (+ tooling) exists on the node, and is current --
|
||||||
|
# Bootstraps once (git clone from this checkout's own `origin`, then
|
||||||
|
# scripts/codex-setup.sh installs Nix + friends) if ${remote_repo_dir}
|
||||||
|
# doesn't exist yet on the node; otherwise just `git pull`s it, so the image
|
||||||
|
# built there reflects what's actually committed and pushed. Only called
|
||||||
|
# right before an actual remote build below -- reusing an image already on
|
||||||
|
# the node, or an explicit --image, never touch the node's checkout at all.
|
||||||
|
ensure_remote_repo() {
|
||||||
|
echo
|
||||||
|
echo "==> Ensuring ${remote_repo_dir} exists and is current on ${node}..."
|
||||||
|
if [[ "$dry_run" -eq 1 ]]; then
|
||||||
|
echo "[dry-run] would ensure ${remote_repo_dir} exists on ${node} (clone + scripts/codex-setup.sh if missing, git pull if present)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ssh "$ssh_target" "test -d '${remote_repo_dir}/.git'"; then
|
||||||
|
echo "Repo present -- pulling latest..."
|
||||||
|
ssh "$ssh_target" "cd '${remote_repo_dir}' && git pull --ff-only"
|
||||||
|
else
|
||||||
|
local origin_url
|
||||||
|
origin_url="$(git -C "$repo_root" remote get-url origin 2>/dev/null || true)"
|
||||||
|
if [[ -z "$origin_url" ]]; then
|
||||||
|
echo "ERROR: ${remote_repo_dir} doesn't exist on ${node}, and this checkout has no" >&2
|
||||||
|
echo "'origin' remote to clone from. Set one (git remote add origin <url>) or create" >&2
|
||||||
|
echo "${remote_repo_dir} on ${node} yourself (e.g. git clone), then re-run." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Not present -- cloning from ${origin_url}..."
|
||||||
|
ssh "$ssh_target" "git clone '${origin_url}' '${remote_repo_dir}'"
|
||||||
|
echo "==> Bootstrapping build tooling on ${node} (scripts/codex-setup.sh)..."
|
||||||
|
ssh "$ssh_target" "cd '${remote_repo_dir}' && bash scripts/codex-setup.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- sync locally-managed host-keys/ to the node ---------------------------
|
||||||
|
# Gitignored (see .gitignore), so `git pull` above never carries it -- both
|
||||||
|
# build paths need it present as NIXOS_HOST_KEYS_DIR / --pre-format-files
|
||||||
|
# input on the node itself now that the build runs there. scp (not rsync,
|
||||||
|
# not already a dependency anywhere else in this repo) mirrors how this
|
||||||
|
# script already transfers the --image case below.
|
||||||
|
sync_remote_host_keys() {
|
||||||
|
echo
|
||||||
|
echo "==> Syncing host-keys/ to ${node}..."
|
||||||
|
if [[ "$dry_run" -eq 1 ]]; then
|
||||||
|
echo "[dry-run] would copy ${repo_root}/host-keys/ to ${ssh_target}:${remote_repo_dir}/host-keys/"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
ssh "$ssh_target" "mkdir -p '${remote_repo_dir}/host-keys'"
|
||||||
|
scp -pr "${repo_root}/host-keys/." "${ssh_target}:${remote_repo_dir}/host-keys/"
|
||||||
|
}
|
||||||
|
|
||||||
# --- build (or reuse an image already on the node) ------------------------
|
# --- build (or reuse an image already on the node) ------------------------
|
||||||
echo
|
echo
|
||||||
local_image=""
|
local_image=""
|
||||||
@@ -425,7 +491,7 @@ else
|
|||||||
if [[ "$dry_run" -eq 1 ]]; then
|
if [[ "$dry_run" -eq 1 ]]; then
|
||||||
echo "[dry-run] would check: ssh ${ssh_target} -- test -f ${remote_path}"
|
echo "[dry-run] would check: ssh ${ssh_target} -- test -f ${remote_path}"
|
||||||
elif ssh "$ssh_target" "test -f '${remote_path}'" 2>/dev/null; then
|
elif ssh "$ssh_target" "test -f '${remote_path}'" 2>/dev/null; then
|
||||||
echo "Found it -- reusing, skipping build and upload (use --force-rebuild to override)."
|
echo "Found it -- reusing, skipping build (use --force-rebuild to override)."
|
||||||
image_already_remote=1
|
image_already_remote=1
|
||||||
else
|
else
|
||||||
echo "Not found -- will build."
|
echo "Not found -- will build."
|
||||||
@@ -433,69 +499,124 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$image_already_remote" -eq 0 && -z "$local_image" ]]; then
|
if [[ "$image_already_remote" -eq 0 && -z "$local_image" ]]; then
|
||||||
# Mirrors the real build commands' "${NIX_OPTS[@]}" below -- nix_extra_opts
|
ensure_remote_repo
|
||||||
# (called earlier, once) has already decided whether nix-cache is in play,
|
sync_remote_host_keys
|
||||||
# and the dry-run preview needs to reflect that decision instead of always
|
|
||||||
# printing the same command regardless of outcome.
|
# Relayed into the remote build below exactly as decided by the local
|
||||||
|
# nix_extra_opts call earlier in this script -- that decision (whether
|
||||||
|
# nix-cache is reachable) is made once, locally, same as it always has
|
||||||
|
# been; only *where* the resulting "${NIX_OPTS[@]}" gets used as a `nix
|
||||||
|
# build` flag moves to the node. NIX_EXTRA_OPTS is already a %q-quoted
|
||||||
|
# string built for exactly this eval-based reconstruction (see env.sh).
|
||||||
nix_opts_display=""
|
nix_opts_display=""
|
||||||
if [[ ${#NIX_OPTS[@]} -gt 0 ]]; then
|
if [[ ${#NIX_OPTS[@]} -gt 0 ]]; then
|
||||||
printf -v nix_opts_display '%q ' "${NIX_OPTS[@]}"
|
printf -v nix_opts_display '%q ' "${NIX_OPTS[@]}"
|
||||||
nix_opts_display=" ${nix_opts_display% }"
|
nix_opts_display=" ${nix_opts_display% }"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$type" == "lxc" ]]; then
|
if [[ "$type" == "lxc" ]]; then
|
||||||
if [[ "$dry_run" -eq 1 ]]; then
|
if [[ "$dry_run" -eq 1 ]]; then
|
||||||
echo "[dry-run] would build: NIXOS_HOST_KEYS_DIR=${repo_root}/host-keys nix build --impure \\"
|
echo "[dry-run] would build on ${node}: NIXOS_HOST_KEYS_DIR=\$(pwd)/host-keys nix build --impure \\"
|
||||||
echo "[dry-run] --no-use-registries --no-accept-flake-config${nix_opts_display} \\"
|
echo "[dry-run] --no-use-registries --no-accept-flake-config${nix_opts_display} \\"
|
||||||
echo "[dry-run] .#nixosConfigurations.${flake_target}.config.system.build.tarball"
|
echo "[dry-run] .#nixosConfigurations.${flake_target}.config.system.build.tarball"
|
||||||
|
echo "[dry-run] would stage the result at ${remote_path}"
|
||||||
local_image="<built-tarball>"
|
local_image="<built-tarball>"
|
||||||
else
|
else
|
||||||
echo "==> Building LXC tarball for ${flake_target}..."
|
echo "==> Building LXC tarball for ${flake_target} on ${node}..."
|
||||||
NIXOS_HOST_KEYS_DIR="${repo_root}/host-keys" nix build --impure \
|
# Built as a single already-%q-quoted command string, not separate ssh
|
||||||
--no-use-registries --no-accept-flake-config "${NIX_OPTS[@]}" \
|
# argv elements -- ssh joins remote command args with plain spaces and
|
||||||
".#nixosConfigurations.${flake_target}.config.system.build.tarball" \
|
# hands the result to the remote shell to re-split, which would
|
||||||
--out-link "${repo_root}/result-${flake_target}"
|
# otherwise scatter NIX_EXTRA_OPTS (itself several space-separated,
|
||||||
local_image="$(find "${repo_root}/result-${flake_target}/tarball" -maxdepth 1 -type f | head -1)"
|
# %q-quoted tokens) across the wrong positional parameters below.
|
||||||
echo "Built: ${local_image}"
|
printf -v remote_cmd 'bash -s -- %q %q %q %q %q' \
|
||||||
|
"$remote_repo_dir" "$flake_target" "$remote_dir" "$remote_filename" "$NIX_EXTRA_OPTS"
|
||||||
|
ssh "$ssh_target" "$remote_cmd" <<'REMOTE_SCRIPT'
|
||||||
|
set -euo pipefail
|
||||||
|
repo_dir="$1"; target="$2"; dest_dir="$3"; dest_name="$4"; nix_extra_opts_str="$5"
|
||||||
|
declare -a NIX_OPTS=()
|
||||||
|
[[ -n "$nix_extra_opts_str" ]] && eval "NIX_OPTS=(${nix_extra_opts_str})"
|
||||||
|
cd "$repo_dir"
|
||||||
|
NIXOS_HOST_KEYS_DIR="$(pwd)/host-keys" nix build --impure \
|
||||||
|
--no-use-registries --no-accept-flake-config "${NIX_OPTS[@]}" \
|
||||||
|
".#nixosConfigurations.${target}.config.system.build.tarball" \
|
||||||
|
--out-link "result-${target}"
|
||||||
|
built="$(find "result-${target}/tarball" -maxdepth 1 -type f | head -1)"
|
||||||
|
if [[ -z "$built" ]]; then
|
||||||
|
echo "ERROR: no tarball found under result-${target}/tarball after build." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mkdir -p "$dest_dir"
|
||||||
|
cp "$built" "${dest_dir}/${dest_name}"
|
||||||
|
echo "Built and staged: ${dest_dir}/${dest_name}"
|
||||||
|
REMOTE_SCRIPT
|
||||||
|
local_image="$remote_path"
|
||||||
|
echo "Built on ${node}: ${remote_path}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
# PROXMOX_SSH_USER defaults to root (env.sh), which needs no sudo and
|
||||||
|
# can't assume it's even installed on a minimal node -- only shell out
|
||||||
|
# through sudo when actually running as a non-root SSH user.
|
||||||
|
sudo_prefix="sudo"
|
||||||
|
sudo_display="sudo "
|
||||||
|
if [[ "$PROXMOX_SSH_USER" == "root" ]]; then
|
||||||
|
sudo_prefix=""
|
||||||
|
sudo_display=""
|
||||||
|
fi
|
||||||
if [[ "$dry_run" -eq 1 ]]; then
|
if [[ "$dry_run" -eq 1 ]]; then
|
||||||
echo "[dry-run] would build: nix build --no-use-registries --no-accept-flake-config${nix_opts_display} \\"
|
echo "[dry-run] would build on ${node}: nix build --no-use-registries --no-accept-flake-config${nix_opts_display} \\"
|
||||||
echo "[dry-run] .#nixosConfigurations.${flake_target}.config.system.build.diskoImagesScript"
|
echo "[dry-run] .#nixosConfigurations.${flake_target}.config.system.build.diskoImagesScript"
|
||||||
echo "[dry-run] would run: sudo ./result-${flake_target} \\"
|
echo "[dry-run] would run: ${sudo_display}./result-${flake_target} \\"
|
||||||
echo "[dry-run] --pre-format-files host-keys/${flake_target}_ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key \\"
|
echo "[dry-run] --pre-format-files host-keys/${flake_target}_ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key \\"
|
||||||
echo "[dry-run] --pre-format-files host-keys/${flake_target}_ssh_host_ed25519_key.pub /etc/ssh/ssh_host_ed25519_key.pub \\"
|
echo "[dry-run] --pre-format-files host-keys/${flake_target}_ssh_host_ed25519_key.pub /etc/ssh/ssh_host_ed25519_key.pub \\"
|
||||||
echo "[dry-run] --build-memory 2048"
|
echo "[dry-run] --build-memory 2048"
|
||||||
|
echo "[dry-run] would stage the result at ${remote_path}"
|
||||||
local_image="<built-image>.raw"
|
local_image="<built-image>.raw"
|
||||||
else
|
else
|
||||||
echo "==> Building Disko image script for ${flake_target}..."
|
echo "==> Building Disko image for ${flake_target} on ${node}..."
|
||||||
nix build --no-use-registries --no-accept-flake-config "${NIX_OPTS[@]}" \
|
# See the LXC branch above for why this is one %q-quoted command
|
||||||
".#nixosConfigurations.${flake_target}.config.system.build.diskoImagesScript" \
|
# string rather than separate ssh argv elements.
|
||||||
--out-link "${repo_root}/result-${flake_target}"
|
printf -v remote_cmd 'bash -s -- %q %q %q %q %q %q' \
|
||||||
echo "==> Running it (builds the .raw image in a temporary QEMU VM, needs sudo)..."
|
"$remote_repo_dir" "$flake_target" "$remote_dir" "$remote_filename" "$NIX_EXTRA_OPTS" "$sudo_prefix"
|
||||||
( cd "$repo_root" && sudo "./result-${flake_target}" \
|
ssh "$ssh_target" "$remote_cmd" <<'REMOTE_SCRIPT'
|
||||||
--pre-format-files "host-keys/${flake_target}_ssh_host_ed25519_key" /etc/ssh/ssh_host_ed25519_key \
|
set -euo pipefail
|
||||||
--pre-format-files "host-keys/${flake_target}_ssh_host_ed25519_key.pub" /etc/ssh/ssh_host_ed25519_key.pub \
|
repo_dir="$1"; target="$2"; dest_dir="$3"; dest_name="$4"; nix_extra_opts_str="$5"; sudo_prefix="$6"
|
||||||
--build-memory 2048 )
|
declare -a NIX_OPTS=()
|
||||||
local_image="$(find "$repo_root" -maxdepth 1 -name "*.raw" -newer "${repo_root}/result-${flake_target}" | head -1)"
|
[[ -n "$nix_extra_opts_str" ]] && eval "NIX_OPTS=(${nix_extra_opts_str})"
|
||||||
if [[ -z "$local_image" ]]; then
|
cd "$repo_dir"
|
||||||
echo "ERROR: expected a .raw image after the build but didn't find one in ${repo_root}." >&2
|
nix build --no-use-registries --no-accept-flake-config "${NIX_OPTS[@]}" \
|
||||||
exit 1
|
".#nixosConfigurations.${target}.config.system.build.diskoImagesScript" \
|
||||||
fi
|
--out-link "result-${target}"
|
||||||
echo "Built: ${local_image}"
|
$sudo_prefix "./result-${target}" \
|
||||||
|
--pre-format-files "host-keys/${target}_ssh_host_ed25519_key" /etc/ssh/ssh_host_ed25519_key \
|
||||||
|
--pre-format-files "host-keys/${target}_ssh_host_ed25519_key.pub" /etc/ssh/ssh_host_ed25519_key.pub \
|
||||||
|
--build-memory 2048
|
||||||
|
built="$(find . -maxdepth 1 -name '*.raw' -newer "result-${target}" | head -1)"
|
||||||
|
if [[ -z "$built" ]]; then
|
||||||
|
echo "ERROR: no .raw image found in ${repo_dir} after build." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mkdir -p "$dest_dir"
|
||||||
|
mv "$built" "${dest_dir}/${dest_name}"
|
||||||
|
echo "Built and staged: ${dest_dir}/${dest_name}"
|
||||||
|
REMOTE_SCRIPT
|
||||||
|
local_image="$remote_path"
|
||||||
|
echo "Built on ${node}: ${remote_path}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- upload (skip entirely if reusing an image already on the node) ------
|
# --- upload -- only for an explicit --image; a build above stages its
|
||||||
|
# result directly at ${remote_path} on the node already, and reusing an
|
||||||
|
# image already on the node needs nothing transferred either. ------------
|
||||||
echo
|
echo
|
||||||
if [[ "$image_already_remote" -eq 1 ]]; then
|
if [[ -n "$image" ]]; then
|
||||||
: # nothing to upload
|
if [[ "$dry_run" -eq 1 ]]; then
|
||||||
elif [[ "$dry_run" -eq 1 ]]; then
|
echo "[dry-run] would upload: scp ${local_image} ${ssh_target}:${remote_path}"
|
||||||
echo "[dry-run] would upload: scp ${local_image} ${ssh_target}:${remote_path}"
|
else
|
||||||
else
|
echo "==> Uploading to ${node}:${remote_path}..."
|
||||||
echo "==> Uploading to ${node}:${remote_path}..."
|
ssh "$ssh_target" "mkdir -p ${remote_dir}"
|
||||||
ssh "$ssh_target" "mkdir -p ${remote_dir}"
|
scp "$local_image" "${ssh_target}:${remote_path}"
|
||||||
scp "$local_image" "${ssh_target}:${remote_path}"
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- create -----------------------------------------------------------------
|
# --- create -----------------------------------------------------------------
|
||||||
|
|||||||
+10
-1
@@ -14,6 +14,14 @@
|
|||||||
: "${PROXMOX_HOST:=pve.sweet.home}"
|
: "${PROXMOX_HOST:=pve.sweet.home}"
|
||||||
: "${PROXMOX_SSH_USER:=root}"
|
: "${PROXMOX_SSH_USER:=root}"
|
||||||
|
|
||||||
|
# Where this flake repo lives on the Proxmox node itself.
|
||||||
|
# scripts/create-proxmox-resource.sh builds images directly on the node
|
||||||
|
# instead of transferring them over the network -- it clones the repo here
|
||||||
|
# (from this checkout's own `origin` remote) the first time it doesn't
|
||||||
|
# find it, installing build tooling via scripts/codex-setup.sh, then
|
||||||
|
# `git pull`s it before every subsequent build.
|
||||||
|
: "${PROXMOX_REMOTE_REPO_DIR:=/root/nixos}"
|
||||||
|
|
||||||
# Storage pool names -- Proxmox's own stock-install defaults, but this
|
# Storage pool names -- Proxmox's own stock-install defaults, but this
|
||||||
# varies a lot by setup (ZFS pool name, custom LVM-thin volume, etc.).
|
# varies a lot by setup (ZFS pool name, custom LVM-thin volume, etc.).
|
||||||
# Verify with `pvesm status` on the node and correct these if wrong.
|
# Verify with `pvesm status` on the node and correct these if wrong.
|
||||||
@@ -49,7 +57,8 @@
|
|||||||
|
|
||||||
export PROXMOX_HOST PROXMOX_SSH_USER PROXMOX_STORAGE PROXMOX_ISO_STORAGE \
|
export PROXMOX_HOST PROXMOX_SSH_USER PROXMOX_STORAGE PROXMOX_ISO_STORAGE \
|
||||||
PROXMOX_BRIDGE PROXMOX_DEFAULT_CORES PROXMOX_DEFAULT_MEMORY_MB \
|
PROXMOX_BRIDGE PROXMOX_DEFAULT_CORES PROXMOX_DEFAULT_MEMORY_MB \
|
||||||
PROXMOX_DEFAULT_LXC_DISK_GB PROXMOX_DEFAULT_LXC_FEATURES
|
PROXMOX_DEFAULT_LXC_DISK_GB PROXMOX_DEFAULT_LXC_FEATURES \
|
||||||
|
PROXMOX_REMOTE_REPO_DIR
|
||||||
|
|
||||||
# Matches variables.nix's nixCacheHost -- update both if it ever changes.
|
# Matches variables.nix's nixCacheHost -- update both if it ever changes.
|
||||||
: "${NIX_CACHE_HOST:=nix-cache}"
|
: "${NIX_CACHE_HOST:=nix-cache}"
|
||||||
|
|||||||
+50
-41
@@ -5,76 +5,85 @@ sops:
|
|||||||
age:
|
age:
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIOWU1K2xnV2xpQVdOMmIz
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaMUpxYmUzaVY4d1pRY3g3
|
||||||
RUgyU3dvVmkxTXJabHQ4dTNtRm5ueisyeWpZCk1DeklsZG9TaEZ2KzRlSVB6Mmgy
|
empaVUJSN0JaSlNQQlJtZENwc0VMYVhJSkFvCmJQMkpSd3RoYzlKQjBSZWErQzR2
|
||||||
VVZ1aVI0U0psTTIvWkxiOG9jRU9DM0kKLS0tIHBYUHdRa2pTU0xnNWdWL0J1K0J0
|
aG5SVndOQWpSRTBDSWJVQkg0c0hiNFUKLS0tIHhiaEdpY3gwZkpCcHl2TW5CNThn
|
||||||
N0dLZTl0VjZIRWp6cGp0SnI0Y1RJMGMKC5x1mvsmadVnp6M0K+nU4vBOnHVU7+Yn
|
aVVUQy9Qd0trb0RNdUpVTXdrdGlrTmcK1uphQAyDV+Gk5+K1YOqw1Z8ynGP5sAPF
|
||||||
ef6WlzBooYlKei5pdh5pkJHksyy+DymZywLX1EKA+LwLYGKt58zF8w==
|
q5icujja/SGexX18hPYXbkyUtOrBYjW62gCuGJinSBPROoFUJbiP7g==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad
|
recipient: age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1OUdjSHgvOC81d1kxbnIv
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKOWZxcFlhRHhKelhDS29M
|
||||||
SlNMbzVPY0VGeFBzN2Z0VzZPQjhZVkN2RVZFCitxTHBtUTJpTURWaWUrSGJRb1lh
|
NGRlTEhJUGUzcFV6QVFCdTNkdEN3MlljWnl3CnI3LzVxSHBwSi9TYlRUcFdyN2py
|
||||||
Zi91WktPZkdtVERMdkNpSytSTHlhYWsKLS0tIHJWTHR6TFQrVXZ1U2dlUmI2Z0NX
|
cVZBV0Q3Z3FhRXA0T1NFQzd2R00yeEUKLS0tIHkxL2dHV3RkVFYxZTJNTVZvVFIr
|
||||||
WXRVRVVIV3hrQUR3cEFpOTRhWWVVYVUKGD+dBn5pEFekiwn0EAHTPydwKS6kRkz3
|
TXpJZzdnYlpJaXBmcjdWWUtxNkc4dWMKVsImJiavzUzSFn78pciNJPHaS3KWqJer
|
||||||
RgakGqUKbkib5iEc1aNoyxFT2WM4S9WFx9zgSuGwFplRi87/19KNvA==
|
VkxF6kF3tl2HmW46eVXtsQowdu+zVR9HS35i/HvQ1r1TyP6qT5ofcQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age19gfn2yedg76dmztm4hncr7vf3r3c9j0qpt4rap7y7gersjk4m3ks2lhd0e
|
recipient: age19gfn2yedg76dmztm4hncr7vf3r3c9j0qpt4rap7y7gersjk4m3ks2lhd0e
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuN09aWHpKRTgwRVVranRa
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyWjdSanRRaEI4VHFZVkdw
|
||||||
Z1dKMjF1UUxVR0RGNkhQMEpPekk5eCtQT2dzCi9CQ0s5bERaR1FDQmcyU2tzS1cz
|
NkxMODRuakFJTFNoTHZIRHptZFNxaGZ3K3lnCjJGR1FJalRsYmtLcHFxZW8yNU5W
|
||||||
aENSS3MzZ0VVdndKc1g1UTVOM1Vnam8KLS0tIDdZL2p5eU8rMmRHUUhSdDJtaDEz
|
MzBjWmltbzI3MTByUjB6djlEdllHNXMKLS0tIEhEOVhLVjZkRi9vUEtDWUhxT0NX
|
||||||
eXFkZUZtVEJFdFQzYk44ZFBCalZTL2sKMb2HbPuPNw12h6HldaIBI9ZGv6X7plrn
|
eUZ3bGdEaHdGbXZIYkowYUZuTWJ3d2MKMwgxOqlMH7GfLlseD4J277Dcg0KCD3d5
|
||||||
lyu7xcFoD5d3REu6TsEIQd1PgqQGr63/pbQ+6fteypPQrdSeBP5sqg==
|
jwJDb82kRWoBMicTJZXoq/5oe5blJNa7dWYoqgkYxMA2O+0igT+I6g==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age1ll6hj5ggruetgjwjfnplpn5xtq35uhlcdflksx3xmnjm6s3uad9sz70jkf
|
recipient: age1ll6hj5ggruetgjwjfnplpn5xtq35uhlcdflksx3xmnjm6s3uad9sz70jkf
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxY3ROYmJmUDlnVVN1bStZ
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsZzdRMm9zdlJHckFoREVs
|
||||||
dkloZDc3NVpnRUQwRzFYbFhIYTMxZVppZFdNCnVQVDJJSWJRT0pSeXJkdjVYWEtM
|
UkVXL3dCeWRuN2NqcnVsOWVNT1FLUHY3andrCmNFY0ZCby9SdnUyYlV6R05YNDB0
|
||||||
VFJSaXJEeUVMVGJidDlmTUhLZW1pTUEKLS0tIEVYb2gyMThBTDNUUFlNdVZyYzVm
|
em43SjRCNVhYbmpRZUVWT0cxQlhGdmsKLS0tIDZHazNyck5VNHBuNVM5bmRZUlpR
|
||||||
VlAyOXdScWJjVFJMVDlrcTFIMEwybzgK6v/+a62q1F1CLH2llwtfk31ZutTIUUA2
|
QzBSNy84VDdLVkZZbnNlUFYydXlreEEKYZaR2b7tyRAhPdP+ytpP0veUTi7pY9Nw
|
||||||
yw1lO0m7gKabPHtySuz+zOQgNRx9EsnGcSXAmWZ2MXW1+m+6OpNuBQ==
|
pK0h4hcegLNYJL1AfOYwFQoW7vb256GdmwdcuuBl1YBGXWGraaBnZg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age120le4a5l8dh3lyfgvmj3d9ksmej6ajs5mer5y7r0vfg3x9fn69dqf8xgzu
|
recipient: age120le4a5l8dh3lyfgvmj3d9ksmej6ajs5mer5y7r0vfg3x9fn69dqf8xgzu
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1SzBlOGVqL0h0Q2N0eDAw
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFSnZiOGpsL1BESWVEdUxx
|
||||||
QTNROHRVeVNOMDdLZTN2ZXNyNERMOGxEbUNFCjU2ZXJwb3ZlSEtoV2dvbVZjMWI4
|
dXc5LzBHTlNodGJ1S3hOeHd5Wmgxb3BPSHl3CnBEWDNTc3NDdzN3RHQxUlNLOEs5
|
||||||
c0NLbm9TaGtlNFZpeEFuQVVabmsvbGsKLS0tIEVRMUpZbmlTZHU0M09Cd2lpaGpl
|
RU1SS2tVT29XbDJCWVliWnVkekN4L1kKLS0tIGFqY2pNK2h2S2ZWMndrRVN6eUdN
|
||||||
akJzWGg1c0RHblNueTJMaFd3SytjeFkKUN00FC0MYc7MC8UMEOFtTHWMOh/Ratyd
|
M0NLY2EvTTVIYlZvdk9XY0NwNE14ZlEKcOwgCK3g56kId/4tEt+2iCcylisn+Fca
|
||||||
e8AvxBrGnEEKjm7PtCKOnFF7l5srBIsnuhjcyGCq8uTlE/6XS8mvBQ==
|
5VWamsXdbwxbxmCEEUbgN3aHrdVz3mV4+8FZqA34yXz8pc45/PUcFg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age1qz9d4ka4xgexujyd247s7lp737sulp5fhxl5d65fj2ykvc4j4edqrsdks8
|
recipient: age1qz9d4ka4xgexujyd247s7lp737sulp5fhxl5d65fj2ykvc4j4edqrsdks8
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2MWFIOHc4RDdyWEVIdDJy
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJU1cydFFuRnpCUU5mbjFu
|
||||||
UmtZZC9CS3l4WUlEejhkODlPb3VCc003eEdrCmlWcHJMRkpaQjI2WUpVNUozMkFE
|
TTIxREkxZ1hMalVtNjNjcHVaUXpPNWdib2tzCkRScWRTWHhxN3lhckI4UFpMSFRa
|
||||||
MEZNakE0Y2RZOU5XZXVNY3hEaDVQRTgKLS0tIGJaWGJscTZENnRQd0NFZUpsRjhs
|
RGxWcldlWnd5SVJFNWxQWjB3R0pMb3MKLS0tIGdjLzlhTHgyT2hjTmRTK1RiZmxS
|
||||||
d3YrR3dkS2VsV3J4THJwTng2VVNMeDgKIG+vd3mnwalAKnJ3neucl7sQ0sgsNcAt
|
OWRWYklBWkoyUG8raFNzd3JlRUtEUEUKw+NdAp1Mz0dEOUGPbqCV8y7029I3Kye0
|
||||||
WeUuF5C6QQXNlzUQClY5dmCvJmRjUIfS/m7s1WJAJbzUfaSOokxehg==
|
keU2T29JGCN1D6x//1NcMUYSaFZKgv0ZVSjVUCl1EnmlJ0nBdbaDXA==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age120whqj96g26lsgy4udvgsn8dc9lumh8jeu3a564fx79rjr5lxffqmrljuu
|
recipient: age120whqj96g26lsgy4udvgsn8dc9lumh8jeu3a564fx79rjr5lxffqmrljuu
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6OHRNd0FZSGZ6MFEwSnU3
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnNFlzYVBqaGFDVE9xbmt5
|
||||||
Tm1pUnoxK1Y4dGJCTk1EbldzaWlscUdzTWlJClpHcHhmVXE5WUZRaUt5TXM0TVJI
|
OVd4ZlZRdEVJd0JFdkRIYVA5ZUEwYjJjWVJjCnZzTExNbDlYbGN6c1dYU2ZlNEVs
|
||||||
UkxnUXhISGtmcUhndGNQcWNVWGVlOEEKLS0tIGJMSVR3OU1oSHkzQWpMMWVYTDV2
|
ZUo4MXdpc0tzbDI0MHl5eXc3d09VRDQKLS0tIGs4SGMya1RZQ0hpa2NtQk9Wa29C
|
||||||
enAxMzQ2NWk1Qzl6YnpVYTdydk5pSFEK/1s8Ej3QLoWPDmd3Yj0nLV1reQ5QCPZX
|
bmxIYWk1VThsaFhxRDlOOGhGQ2tYamsKs+PcOiaeNFujCWwZBr+nq1MzrGohl+ch
|
||||||
YhGlujb3rTlgxJaQCpqynf6w2Tf4dT/Wq5edE8tHnXyr/kHacpnsFg==
|
TASI7eNsiHmSVRzSMHv4mX+8yXDHIRgHbFuUty2gdgGFLRjYXe4gDA==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age164px2a8e48ptsf9ngtan38aa6jls4jdl26mzrgzf6sn3vcvt49hqjrgr8w
|
recipient: age1xjst4frdh0th6q8m7p7u9g5af7ty5jqeum0p6z8a52a9q7st7ewqw8yl9j
|
||||||
- enc: |
|
- enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrNklUU2UrN3ZTeGdYNTRw
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkcmVQYXV1NzRrQ2IxTElt
|
||||||
cXZZVXdrUEtxWjNKaWp2cDZrQW5tVkJ0MEdjCnN4NmgxYlJNNFNXODcvUFF6aEZS
|
QUJRMkhiUUJqRDdwQW03K0lCTEtkSTU5UDJrCjh6SldpQkF1NzIybTJTdnBlOHdQ
|
||||||
OUpEZkpXcU1CRDVEUlBGYVYzVXdYTEkKLS0tIGtyUDc4SjJYUFUzT3BtNnVCeTdZ
|
VlREMy9hM0ZaL21Pa0VPUzcvb0pQQjQKLS0tIFcrK0I3Z3Nhem45eHpZYmdWeit6
|
||||||
azJ4bk9sTWZYYWRoV1VPV0VBUzFVekEKsrD8hFi8F8ME0VO4CHAYa5N0swt5R2Bz
|
eXFtRHVxODhaNTVDdVR1a2tOb1N1U1EKZBdLHq8PRMKX2ndFr3AxFVAZRyvhFa1u
|
||||||
Ll6AgyEysPR3Q8dqGJnBV/b6hs2aVDyKgGjaAXlI55OxP3RgXJQ1vQ==
|
72R5tordo4IR3HSxG3Z06rokOITd+KKhaQ8NEWEC8qioAAMxEC9QWw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age10at8862478urh0eeuwh8hzln6ck78jgwtztgxatwqlzwagg77y5snm4xzg
|
recipient: age10at8862478urh0eeuwh8hzln6ck78jgwtztgxatwqlzwagg77y5snm4xzg
|
||||||
|
- enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0WjJPbXhXNTNyQUZzMmxS
|
||||||
|
Rkd3Yk5Ga3pPRXFtMFpXcmpBZ3RJYnJlaHhjClRDbFBHRVZ0SDdrNFdVWmUwalpT
|
||||||
|
WUt5a2RUTnQ4VFBGMlowR3JycDM3aXMKLS0tIERSeFd4cGdSbzRpSmpSQnB1Yng5
|
||||||
|
OHBma3lYeWEwQ2RvelpzZHRkN1JPWFEKLXkJfEkH3lo5Z4mj8PZXTfAfZn6B46To
|
||||||
|
U0G54tUh0U1EeMnI5ZPRGwDxi5K0eD68HjeE9MBvFBysOChP/ANDPQ==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
recipient: age1ezk9x53zt8kcnscdm80jcyf0xq97vndv7jsn3rl8cc0cwm2jmpmq372dzs
|
||||||
lastmodified: "2026-07-19T02:30:40Z"
|
lastmodified: "2026-07-19T02:30:40Z"
|
||||||
mac: ENC[AES256_GCM,data:UiL3VMDF6rq4Nr87KspcDx434q3tfNXeb5pwH2O+4ssNQ6xzcYDdzXBnhAY3zLBsqPMKrvHBd4Ot/gEMcq3FMIVe7Q6p9yWKpep66KZ/yWEhAlwIVhD79Oj8VS+1CHKjf25zpRdhZorp04oeFQQd9VfjJB4EE/Q1aVbwTGlpIic=,iv:i/0conaFgFia+wzNTdUL6tlSTw35HTK3Ap1Sr5RGHf8=,tag:ULbz5FllShA/JjlSRdxA0g==,type:str]
|
mac: ENC[AES256_GCM,data:UiL3VMDF6rq4Nr87KspcDx434q3tfNXeb5pwH2O+4ssNQ6xzcYDdzXBnhAY3zLBsqPMKrvHBd4Ot/gEMcq3FMIVe7Q6p9yWKpep66KZ/yWEhAlwIVhD79Oj8VS+1CHKjf25zpRdhZorp04oeFQQd9VfjJB4EE/Q1aVbwTGlpIic=,iv:i/0conaFgFia+wzNTdUL6tlSTw35HTK3Ap1Sr5RGHf8=,tag:ULbz5FllShA/JjlSRdxA0g==,type:str]
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
|
|||||||
Reference in new issue
Block a user