suse-professional-package-i.../spec/main_spec.md

9.3 KiB

suse-professional-package-installer — spec

Spec-first entries per CE OS Script Development standards, one per script, written before generation.


main.sh (orchestrator)

  • Name: main.sh — top-level entry point; parses arguments, sources lib/ce-common.sh, invokes the requested subscript(s) in order.
  • Inputs: CLI args — an optional package-list file path, default local/zypper.list (gitignored, machine-specific real list — see .gitignore and packages/*.example below).
  • Outputs: stdout/log lines via ce-common.sh logging; exit 0 on full success, non-zero if any subscript reports failure.
  • Error behaviour: halt on missing/unreadable list file; otherwise log-and-continue between independent subscripts (a zypper failure doesn't block an unrelated later subscript), non-zero exit if any subscript failed.
  • Privilege: standard user — orchestrator never elevates itself or carries elevation between subscripts (per CE OS privilege model).
  • Doc references: ceos_script_architecture.md (orchestrator/ subscript model, privilege model).
  • Distro target: common (dispatches to distro-specific subscripts).
  • Exempt from the 100-line subscript boundary per the orchestrator exemption.

lib/ce-common.sh (shared library)

  • Name: ce-common.sh — logging, privilege-command detection, zypper wrapper functions, cleanup trap, user confirmation. Promoted/ generalized from the private tinkerpad-stt deployment's copy — project-specific bits (VOSK_HOME, hardcoded installer name) stripped for public reuse.
  • Inputs: sourced only, not executed directly. Reads CE_INSTALLER_NAME env var (optional, defaults to suse-pkg-install).
  • Outputs: exported functions/vars for consuming scripts (log_info, run_test, detect_priv_cmd, test_package_available, package_installed, install_packages, confirm_proceed, etc.). run_test(desc, cmd, mode=fail|warn) is the shared PASS/FAIL/WARN check helper (matches the established pattern in ~/.local/opt/package-installer/) — used both by 00_preflight.sh and by install_packages() itself for a post-install presence check per package (warn-mode: a verification miss is logged, not fatal).
  • Error behaviour: log_error + exit 1 on unrecoverable conditions (no priv command found, no zypper found).
  • Privilege: none itself — only detects what's available; escalation happens per-subscript at the point of use.
  • Doc references: ceos_script_architecture.md, ceos_script_source_discipline.md (never assume sudo vs doas).
  • Distro target: SUSE family (zypper only, scoped to this repo's name/purpose — unlike the private multi-manager ce-common.sh).
  • Line count: 188 non-blank lines — over the 100-line soft signal but within the 200-line hard ceiling for non-orchestrator scripts (RIS doc-set 65ppjj, section lin, chunks sft/hrd/exm — supersedes 0nxwoh, the original text which omitted the 200-line figure entirely; corrected 2026-08-06 per John's direct clarification during this project's review). Also arguably orchestrator-like itself, per John. Line limits are being deliberately not enforced strictly at this early-dev stage, with the intent to split this file further once real use/testing surfaces where the actual seams are — splitting now, before that, would be guessing at boundaries rather than finding them.

lib/00_preflight.sh (subscript)

  • Name: 00_preflight.sh — environment checks only, no system changes. This is the "dry run" step: it always runs, unconditionally, before any privileged subscript, and never itself prompts for privilege escalation.
  • Inputs: none.
  • Outputs: exit 0 if all fail-mode checks pass (warn-mode checks — internet reachability, disk space — log but don't block); exit 1 on the first fail-mode check that fails.
  • Error behaviour: halt immediately via run_test's fail mode (not running as root, zypper present, sudo-or-doas present); warn and continue for environmental checks that aren't hard requirements.
  • Privilege: standard user only — this subscript makes no privileged calls itself, by design.
  • Doc references: matches the pre-flight phase pattern in ~/.local/opt/package-installer/20260726-201557-package-installer.sh (the established local convention for this project's "dry-run and tests" behaviour, per John, 2026-08-06).
  • Distro target: SUSE family (zypper check), otherwise common.

tests/test_list_parsing.sh (test script — kept separate, never merged into an install script)

  • Name: test_list_parsing.sh — exercises read_package_list() (comment stripping, whitespace trimming, blank-line skipping, comment-only-file rejection, missing-file rejection) with no zypper calls and no privilege escalation.
  • Inputs: none (writes its own fixture files to a mktemp -d registered via register_temp_dir for automatic cleanup).
  • Outputs: exit 0 if every run_test check passes; exit 1 (via run_test's fail mode) on the first failing assertion.
  • Error behaviour: fail-fast — every assertion in this file is fail-mode, since a parsing regression should never be silently downgraded to a warning.
  • Privilege: standard user only.
  • Doc references: ceos_script_architecture.md ("Test scripts always remain separate — they are never merged into installation or configuration scripts").
  • Distro target: common (pure bash, no package-manager calls).

lib/10_zypper-packages.sh (subscript)

  • Name: 10_zypper-packages.sh — installs every package listed in a given zypper package-list file.
  • Inputs: $1 = path to a package-list file (one package name per line, #-prefixed comments and blank lines ignored). Defaults to local/zypper.list (gitignored) if not given.
  • Outputs: exit 0 if every listed package ends up installed or was already present; exit 1 if any install failed. Unavailable packages are warned about, not treated as fatal (matches existing install_packages() behaviour — a typo in one line shouldn't abort the whole run).
  • Error behaviour: halt immediately if the list file doesn't exist or is empty; per-package log-and-continue during install.
  • Privilege: requires escalation (installing system packages) — prompts for it at the point install_packages() first needs it, via detect_priv_cmd. Does not hold elevation before that point.
  • Doc references: ceos_script_architecture.md (privilege model — escalation isolated to the subscript that needs it).
  • Distro target: SUSE family (zypper).

Deferred (not built this pass)

  • lib/20_pip-packages.sh — pip/pipx package-list subscript. Not needed for the immediate target (poppler-tools, a zypper package), and per the standing rule zypper/pip must stay fully separate subscripts, never combined. Spec entry to be written when an actual pip/pipx list is needed.
  • Multi-distro (apk/apt/nix) support — deliberately out of scope. This repo's name and purpose are SUSE-specific; a general multi-distro engine already exists privately as ce-common.sh in ~/.local/opt/tinkerpad-stt/lib/ and is not what this public repo is for.
  • Textual list-authoring/validation TUI — explicitly deferred until the plain-text list format has been used for real and any rough edges are known.

Known gaps (Ambrosiana Gap Protocol — documented per ceos_script_source_discipline.md)

  • No Ambrosiana-sourced zypper/Tumbleweed documentation. Per the "no training-derived assumptions" rule, every zypper-specific behavior used here (zypper --non-interactive search -x, cache cleanup via zypper clean --all, rpm -q as the query mechanism) was verified live against the real machine, not sourced from Ambrosiana — it holds no zypper/Tumbleweed doc-set yet. Same gap already logged privately for tinkerpad-stt in ~/.local/opt/INSTALLER_NOTES.md. Per protocol step 3 (no quality alternative exists yet): proceeding with elevated live-verification discipline instead of blocking on it; this note is that documentation requirement being met. Should travel into the README's "Known bugs" section at public-release time.
  • Full CE OS deployment workflow not implemented. The methodology's full sequence (full-stack discovery, conflict analysis, FHS Relocator, offline USB preparation, formal two-stage QC with a specialised local agent ahead of Claude Code) targets full service/system deployments. This project is a lightweight package-list installer, not a service deployer — no package here lands in a non-FHS default location the Relocator would need to catch, and there's no service being deployed to discover conflicts against. Treating those pieces as out of proportion to scope rather than a compliance gap, but flagging explicitly rather than silently omitting them — John's call to confirm.
  • QC is single-stage in practice. No specialised local agent is currently trusted to run a Stage 1 pass ahead of Claude Code — local fleet models aren't yet evaluated as reliable enough for this role. Claude Code performs both drafting and QC (shellcheck + manual review) in one pass, consistent with how this gap is already handled elsewhere in this project ecosystem.