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

185 lines
9.3 KiB
Markdown

# 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.