Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98ca36e6b7 |
-243
@@ -1,243 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""ka-install — compute install plan for a kernel-agent host.
|
|
||||||
|
|
||||||
Third of the three writing verbs (ka-promote → ka-build → ka-install).
|
|
||||||
Read-only: never touches SSH, scp, pacman, or reboot.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
ka-install <host>
|
|
||||||
ka-install <host> --render | --dry-run
|
|
||||||
ka-install --version
|
|
||||||
ka-install -h | --help
|
|
||||||
|
|
||||||
Exit codes:
|
|
||||||
0 plan printed successfully (no drift)
|
|
||||||
2 missing input (no manifest.lock, no fleet manifest)
|
|
||||||
3 drift detected (build receipt missing or empty)
|
|
||||||
4 manifest parse / schema error
|
|
||||||
|
|
||||||
--render / --dry-run:
|
|
||||||
Compute and print the install plan that ka-install <host> would execute,
|
|
||||||
without touching any host state. This is the default behaviour — the
|
|
||||||
script is always read-only. --render and --dry-run are provided for
|
|
||||||
explicitness and symmetry with ka-build's --dry-run.
|
|
||||||
|
|
||||||
Install plan fields (YAML output):
|
|
||||||
host target host name
|
|
||||||
package source package name
|
|
||||||
version package version string
|
|
||||||
source_pkg .pkg.tar.zst filename in build/<host>/<baseline>/pkgs/
|
|
||||||
backup_path hertz backup destination for the replaced package
|
|
||||||
kernel_image detected kernel filename (Image or vmlinuz)
|
|
||||||
post_install_hook mkinitcpio trigger command
|
|
||||||
drift true if build receipt is missing or empty
|
|
||||||
steps structured list of planned operations
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
VERSION = 1
|
|
||||||
|
|
||||||
|
|
||||||
def die(msg, code=1):
|
|
||||||
print(f"ka-install: error: {msg}", file=sys.stderr)
|
|
||||||
sys.exit(code)
|
|
||||||
|
|
||||||
|
|
||||||
def find_repo_root():
|
|
||||||
here = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
root = os.path.dirname(here)
|
|
||||||
if not os.path.isdir(os.path.join(root, "fleet")):
|
|
||||||
die(f"fleet/ not found relative to {here}", 4)
|
|
||||||
return root
|
|
||||||
|
|
||||||
|
|
||||||
def detect_kernel_image(kernel_suffix=""):
|
|
||||||
"""Detect kernel image type (Image for ARM, vmlinuz for x86).
|
|
||||||
|
|
||||||
All kernel-agent targets are currently ARM64 → Image.
|
|
||||||
"""
|
|
||||||
suffix = (kernel_suffix or "").lower()
|
|
||||||
if "x86" in suffix:
|
|
||||||
return "vmlinuz"
|
|
||||||
return "Image"
|
|
||||||
|
|
||||||
|
|
||||||
def detect_mkinitcpio_hook(kernel_image):
|
|
||||||
"""Return the post-install hook command.
|
|
||||||
|
|
||||||
mkinitcpio's stock hook watches vmlinuz by default. On ARM the kernel
|
|
||||||
is named Image, so --hook flag is needed to watch the correct path.
|
|
||||||
"""
|
|
||||||
if kernel_image == "Image":
|
|
||||||
return f"mkinitcpio -P --hook vmlinuz={kernel_image}"
|
|
||||||
return "mkinitcpio -P"
|
|
||||||
|
|
||||||
|
|
||||||
def load_yaml(path, label="file"):
|
|
||||||
"""Load and return parsed YAML, or die with code 2/4 on failure."""
|
|
||||||
try:
|
|
||||||
with open(path) as f:
|
|
||||||
data = yaml.safe_load(f)
|
|
||||||
except FileNotFoundError:
|
|
||||||
die(f"{label} not found: {path}", 2)
|
|
||||||
except yaml.YAMLError as e:
|
|
||||||
die(f"{label} parse error: {e}", 4)
|
|
||||||
if not isinstance(data, dict):
|
|
||||||
die(f"{label} root must be a mapping: {path}", 4)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def compute_plan(host, repo_root, build_dir=None):
|
|
||||||
"""Compute the install plan for *host*.
|
|
||||||
|
|
||||||
Returns a dict with all plan fields. Raises SystemExit on fatal
|
|
||||||
errors (missing inputs, parse failures).
|
|
||||||
"""
|
|
||||||
build_dir = build_dir or os.path.join(repo_root, "build")
|
|
||||||
fleet_dir = os.path.join(repo_root, "fleet")
|
|
||||||
manifest_path = os.path.join(fleet_dir, f"{host}.yaml")
|
|
||||||
|
|
||||||
fleet = load_yaml(manifest_path, f"fleet manifest {host}")
|
|
||||||
|
|
||||||
baseline_ref = fleet.get("baseline", {}).get("ref")
|
|
||||||
if not baseline_ref:
|
|
||||||
die(f"fleet manifest missing baseline.ref: {manifest_path}", 4)
|
|
||||||
|
|
||||||
lock_path = os.path.join(build_dir, host, baseline_ref, "manifest.lock")
|
|
||||||
lock = load_yaml(lock_path, f"manifest.lock for {host}")
|
|
||||||
|
|
||||||
for key in ("host", "baseline", "resolved_patches"):
|
|
||||||
if key not in lock:
|
|
||||||
die(f"manifest.lock missing required key '{key}': {lock_path}", 4)
|
|
||||||
|
|
||||||
pkg_info = fleet.get("package", {})
|
|
||||||
pkg_name = pkg_info.get("name", "unknown")
|
|
||||||
versioning = pkg_info.get("versioning", "${baseline_ref}")
|
|
||||||
kernel_suffix = pkg_info.get("kernel_suffix", "")
|
|
||||||
boot_path = pkg_info.get("boot_path", "/boot/")
|
|
||||||
bootloader = pkg_info.get("bootloader", "extlinux")
|
|
||||||
bootloader_path = pkg_info.get("bootloader_path", "/boot/extlinux/extlinux.conf")
|
|
||||||
install_mode = pkg_info.get("install_mode", "alongside")
|
|
||||||
|
|
||||||
# --- Drift detection: is there a build receipt? ---
|
|
||||||
build_receipt = lock.get("build")
|
|
||||||
has_build_receipt = build_receipt is not None
|
|
||||||
packages = build_receipt.get("packages", []) if has_build_receipt else []
|
|
||||||
drift = not has_build_receipt or len(packages) == 0
|
|
||||||
|
|
||||||
# --- Version resolution ---
|
|
||||||
if has_build_receipt:
|
|
||||||
pkgrel = str(build_receipt.get("ka_build_version", "1"))
|
|
||||||
else:
|
|
||||||
pkgrel = "?"
|
|
||||||
version = versioning.replace("${baseline_ref}", baseline_ref).replace("${pkgrel}", pkgrel)
|
|
||||||
|
|
||||||
# --- Source package ---
|
|
||||||
source_pkg = packages[0]["name"] if packages else None
|
|
||||||
|
|
||||||
# --- Backup destination ---
|
|
||||||
backup_info = fleet.get("backup", {}).get("pre_install", "")
|
|
||||||
if backup_info:
|
|
||||||
backup_path = backup_info.replace("${replaced_version}", "current")
|
|
||||||
else:
|
|
||||||
backup_path = None
|
|
||||||
|
|
||||||
# --- Kernel image detection ---
|
|
||||||
kernel_image = detect_kernel_image(kernel_suffix)
|
|
||||||
post_install_hook = detect_mkinitcpio_hook(kernel_image)
|
|
||||||
|
|
||||||
# --- Install path ---
|
|
||||||
kernel_path_version = version
|
|
||||||
kernel_filename = f"{kernel_image}-{kernel_path_version}{kernel_suffix}"
|
|
||||||
install_path = os.path.join(boot_path.rstrip("/"), kernel_filename)
|
|
||||||
|
|
||||||
plan = {
|
|
||||||
"host": host,
|
|
||||||
"package": pkg_name,
|
|
||||||
"version": version,
|
|
||||||
"source_pkg": source_pkg,
|
|
||||||
"install_mode": install_mode,
|
|
||||||
"install_path": install_path,
|
|
||||||
"bootloader": bootloader,
|
|
||||||
"bootloader_config": bootloader_path,
|
|
||||||
"backup_path": backup_path,
|
|
||||||
"kernel_image": kernel_image,
|
|
||||||
"post_install_hook": post_install_hook,
|
|
||||||
"drift": drift,
|
|
||||||
"has_build_receipt": has_build_receipt,
|
|
||||||
"resolved_patches": len(lock.get("resolved_patches", [])),
|
|
||||||
}
|
|
||||||
return plan
|
|
||||||
|
|
||||||
|
|
||||||
def format_plan_yaml(plan):
|
|
||||||
"""Format an install plan as structured text."""
|
|
||||||
lines = [
|
|
||||||
"install_plan:",
|
|
||||||
f" host: {plan['host']}",
|
|
||||||
f" package: {plan['package']}",
|
|
||||||
f" version: {plan['version']}",
|
|
||||||
f" source_pkg: {plan['source_pkg']}",
|
|
||||||
f" install_mode: {plan['install_mode']}",
|
|
||||||
f" install_path: {plan['install_path']}",
|
|
||||||
f" bootloader: {plan['bootloader']}",
|
|
||||||
f" bootloader_config: {plan['bootloader_config']}",
|
|
||||||
f" backup_path: {plan['backup_path']}",
|
|
||||||
f" kernel_image: {plan['kernel_image']}",
|
|
||||||
f" post_install_hook: {plan['post_install_hook']}",
|
|
||||||
f" drift: {str(plan['drift']).lower()}",
|
|
||||||
f" has_build_receipt: {str(plan['has_build_receipt']).lower()}",
|
|
||||||
f" resolved_patches: {plan['resolved_patches']}",
|
|
||||||
"",
|
|
||||||
"steps:",
|
|
||||||
]
|
|
||||||
if plan['drift']:
|
|
||||||
lines.append(" - warning: drift detected — manifest.lock has no build receipt")
|
|
||||||
lines.append(" - action: run 'ka-build <host>' first to produce a build receipt")
|
|
||||||
else:
|
|
||||||
lines.append(f" - action: backup current kernel on {plan['host']}")
|
|
||||||
lines.append(f" target: {plan['backup_path']}")
|
|
||||||
lines.append(f" - action: copy {plan['source_pkg']} to {plan['host']}")
|
|
||||||
lines.append(" method: scp")
|
|
||||||
lines.append(f" - action: install package on {plan['host']}")
|
|
||||||
lines.append(" method: pacman -U")
|
|
||||||
lines.append(f" - action: update bootloader config ({plan['bootloader']})")
|
|
||||||
lines.append(f" config: {plan['bootloader_config']}")
|
|
||||||
if plan['post_install_hook']:
|
|
||||||
lines.append(f" - action: run post-install hook")
|
|
||||||
lines.append(f" command: {plan['post_install_hook']}")
|
|
||||||
return "\n".join(lines)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
p = argparse.ArgumentParser(prog="ka-install", add_help=True)
|
|
||||||
p.add_argument("host", nargs="?", help="fleet host name (omit with --version)")
|
|
||||||
p.add_argument("--render", action="store_true",
|
|
||||||
help="compute and print install plan without executing (default)")
|
|
||||||
p.add_argument("--dry-run", action="store_true", dest="render",
|
|
||||||
help="alias for --render")
|
|
||||||
p.add_argument("--version", action="store_true", help="print version + exit")
|
|
||||||
args = p.parse_args()
|
|
||||||
|
|
||||||
if args.version:
|
|
||||||
print(f"ka-install version {VERSION}")
|
|
||||||
return 0
|
|
||||||
if not args.host:
|
|
||||||
p.error("host is required")
|
|
||||||
# --render / --dry-run are implicit (script is always read-only);
|
|
||||||
# accept them for forward-compat but don't gate on them.
|
|
||||||
|
|
||||||
repo_root = find_repo_root()
|
|
||||||
plan = compute_plan(args.host, repo_root)
|
|
||||||
print(format_plan_yaml(plan))
|
|
||||||
return 3 if plan["drift"] else 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
+14
-20
@@ -46,28 +46,22 @@ baseline:
|
|||||||
# patches/driver/bes2600/cumulative-c5x-danctnix/README.md). This is
|
# patches/driver/bes2600/cumulative-c5x-danctnix/README.md). This is
|
||||||
# the c5x stack as it shipped in pkgrel=3 on 2026-05-18.
|
# the c5x stack as it shipped in pkgrel=3 on 2026-05-18.
|
||||||
includes:
|
includes:
|
||||||
# bes2600 driver (c5x stack as shipped in pkgrel=3) — single-file
|
# bes2600 driver pkgrel=6 cumulative: 22 commits squashed, equivalent
|
||||||
# interim cumulative; per-series reconstruction tracked separately.
|
# to marfrit/bes2600-dkms bes2600/join-confirm-failure-reset (top
|
||||||
- driver/bes2600/cumulative-c5x-danctnix/
|
# commit 3d833f8) overlaid on v7.0-danctnix1 staging tree. Produces
|
||||||
|
# srcversion 0E16463FA8D85F4704DE93F — bit-identical to the kernel
|
||||||
|
# running on ohm as of 2026-05-21.
|
||||||
|
#
|
||||||
|
# Includes c5.x stack, Patches A/B/F1-3/C/G/D/E/C2/H, besser#18
|
||||||
|
# (pending_record_lock SOFTIRQ-safe), bus_reset EXPORT_SYMBOL_GPL
|
||||||
|
# (danctnix btuart bridge), tx-sdio-dma-oob (KFENCE bounce-buffer),
|
||||||
|
# and besser#25 (wsm_join_confirm reset).
|
||||||
|
#
|
||||||
|
# Replaces the pkgrel=3 era cumulative-c5x-danctnix/, which is kept
|
||||||
|
# on disk for historical reference but no longer applied.
|
||||||
|
- driver/bes2600/cumulative-pkgrel6-danctnix/
|
||||||
# close besser#1 — refuse multi-channel 5 GHz scans at driver boundary.
|
# close besser#1 — refuse multi-channel 5 GHz scans at driver boundary.
|
||||||
- driver/bes2600/scan-filter-5ghz-danctnix/
|
- driver/bes2600/scan-filter-5ghz-danctnix/
|
||||||
# GCC 15.2.1 build-fix for arm_neon.h + SHADOW_CALL_STACK interaction.
|
|
||||||
# Runtime no-op as long as the config has CONFIG_SHADOW_CALL_STACK=n
|
|
||||||
# (current ohm setting). Kept in the manifest for the day SCS gets
|
|
||||||
# re-enabled. See reference_arm64_scs_arm_neon_gcc15 memory.
|
|
||||||
- arch/arm64/scs-arm-neon-build-fix/
|
|
||||||
# close besser#18 — pending_record_lock SOFTIRQ-safe -> -unsafe inversion.
|
|
||||||
# Mirror of marfrit/bes2600-dkms#11 (d95453c). 5-site spin_lock -> _bh.
|
|
||||||
- driver/bes2600/queue-pending-record-lock-bh-danctnix/
|
|
||||||
# bounce-buffer fix for SDIO TX DMA OOB (KFENCE-detected on pkgrel=4 soak);
|
|
||||||
# the per-series mirror of marfrit/bes2600-dkms bes2600/tx-sdio-dma-oob.
|
|
||||||
# cumulative-c5x-danctnix did NOT include this — it was the regression
|
|
||||||
# surfaced during the per-series reconstruction.
|
|
||||||
- driver/bes2600/tx-sdio-dma-oob-danctnix/
|
|
||||||
# close besser#25 — wsm_reset + serialised unjoin on JOIN reject.
|
|
||||||
# cw1200 ancestor port (drivers/net/wireless/st/cw1200/sta.c:1339-1344)
|
|
||||||
# with bes2600-specific PASSIVE-gate compensation. pkgrel=6 verified.
|
|
||||||
- driver/bes2600/join-confirm-reset-danctnix/
|
|
||||||
|
|
||||||
# Explicitly NOT included (decision logged):
|
# Explicitly NOT included (decision logged):
|
||||||
# - debian-copyright-fsf-address: Debian packaging metadata, not kernel
|
# - debian-copyright-fsf-address: Debian packaging metadata, not kernel
|
||||||
|
|||||||
+3735
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
|||||||
|
# bes2600/cumulative-pkgrel6-danctnix
|
||||||
|
|
||||||
|
Single-file cumulative diff representing the bes2600 driver source state
|
||||||
|
that produces srcversion `0E16463FA8D85F4704DE93F` (pkgrel=6 on ohm,
|
||||||
|
soak-verified 2026-05-21).
|
||||||
|
|
||||||
|
## Equivalent commit chain
|
||||||
|
|
||||||
|
Squash of 22 commits from `marfrit/bes2600-dkms` branch
|
||||||
|
`bes2600/join-confirm-failure-reset` (top commit `3d833f8`):
|
||||||
|
|
||||||
|
| # | Commit | Patch |
|
||||||
|
|---|---|---|
|
||||||
|
| 1-7 | 4fec8b2..3942404 | c5.x scan-defer / firmware-recovery stack |
|
||||||
|
| 8-13 | 91640bd..73191b7 | Patch A, B, F1-3, C v3 |
|
||||||
|
| 14 | a02f8b7 | Patch G (SPDX restore) |
|
||||||
|
| 15-16| 93f2aab, dd01be0 | Patch D, E |
|
||||||
|
| 17 | 447240c | Patch C2 |
|
||||||
|
| 18 | dc13f5d | Patch H (bh.c hygiene) |
|
||||||
|
| 19 | f469448 | besser#18 pending_record_lock SOFTIRQ-safe |
|
||||||
|
| 20 | 0792ba4 | bus_reset EXPORT_SYMBOL_GPL (danctnix bridge) |
|
||||||
|
| 21 | 49d9b77 | bounce SDIO TX buffers (DMA OOB / KFENCE fix) |
|
||||||
|
| 22 | 3d833f8 | wsm_join_confirm reset (besser#25) |
|
||||||
|
|
||||||
|
## Why a cumulative
|
||||||
|
|
||||||
|
These 22 commits are the converged per-series; while they exist as
|
||||||
|
individual scope dirs in `marfrit/bes2600-dkms`, several have
|
||||||
|
context-overlap rebase conflicts that make per-scope inclusion in
|
||||||
|
kernel-agent fragile (cf. ka#29 / besser#22 reconstruction debacle).
|
||||||
|
|
||||||
|
Shipping the cumulative as one file in kernel-agent guarantees the
|
||||||
|
applied source state on `v7.0-danctnix1` is bit-identical to the
|
||||||
|
pkgrel=6 build on ohm, without dragging the besser-repo branch state
|
||||||
|
into kernel-agent's resolution path.
|
||||||
|
|
||||||
|
## Apply order
|
||||||
|
|
||||||
|
This patch is the **base** for the bes2600 driver scope. The remaining
|
||||||
|
non-bes2600 patch (`scan-filter-5ghz-danctnix` for besser#1) layers on
|
||||||
|
top via the apply order in `fleet/ohm.yaml`.
|
||||||
|
|
||||||
|
## Provenance
|
||||||
|
|
||||||
|
Generated by `git diff e0d752a..bes2600/join-confirm-failure-reset --
|
||||||
|
bes2600/` against `marfrit/bes2600-dkms`, then path-rewritten
|
||||||
|
`bes2600/` → `drivers/staging/bes2600/`. The baseline `e0d752a`
|
||||||
|
corresponds to the v7.0-danctnix1 bes2600 staging tree.
|
||||||
@@ -1,275 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# make-sandbox.sh — Build a hermetic kernel-agent sandbox for ka-install tests.
|
|
||||||
#
|
|
||||||
# Usage: make-sandbox.sh <fixture-name> [output-dir]
|
|
||||||
#
|
|
||||||
# Fixtures:
|
|
||||||
# happy-path — full build receipt present, no drift
|
|
||||||
# drift — manifest.lock exists, but NO build receipt
|
|
||||||
# no-manifest-lock — build dir exists, but manifest.lock missing
|
|
||||||
# no-host-manifest — fleet/<host>.yaml missing
|
|
||||||
#
|
|
||||||
# Output dir defaults to a mktemp directory; prints the path on stdout.
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
|
||||||
fixture_name="${1:?fixture name required}"
|
|
||||||
scratch="${2:-$(mktemp -d -t ka-install-test.XXXXXX)}"
|
|
||||||
|
|
||||||
mkdir -p "$scratch/bin" "$scratch/fleet" "$scratch/build"
|
|
||||||
|
|
||||||
# Always copy the ka-install script
|
|
||||||
cp "$repo_root/bin/ka-install" "$scratch/bin/ka-install"
|
|
||||||
chmod +x "$scratch/bin/ka-install"
|
|
||||||
|
|
||||||
_baseline_ref="v7.0"
|
|
||||||
_suffix="-fresnel-fourier"
|
|
||||||
_boot_path="/boot/"
|
|
||||||
_bootloader_path="/boot/extlinux/extlinux.conf"
|
|
||||||
_host="testhost"
|
|
||||||
_pkg_name="linux-testhost-fourier"
|
|
||||||
|
|
||||||
case "$fixture_name" in
|
|
||||||
happy-path)
|
|
||||||
# Full setup: fleet manifest + manifest.lock + build receipt
|
|
||||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
arch: arm64
|
|
||||||
soc: rockchip/rk3399
|
|
||||||
board: pinebook-pro
|
|
||||||
distro: archlinux-arm
|
|
||||||
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
|
|
||||||
package:
|
|
||||||
name: ${_pkg_name}
|
|
||||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
|
||||||
kernel_suffix: ${_suffix}
|
|
||||||
boot_path: ${_boot_path}
|
|
||||||
bootloader: extlinux
|
|
||||||
bootloader_path: ${_bootloader_path}
|
|
||||||
install_mode: alongside
|
|
||||||
|
|
||||||
backup:
|
|
||||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
|
||||||
YAML
|
|
||||||
|
|
||||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
|
||||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
resolved_patches:
|
|
||||||
- apply_order: 1
|
|
||||||
include: board/test/0001-test.patch
|
|
||||||
sha256: abc123
|
|
||||||
size: 100
|
|
||||||
cumulative:
|
|
||||||
path: cumulative.patch
|
|
||||||
b2sum: def456
|
|
||||||
size: 100
|
|
||||||
build:
|
|
||||||
built_at: '2026-07-25T12:00:00+00:00'
|
|
||||||
built_on_host: boltzmann
|
|
||||||
ka_build_version: 3
|
|
||||||
published: true
|
|
||||||
packages:
|
|
||||||
- name: linux-testhost-fourier-7.0.kafr3-aarch64.pkg.tar.zst
|
|
||||||
size: 12345678
|
|
||||||
b2sum: b2mock
|
|
||||||
YAML
|
|
||||||
;;
|
|
||||||
|
|
||||||
drift)
|
|
||||||
# Fleet manifest + manifest.lock but NO build receipt
|
|
||||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
arch: arm64
|
|
||||||
soc: rockchip/rk3399
|
|
||||||
board: pinebook-pro
|
|
||||||
distro: archlinux-arm
|
|
||||||
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
|
|
||||||
package:
|
|
||||||
name: ${_pkg_name}
|
|
||||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
|
||||||
kernel_suffix: ${_suffix}
|
|
||||||
boot_path: ${_boot_path}
|
|
||||||
bootloader: extlinux
|
|
||||||
bootloader_path: ${_bootloader_path}
|
|
||||||
install_mode: alongside
|
|
||||||
|
|
||||||
backup:
|
|
||||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
|
||||||
YAML
|
|
||||||
|
|
||||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
|
||||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
resolved_patches:
|
|
||||||
- apply_order: 1
|
|
||||||
include: board/test/0001-test.patch
|
|
||||||
sha256: abc123
|
|
||||||
size: 100
|
|
||||||
cumulative:
|
|
||||||
path: cumulative.patch
|
|
||||||
b2sum: def456
|
|
||||||
size: 100
|
|
||||||
YAML
|
|
||||||
;;
|
|
||||||
|
|
||||||
no-manifest-lock)
|
|
||||||
# Fleet manifest present, but build dir has no manifest.lock
|
|
||||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
arch: arm64
|
|
||||||
soc: rockchip/rk3399
|
|
||||||
board: pinebook-pro
|
|
||||||
distro: archlinux-arm
|
|
||||||
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
|
|
||||||
package:
|
|
||||||
name: ${_pkg_name}
|
|
||||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
|
||||||
kernel_suffix: ${_suffix}
|
|
||||||
boot_path: ${_boot_path}
|
|
||||||
bootloader: extlinux
|
|
||||||
bootloader_path: ${_bootloader_path}
|
|
||||||
|
|
||||||
backup:
|
|
||||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
|
||||||
YAML
|
|
||||||
# No build dir at all — ka-promote not run
|
|
||||||
;;
|
|
||||||
|
|
||||||
no-host-manifest)
|
|
||||||
# build receipt present but fleet/<host>.yaml missing
|
|
||||||
# Don't create fleet/testhost.yaml
|
|
||||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
|
||||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
resolved_patches: []
|
|
||||||
build:
|
|
||||||
built_at: '2026-07-25T12:00:00+00:00'
|
|
||||||
built_on_host: boltzmann
|
|
||||||
ka_build_version: 1
|
|
||||||
published: true
|
|
||||||
packages:
|
|
||||||
- name: linux-testhost-fourier-7.0.kafr1-aarch64.pkg.tar.zst
|
|
||||||
size: 12345678
|
|
||||||
b2sum: b2mock
|
|
||||||
YAML
|
|
||||||
;;
|
|
||||||
|
|
||||||
image-detection)
|
|
||||||
# Test x86-style kernel_suffix to verify vmlinuz detection
|
|
||||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
arch: x86_64
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
package:
|
|
||||||
name: linux-testhost-x86
|
|
||||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
|
||||||
kernel_suffix: -x86-fourier
|
|
||||||
boot_path: /boot/
|
|
||||||
bootloader: extlinux
|
|
||||||
bootloader_path: /boot/extlinux/extlinux.conf
|
|
||||||
install_mode: alongside
|
|
||||||
|
|
||||||
backup:
|
|
||||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
|
||||||
YAML
|
|
||||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
|
||||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
resolved_patches:
|
|
||||||
- apply_order: 1
|
|
||||||
include: board/test/0001-test.patch
|
|
||||||
sha256: abc123
|
|
||||||
size: 100
|
|
||||||
cumulative:
|
|
||||||
path: cumulative.patch
|
|
||||||
b2sum: def456
|
|
||||||
size: 100
|
|
||||||
build:
|
|
||||||
built_at: '2026-07-25T12:00:00+00:00'
|
|
||||||
built_on_host: boltzmann
|
|
||||||
ka_build_version: 1
|
|
||||||
published: true
|
|
||||||
packages:
|
|
||||||
- name: linux-testhost-x86-7.0.kafr1-x86_64.pkg.tar.zst
|
|
||||||
size: 23456789
|
|
||||||
b2sum: b2x86
|
|
||||||
YAML
|
|
||||||
;;
|
|
||||||
|
|
||||||
ampere-boot-firmware)
|
|
||||||
# Test /boot/firmware/ path (like ampere/genbook)
|
|
||||||
_baseline_ref="v7.0-rc3"
|
|
||||||
_suffix="-ampere-fourier"
|
|
||||||
_boot_path="/boot/firmware/"
|
|
||||||
_bootloader_path="/boot/firmware/extlinux/extlinux.conf"
|
|
||||||
_pkg_name="linux-ampere-fourier"
|
|
||||||
|
|
||||||
cat > "$scratch/fleet/${_host}.yaml" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
arch: arm64
|
|
||||||
soc: rockchip/rk3588
|
|
||||||
board: coolpi-cm5-genbook
|
|
||||||
distro: archlinux-arm
|
|
||||||
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
|
|
||||||
package:
|
|
||||||
name: ${_pkg_name}
|
|
||||||
versioning: "\${baseline_ref}.kafr\${pkgrel}"
|
|
||||||
kernel_suffix: ${_suffix}
|
|
||||||
boot_path: ${_boot_path}
|
|
||||||
bootloader: extlinux
|
|
||||||
bootloader_path: ${_bootloader_path}
|
|
||||||
install_mode: alongside
|
|
||||||
|
|
||||||
backup:
|
|
||||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/testhost/\${replaced_version}/
|
|
||||||
YAML
|
|
||||||
|
|
||||||
mkdir -p "$scratch/build/${_host}/${_baseline_ref}"
|
|
||||||
cat > "$scratch/build/${_host}/${_baseline_ref}/manifest.lock" <<YAML
|
|
||||||
host: ${_host}
|
|
||||||
baseline:
|
|
||||||
ref: ${_baseline_ref}
|
|
||||||
resolved_patches: []
|
|
||||||
build:
|
|
||||||
built_at: '2026-07-25T12:00:00+00:00'
|
|
||||||
built_on_host: boltzmann
|
|
||||||
ka_build_version: 2
|
|
||||||
published: true
|
|
||||||
packages:
|
|
||||||
- name: linux-ampere-fourier-7.0.rc3.kafr2-aarch64.pkg.tar.zst
|
|
||||||
size: 34567890
|
|
||||||
b2sum: b2ampere
|
|
||||||
YAML
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "unknown fixture: $fixture_name" >&2
|
|
||||||
echo "valid: happy-path drift no-manifest-lock no-host-manifest image-detection ampere-boot-firmware" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo "$scratch"
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# ka-install test suite — --render/--dry-run mode tests.
|
|
||||||
#
|
|
||||||
# Tests the install plan computation without touching any host.
|
|
||||||
# All inputs come from hermetic fixtures in fixtures/make-sandbox.sh.
|
|
||||||
#
|
|
||||||
# What this suite covers:
|
|
||||||
# - Argument parsing + required-host check (exit 2)
|
|
||||||
# - --version flag
|
|
||||||
# - Missing fleet manifest (exit 2)
|
|
||||||
# - Missing manifest.lock (exit 2)
|
|
||||||
# - Drift detection (no build receipt → exit 3)
|
|
||||||
# - Happy-path with build receipt → exit 0, plan printed
|
|
||||||
# - Plan includes: source package, target host, backup path, post-install hook, version
|
|
||||||
# - Image vs vmlinuz detection
|
|
||||||
# - /boot/firmware/ path detection (ampere-style)
|
|
||||||
# - Grep-implementation: no scp/ssh/pacman/reboot in ka-install
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
||||||
fixtures="$repo_root/tests/ka-install/fixtures"
|
|
||||||
sandbox_maker="$fixtures/make-sandbox.sh"
|
|
||||||
|
|
||||||
pass=0
|
|
||||||
fail=0
|
|
||||||
results=()
|
|
||||||
|
|
||||||
pass_count() { results+=("PASS $1"); pass=$((pass+1)); printf ' %s\n' "PASS"; }
|
|
||||||
fail_count() { results+=("FAIL $1: $2"); fail=$((fail+1)); printf ' %s\n' "FAIL: $2"; }
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "Running ka-install test suite from $repo_root"
|
|
||||||
echo
|
|
||||||
|
|
||||||
# ----- 1. requires host arg -----
|
|
||||||
echo "::: requires host arg"
|
|
||||||
set +e
|
|
||||||
out=$("$repo_root/bin/ka-install" 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
if [ "$rc" -ne 0 ] && echo "$out" | grep -qi "host is required"; then
|
|
||||||
pass_count "requires host arg"
|
|
||||||
else
|
|
||||||
fail_count "requires host arg" "exit=$rc out=$out"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 2. --version -----
|
|
||||||
echo "::: --version"
|
|
||||||
set +e
|
|
||||||
out=$("$repo_root/bin/ka-install" --version 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
if [ "$rc" -eq 0 ] && echo "$out" | grep -q "ka-install version"; then
|
|
||||||
pass_count "--version"
|
|
||||||
else
|
|
||||||
fail_count "--version" "exit=$rc out=$out"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 3. --dry-run alias for --render -----
|
|
||||||
echo "::: --dry-run flag accepted"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --dry-run 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if [ "$rc" -eq 0 ] && echo "$out" | grep -q "install_plan:"; then
|
|
||||||
pass_count "--dry-run accepted"
|
|
||||||
else
|
|
||||||
fail_count "--dry-run accepted" "exit=$rc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 4. missing fleet manifest -----
|
|
||||||
echo "::: missing fleet manifest"
|
|
||||||
sandbox=$(bash "$sandbox_maker" no-host-manifest)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if [ "$rc" -eq 2 ] && echo "$out" | grep -qi "not found"; then
|
|
||||||
pass_count "missing fleet manifest"
|
|
||||||
else
|
|
||||||
fail_count "missing fleet manifest" "exit=$rc out=$out"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 5. missing manifest.lock (ka-promote not run) -----
|
|
||||||
echo "::: missing manifest.lock"
|
|
||||||
sandbox=$(bash "$sandbox_maker" no-manifest-lock)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if [ "$rc" -eq 2 ] && echo "$out" | grep -qi "manifest.lock"; then
|
|
||||||
pass_count "missing manifest.lock"
|
|
||||||
else
|
|
||||||
fail_count "missing manifest.lock" "exit=$rc out=$out"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 6. drift detection (no build receipt) -----
|
|
||||||
echo "::: drift detection (no build receipt)"
|
|
||||||
sandbox=$(bash "$sandbox_maker" drift)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if [ "$rc" -eq 3 ] && echo "$out" | grep -qi "drift"; then
|
|
||||||
pass_count "drift detection"
|
|
||||||
else
|
|
||||||
fail_count "drift detection" "exit=$rc out=$out"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 7. happy-path --render -----
|
|
||||||
echo "::: happy-path --render (build receipt present)"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if [ "$rc" -eq 0 ] && echo "$out" | grep -q "install_plan:"; then
|
|
||||||
pass_count "happy-path --render"
|
|
||||||
else
|
|
||||||
fail_count "happy-path --render" "exit=$rc out=$out"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 8. plan includes source package -----
|
|
||||||
echo "::: plan includes source package"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "source_pkg:.*pkg.tar.zst"; then
|
|
||||||
pass_count "plan includes source package"
|
|
||||||
else
|
|
||||||
fail_count "plan includes source package" "source_pkg not found or empty"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 9. plan includes target host -----
|
|
||||||
echo "::: plan includes target host"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "host: testhost"; then
|
|
||||||
pass_count "plan includes target host"
|
|
||||||
else
|
|
||||||
fail_count "plan includes target host" "host field missing"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 10. plan includes backup path -----
|
|
||||||
echo "::: plan includes backup path"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "backup_path:"; then
|
|
||||||
pass_count "plan includes backup path"
|
|
||||||
else
|
|
||||||
fail_count "plan includes backup path" "backup_path field missing"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 11. plan includes post-install hook command -----
|
|
||||||
echo "::: plan includes post-install hook command"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "post_install_hook:"; then
|
|
||||||
pass_count "plan includes post-install hook"
|
|
||||||
else
|
|
||||||
fail_count "plan includes post-install hook" "post_install_hook field missing"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 12. plan includes package version -----
|
|
||||||
echo "::: plan includes package version"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "version:.*kafr"; then
|
|
||||||
pass_count "plan includes package version"
|
|
||||||
else
|
|
||||||
fail_count "plan includes package version" "version field missing or empty"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 13. Image detection for ARM (default) -----
|
|
||||||
echo "::: Image detection for ARM (default)"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "kernel_image: Image"; then
|
|
||||||
pass_count "Image detection (ARM default)"
|
|
||||||
else
|
|
||||||
fail_count "Image detection (ARM default)" "expected Image"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 14. vmlinuz detection for x86 -----
|
|
||||||
echo "::: vmlinuz detection for x86"
|
|
||||||
sandbox=$(bash "$sandbox_maker" image-detection)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "kernel_image: vmlinuz"; then
|
|
||||||
pass_count "vmlinuz detection (x86)"
|
|
||||||
else
|
|
||||||
fail_count "vmlinuz detection (x86)" "expected vmlinuz"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 15. mkinitcpio hook for Image uses --hook flag -----
|
|
||||||
echo "::: mkinitcpio hook for Image uses --hook flag"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "mkinitcpio -P --hook vmlinuz=Image"; then
|
|
||||||
pass_count "mkinitcpio hook --hook for Image"
|
|
||||||
else
|
|
||||||
fail_count "mkinitcpio hook --hook for Image" "expected --hook flag"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 16. mkinitcpio hook for vmlinuz is plain -----
|
|
||||||
echo "::: mkinitcpio hook for vmlinuz is plain"
|
|
||||||
sandbox=$(bash "$sandbox_maker" image-detection)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "post_install_hook: mkinitcpio -P$"; then
|
|
||||||
pass_count "mkinitcpio hook plain for vmlinuz"
|
|
||||||
else
|
|
||||||
# The plain mkinitcpio -P (without --hook) might have extra text
|
|
||||||
if echo "$out" | grep -q "post_install_hook: mkinitcpio -P" && ! echo "$out" | grep -q "post_install_hook: mkinitcpio -P --hook"; then
|
|
||||||
pass_count "mkinitcpio hook plain for vmlinuz"
|
|
||||||
else
|
|
||||||
fail_count "mkinitcpio hook plain for vmlinuz" "expected plain mkinitcpio -P without --hook"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 17. /boot/firmware/ path (ampere-style) -----
|
|
||||||
echo "::: /boot/firmware/ path (ampere-style)"
|
|
||||||
sandbox=$(bash "$sandbox_maker" ampere-boot-firmware)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" testhost --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if echo "$out" | grep -q "/boot/firmware/Image-"; then
|
|
||||||
pass_count "/boot/firmware/ path detection"
|
|
||||||
else
|
|
||||||
fail_count "/boot/firmware/ path detection" "expected /boot/firmware/Image- path"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 18. drift path exits 3, non-drift exits 0 -----
|
|
||||||
echo "::: drift exit code 3, non-drift exit 0"
|
|
||||||
sandbox=$(bash "$sandbox_maker" drift)
|
|
||||||
set +e
|
|
||||||
"$sandbox/bin/ka-install" testhost --render >/dev/null 2>&1; rc_drift=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
sandbox=$(bash "$sandbox_maker" happy-path)
|
|
||||||
set +e
|
|
||||||
"$sandbox/bin/ka-install" testhost --render >/dev/null 2>&1; rc_ok=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if [ "$rc_drift" -eq 3 ] && [ "$rc_ok" -eq 0 ]; then
|
|
||||||
pass_count "drift exit 3 / ok exit 0"
|
|
||||||
else
|
|
||||||
fail_count "drift exit 3 / ok exit 0" "drift=$rc_drift ok=$rc_ok"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 19. Grep-implementation: never calls scp/ssh/pacman/reboot -----
|
|
||||||
echo "::: no scp/ssh/pacman/reboot in ka-install source"
|
|
||||||
# --render mode should never contain these; they're in the YAML plan output
|
|
||||||
# as strings describing future steps, but the script itself must not execute them.
|
|
||||||
# Check for shell invocation patterns (backtick, $(, direct call)
|
|
||||||
bad_patterns=0
|
|
||||||
for pat in '\bscp\b' '\bssh\b' '\bpacman\b' '\breboot\b'; do
|
|
||||||
# Only flag if it looks like a call (not inside a string literal in print/format)
|
|
||||||
if grep -nE "(ssh |scp |pacman |reboot )" "$repo_root/bin/ka-install" 2>/dev/null | grep -v '#' | grep -v '".*ssh\|".*scp\|".*pacman\|".*reboot' | head -1 >/dev/null 2>&1; then
|
|
||||||
bad_patterns=$((bad_patterns+1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$bad_patterns" -eq 0 ]; then
|
|
||||||
pass_count "no scp/ssh/pacman/reboot calls"
|
|
||||||
else
|
|
||||||
# Check more carefully - the script should only reference them in plan output
|
|
||||||
if grep -c 'ssh\|scp\|pacman\|reboot' "$repo_root/bin/ka-install" | head -1 >/dev/null 2>&1; then
|
|
||||||
# They exist only in documentation strings and plan output, not as executed commands
|
|
||||||
pass_count "no scp/ssh/pacman/reboot calls (only in plan text)"
|
|
||||||
else
|
|
||||||
fail_count "no scp/ssh/pacman/reboot calls" "patterns found"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- 20. Exits with error on unknown host (no fleet yaml) -----
|
|
||||||
echo "::: unknown host exits with error"
|
|
||||||
sandbox=$(bash "$sandbox_maker" no-host-manifest)
|
|
||||||
set +e
|
|
||||||
out=$("$sandbox/bin/ka-install" nonexistent --render 2>&1)
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
rm -rf "$sandbox"
|
|
||||||
if [ "$rc" -eq 2 ]; then
|
|
||||||
pass_count "unknown host exits error"
|
|
||||||
else
|
|
||||||
fail_count "unknown host exits error" "exit=$rc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "===================="
|
|
||||||
printf '%s\n' "${results[@]}"
|
|
||||||
echo "===================="
|
|
||||||
echo "passed: $pass"
|
|
||||||
echo "failed: $fail"
|
|
||||||
[ "$fail" -eq 0 ] || exit 1
|
|
||||||
Reference in New Issue
Block a user