Plan repository audit remediation
This commit is contained in:
@@ -0,0 +1,498 @@
|
|||||||
|
# Panama repository audit remediation
|
||||||
|
|
||||||
|
Approved direction (2026-08-26): repair the complete repository audit in staged,
|
||||||
|
reviewable commits on one branch. Safety and test trust come first. No repair may
|
||||||
|
touch a real server, change a live firewall, or run a desktop-takeover check without
|
||||||
|
Gabriel explicitly approving that runtime step.
|
||||||
|
|
||||||
|
## Why this is one program
|
||||||
|
|
||||||
|
The audit found defects in four systems that depend on each other:
|
||||||
|
|
||||||
|
- `boot`, `install`, and `panama update` decide which code runs with root access.
|
||||||
|
- The server catalog and updater decide which network services run unattended.
|
||||||
|
- Quickshell owns capture, dictation, privacy state, and other long-lived desktop work.
|
||||||
|
- The contract runner is the proof for all three, but its safe classification and two
|
||||||
|
contracts are currently wrong.
|
||||||
|
|
||||||
|
Fixing a product defect while the gate is false-green or incorrectly labelled safe
|
||||||
|
would replace one uncertainty with another. This design therefore restores the gate
|
||||||
|
first, then fixes privileged and unattended paths, then the desktop.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
| Decision | Choice |
|
||||||
|
|---|---|
|
||||||
|
| Delivery | One remediation branch with a small commit per behavior |
|
||||||
|
| Order | Test trust, bootstrap, updates and server lifecycle, desktop, remaining hardening |
|
||||||
|
| Test style | Behavioral fixtures at public command and QML interfaces |
|
||||||
|
| Live desktop | Excluded from the default safe gate; explicit capability and approval required |
|
||||||
|
| Live server | Never used during implementation; Podman, systemd, SSH, and firewall are stubbed |
|
||||||
|
| Production | Out of scope; repository changes only |
|
||||||
|
| Visual design | Unchanged; no mocks are needed because no layout or copy redesign is planned |
|
||||||
|
| Compatibility | Existing command names and normal successful flows remain intact |
|
||||||
|
| Failure policy | Privileged or destructive uncertainty fails closed with a recovery instruction |
|
||||||
|
|
||||||
|
## Program structure
|
||||||
|
|
||||||
|
The work is five repair packages. Each package has its own tests, implementation,
|
||||||
|
review, and commit sequence. A package may use a helper introduced by an earlier one,
|
||||||
|
but it may not reach forward into unfinished work.
|
||||||
|
|
||||||
|
### Package 1: make the verification gate trustworthy
|
||||||
|
|
||||||
|
#### Explicit contract capabilities
|
||||||
|
|
||||||
|
`tests/contracts.manifest` becomes the source of truth for contract execution.
|
||||||
|
Every discovered executable contract has exactly one entry. Its format is
|
||||||
|
`<capability>[,<capability>...] <repo-relative-path>`, with `#` for whole-line
|
||||||
|
comments:
|
||||||
|
|
||||||
|
```text
|
||||||
|
hermetic tests/setup/boot-contract
|
||||||
|
live-compositor tests/hypr/keybind-categories-contract
|
||||||
|
live-desktop tests/quickshell/settings-pages-contract
|
||||||
|
network tests/quickshell/home-assistant-helper-contract
|
||||||
|
privileged tests/setup/root-server-bootstrap-contract
|
||||||
|
```
|
||||||
|
|
||||||
|
The vocabulary is deliberately small:
|
||||||
|
|
||||||
|
- `hermetic`: temporary state and stubbed system commands only.
|
||||||
|
- `live-compositor`: reads or reloads the running compositor, without moving windows.
|
||||||
|
- `live-desktop`: maps surfaces, moves focus or windows, or changes desktop state.
|
||||||
|
- `network`: contacts a non-fixture network endpoint.
|
||||||
|
- `privileged`: needs root or changes system configuration.
|
||||||
|
|
||||||
|
Capabilities may be combined. `panama test --safe` runs only `hermetic` contracts.
|
||||||
|
`hermetic` is exclusive and cannot be combined with another capability. Plain
|
||||||
|
`panama test` keeps its current all-contract meaning, but prints the capabilities
|
||||||
|
before each non-hermetic contract and requires a TTY confirmation. Automation must
|
||||||
|
grant each needed capability explicitly with repeatable flags such as
|
||||||
|
`--allow live-compositor --allow network`; there is no grant that means "anything."
|
||||||
|
Pattern selection does not bypass this rule.
|
||||||
|
|
||||||
|
The existing `tests/desktop-hijacking` file is retired after its explanations move
|
||||||
|
beside the matching manifest entries as comments. A contract fails the manifest gate
|
||||||
|
when a discovered path is missing, a manifest path is stale, a path is duplicated, or
|
||||||
|
an unknown capability appears. The runner fails closed rather than inferring safety
|
||||||
|
from source patterns.
|
||||||
|
|
||||||
|
#### Runner behavior
|
||||||
|
|
||||||
|
Each contract gets a configurable outer timeout. The default is 180 seconds and
|
||||||
|
`PANAMA_TEST_TIMEOUT_SECONDS` may change it for local diagnosis. The runner captures
|
||||||
|
stdout and stderr separately. On failure it prints both. On success it prints a
|
||||||
|
warning and the captured stderr rather than discarding it.
|
||||||
|
|
||||||
|
The runner creates its capture directory with `mktemp -d`, removes it on exit, and
|
||||||
|
reports a timeout as a normal failed contract. One stuck QML or IPC process cannot
|
||||||
|
block the remaining suite forever.
|
||||||
|
|
||||||
|
#### Current red and false-green contracts
|
||||||
|
|
||||||
|
- `agent-usage-contract` generates its session directory and timestamps from the
|
||||||
|
current local day. Production gains no test-only clock interface.
|
||||||
|
- `compose-secrets-contract` parses YAML and dotenv-shaped files as structured data.
|
||||||
|
Markdown is scanned only for private-key and known token signatures, not prose that
|
||||||
|
resembles an assignment.
|
||||||
|
- `update-command-contract` runs the real `panama update` command against a temporary
|
||||||
|
local bare remote, clone, temporary state, and stubbed installer/system commands.
|
||||||
|
Parser failures and fixture command failures must propagate. Successful stderr stays
|
||||||
|
visible through the runner.
|
||||||
|
- Contracts that currently write a probe into tracked or live-linked paths move the
|
||||||
|
probe into a complete temporary copy. Any unavoidable temporary mutation restores
|
||||||
|
from the EXIT trap, including interruption.
|
||||||
|
|
||||||
|
#### Test interfaces
|
||||||
|
|
||||||
|
- Contract discovery and execution: `panama test [--safe] [pattern]`.
|
||||||
|
- Update behavior: the real `panama update` command in disposable Git repositories.
|
||||||
|
- Secret policy: parsed Compose/env data plus explicit token fixtures.
|
||||||
|
|
||||||
|
Tests do not assert that a source file contains a command when they can execute the
|
||||||
|
public command against stubs and inspect the outcome.
|
||||||
|
|
||||||
|
### Package 2: secure bootstrap and privileged installation
|
||||||
|
|
||||||
|
#### SSH hardening transaction
|
||||||
|
|
||||||
|
Root server bootstrap may harden SSH only when all of these are true:
|
||||||
|
|
||||||
|
1. The target account has a nonempty regular `authorized_keys` file.
|
||||||
|
2. The `.ssh` directory and file are owned by the target user and have safe modes.
|
||||||
|
3. A candidate Panama drop-in passes `sshd -t` as part of the complete active config.
|
||||||
|
4. Reloading the detected SSH unit succeeds.
|
||||||
|
|
||||||
|
The drop-in is written to a same-directory temporary file and installed atomically.
|
||||||
|
If validation or reload fails, Panama restores the previous drop-in, validates the
|
||||||
|
restored configuration, and leaves root/password access unchanged. If the user has no
|
||||||
|
verified key, hardening is unavailable rather than merely defaulting to no.
|
||||||
|
|
||||||
|
The public interface stays `boot --server`. A new root-bootstrap contract supplies
|
||||||
|
stubbed `id`, `passwd`, `sshd`, `systemctl`, account data, and filesystem state. It
|
||||||
|
proves the no-key refusal, successful transaction, invalid-config rollback, and failed-
|
||||||
|
reload rollback.
|
||||||
|
|
||||||
|
#### Trusted installation inputs
|
||||||
|
|
||||||
|
No network response may be executed as root unless Panama verifies an immutable digest
|
||||||
|
or package signature first.
|
||||||
|
|
||||||
|
- Terra installation no longer uses `--nogpgcheck`. Before implementation, the plan
|
||||||
|
records the current official repository instructions, signing-key fingerprint, and
|
||||||
|
verification command in a provenance fixture. The contract pins that fingerprint.
|
||||||
|
If no verifiable path exists, the installer reports Terra unavailable and stops
|
||||||
|
before the desktop package transaction that depends on it.
|
||||||
|
- Claude Desktop's unpinned GitHub Pages installer is removed from the automatic path.
|
||||||
|
Panama may install the package when a trusted repository is already configured. It
|
||||||
|
otherwise reports a manual optional step and continues without Claude Desktop.
|
||||||
|
- Existing remote installers for Bun, Claude Code, and similar tools are audited under
|
||||||
|
the same rule. A tool that cannot offer a pinned or signed installation path moves to
|
||||||
|
an explicit optional action rather than remaining in the unattended base install.
|
||||||
|
|
||||||
|
Package contracts test artifact provenance and failure behavior with local fixtures.
|
||||||
|
They never contact the real repositories.
|
||||||
|
|
||||||
|
#### Server firewall transaction
|
||||||
|
|
||||||
|
Server setup establishes the policy it documents:
|
||||||
|
|
||||||
|
- firewalld must be installed, enabled, and active, or server setup fails.
|
||||||
|
- Ports 80 and 443 accept public traffic only from validated Cloudflare IPv4 and IPv6
|
||||||
|
ranges held in dedicated firewalld ipsets.
|
||||||
|
- Port 81 is assigned only to the WireGuard interface or zone.
|
||||||
|
- No service-specific port is opened automatically.
|
||||||
|
- Updating Cloudflare ranges validates every CIDR before replacing the last known good
|
||||||
|
ipsets. An empty or malformed download changes nothing.
|
||||||
|
- The complete permanent configuration is applied and reloaded as one recoverable
|
||||||
|
transaction. A failure restores the previous Panama-owned rules.
|
||||||
|
|
||||||
|
The repository carries the policy and updater, not a claim that an external cloud
|
||||||
|
firewall happens to compensate. Fixture tests cover inactive firewalld, zone selection,
|
||||||
|
bad CIDRs, rollback, and repeated setup.
|
||||||
|
|
||||||
|
### Package 3: make updates, migrations, and server lifecycle recoverable
|
||||||
|
|
||||||
|
#### Clean-revision machine updates
|
||||||
|
|
||||||
|
`panama update` keeps local work stashed until the pulled checkout has completed
|
||||||
|
`install --upgrade` and migrations. It records the exact stash object it created and
|
||||||
|
does not assume `stash@{0}` still names it.
|
||||||
|
|
||||||
|
An EXIT/INT/TERM recovery handler restores that stash only when the pulled update has
|
||||||
|
finished and the worktree is clean. If restoration conflicts or the tree is not clean,
|
||||||
|
the handler leaves the exact stash untouched and prints its object ID and recovery
|
||||||
|
command. A next-run check also reports an unfinished Panama update, which covers SIGKILL
|
||||||
|
and power loss that no trap can catch.
|
||||||
|
|
||||||
|
Installer edits restored after the trusted update are not executed during that run.
|
||||||
|
The update contract proves dirty dotfiles, dirty installer code, pull failure, installer
|
||||||
|
failure, interruption, successful restore, and conflicting restore.
|
||||||
|
|
||||||
|
A failed or unavailable pull remains visible in the final status and makes `panama
|
||||||
|
update` return nonzero after safe local repairs finish. Interactive updates preflight
|
||||||
|
administrator authentication once. A noninteractive update uses `sudo -n` and fails
|
||||||
|
immediately with a clear instruction instead of waiting on a hidden prompt. Documentation
|
||||||
|
states that routine updates ask no Panama questions but may require administrator
|
||||||
|
authentication.
|
||||||
|
|
||||||
|
#### Exact installer state
|
||||||
|
|
||||||
|
Before disabling idle behavior, `install` records whether each relevant gsettings key
|
||||||
|
exists and its exact serialized value. The EXIT handler restores only keys it changed,
|
||||||
|
using those exact values. A missing schema remains untouched.
|
||||||
|
|
||||||
|
Every declared stage is required. A missing or non-executable stage is recorded as a
|
||||||
|
failed stage and makes the final result nonzero.
|
||||||
|
|
||||||
|
Automatic migration baselining is removed. Shipped migrations are self-guarding and run
|
||||||
|
on both fresh and existing machines. `--baseline` remains an explicit development/admin
|
||||||
|
command but no install path infers freshness from an absent state directory.
|
||||||
|
|
||||||
|
The secret relocation migration exits nonzero while both the old and new secret files
|
||||||
|
exist. It tightens the old file to mode `0600`, prints the two exact paths and required
|
||||||
|
manual reconciliation, and retries on the next migration run. It never marks unresolved
|
||||||
|
secret state complete.
|
||||||
|
|
||||||
|
#### Collision-proof displacement
|
||||||
|
|
||||||
|
A shared shell module owns backup displacement for installer, user-content, skills, and
|
||||||
|
server-definition paths. Its small interface accepts a source path and a backup category.
|
||||||
|
It guarantees:
|
||||||
|
|
||||||
|
- Panama-owned symlinks are replaced without backup.
|
||||||
|
- Foreign symlinks are moved, never discarded.
|
||||||
|
- Existing backups are never overwritten.
|
||||||
|
- The destination is unique without relying on second-resolution timestamps alone.
|
||||||
|
- A failed move leaves the original object in place and returns nonzero.
|
||||||
|
|
||||||
|
Callers no longer invent `.bak` or `.pre-panama` names independently. Behavioral tests
|
||||||
|
exercise repeated runs, foreign symlinks, collisions, and failure paths through the
|
||||||
|
public stage commands.
|
||||||
|
|
||||||
|
#### Server catalog containment and portability
|
||||||
|
|
||||||
|
`panama server` accepts only an exact service name returned by the catalog. Separators,
|
||||||
|
dot components, and aliases are rejected before any target path is created.
|
||||||
|
|
||||||
|
Compose definitions use `${HOME}` and `${XDG_RUNTIME_DIR}` rather than `/home/gib` and
|
||||||
|
`/run/user/1000`. `RequiresMountsFor` is removed where unused and uses `%h` only for a
|
||||||
|
service that truly needs the media mount. Existing `.env` files must be regular,
|
||||||
|
non-symlink files and are corrected to mode `0600` on every enable.
|
||||||
|
|
||||||
|
The nightly update unit executes a stable command linked under `~/.local/bin`, not a
|
||||||
|
hard-coded checkout path. Setup creates that link from the resolved `PANAMA_PATH`, so a
|
||||||
|
supported custom checkout receives the same timer behavior as the default location.
|
||||||
|
|
||||||
|
`disable` stops the unit, verifies the compose containers are stopped, and only then
|
||||||
|
unlinks the unit. Failure leaves the management link installed and reports the commands
|
||||||
|
needed for diagnosis.
|
||||||
|
|
||||||
|
Definition tracking separates `seen` from `applied` hashes. Relinking may update `seen`,
|
||||||
|
but only a verified successful restart updates `applied`, so an unapplied definition
|
||||||
|
keeps warning.
|
||||||
|
|
||||||
|
#### Safe unattended container updates
|
||||||
|
|
||||||
|
The updater takes a nonblocking `flock` for the complete run. It gets resolved images
|
||||||
|
from `podman compose config --images`; dotenv files are never sourced or evaluated as
|
||||||
|
shell code.
|
||||||
|
|
||||||
|
Before pulling, the updater records every running container's image ID and tags enough
|
||||||
|
rollback references to recreate the old project. After `compose up -d`, it waits with a
|
||||||
|
bounded timeout until every expected container is running and each declared healthcheck
|
||||||
|
is healthy. A service without healthchecks still has to remain running for the complete
|
||||||
|
stability window.
|
||||||
|
|
||||||
|
On failure, it restores the old image references, recreates the project, verifies the
|
||||||
|
rollback, records the service as failed, and keeps the rollback images. Image pruning
|
||||||
|
runs only after every changed service passed verification. A rollback failure is called
|
||||||
|
out separately and keeps all images.
|
||||||
|
|
||||||
|
The updater's public interface and systemd timer stay the same. A fixture contract stubs
|
||||||
|
`podman`, `podman compose`, and `systemctl` to prove pull failure, unhealthy startup,
|
||||||
|
crash after startup, successful update, successful rollback, failed rollback, frozen and
|
||||||
|
stopped services, concurrency, and hostile dotenv values.
|
||||||
|
|
||||||
|
#### Container privilege and secret policy
|
||||||
|
|
||||||
|
Socket consumers are split by what they need:
|
||||||
|
|
||||||
|
- Read-only monitoring uses an allowlisted socket proxy. A read-only bind mount is not
|
||||||
|
treated as an API permission boundary.
|
||||||
|
- Portainer retains administrative control only when pinned to an immutable image,
|
||||||
|
bound to WireGuard, excluded from automatic updates, and explicitly enabled as a
|
||||||
|
trusted administrator.
|
||||||
|
- Spoon's job worker runs under a dedicated Unix account and rootless Podman runtime so
|
||||||
|
a job cannot mount the main server account's SSH keys, service data, or `.env` files.
|
||||||
|
- Services that do not require the Podman API lose the socket mount.
|
||||||
|
|
||||||
|
Every service receives only the environment variables it needs. Redis, MinIO, and other
|
||||||
|
sidecars do not inherit a stack-wide `.env`. The catalog contract inventories socket
|
||||||
|
mounts, floating tags, `label:disable`, `seccomp:unconfined`, published ports, and broad
|
||||||
|
`env_file` use. Intentional exceptions name their risk and update policy in a machine-
|
||||||
|
checked manifest.
|
||||||
|
|
||||||
|
Required SMTP and mail settings live in each service's `.env.example`; Compose carries
|
||||||
|
only `${VAR}` references. `CHANGE_ME` never appears inline where `panama server enable`
|
||||||
|
cannot detect it.
|
||||||
|
|
||||||
|
Publicly sourced images use immutable versions or digests. A service that deliberately
|
||||||
|
tracks a locally controlled `latest` tag is excluded from unattended pulls unless its
|
||||||
|
deployment pipeline supplies and records an immutable digest.
|
||||||
|
|
||||||
|
### Package 4: fix desktop races and permanent work
|
||||||
|
|
||||||
|
#### One monitor per capture transaction
|
||||||
|
|
||||||
|
Capture snapshots the focused output name when a transaction opens and never reads live
|
||||||
|
focus again for that transaction. `shell.qml` creates one capture overlay per
|
||||||
|
`Quickshell.screens` entry. Only the overlay whose screen matches the snapshotted output
|
||||||
|
maps and accepts coordinates. Freeze, selection, capture, and commit all use the same
|
||||||
|
output name.
|
||||||
|
|
||||||
|
A two-screen QML fixture proves that focus changes after open do not move the transaction
|
||||||
|
and that overlay-local coordinates resolve against the frozen output.
|
||||||
|
|
||||||
|
Screenshot and recording destinations include millisecond precision plus an exclusive
|
||||||
|
collision suffix. The large frozen frame loads asynchronously while its overlay remains
|
||||||
|
unmapped; the overlay maps only after the image is ready or the fallback state is known.
|
||||||
|
|
||||||
|
#### Owned dictation recorder
|
||||||
|
|
||||||
|
The dictation helper serializes start, stop, cancel, and recovery with a lock. State is
|
||||||
|
written to a mode-`0600` temporary file and atomically replaced only after `pw-record`
|
||||||
|
starts.
|
||||||
|
|
||||||
|
State carries PID, `/proc` start time, expected executable identity, recording path, and
|
||||||
|
creation time. Stop and cancel signal a process only after all identity fields match.
|
||||||
|
Stale state is removed without signalling an unknown PID. Concurrent start returns the
|
||||||
|
existing active recording instead of launching a second recorder.
|
||||||
|
|
||||||
|
Behavioral tests use real short-lived fixture processes to prove concurrent start, stale
|
||||||
|
PID, PID mismatch, normal stop, cancel, and interrupted state write.
|
||||||
|
|
||||||
|
#### Request-owned Screen Intelligence work
|
||||||
|
|
||||||
|
Every analysis receives a monotonically increasing generation. Capture, OCR, and model
|
||||||
|
processes record that generation when started. Stream and exit callbacks ignore output
|
||||||
|
whose generation no longer matches the active request. `close()` invalidates the
|
||||||
|
generation before stopping any process.
|
||||||
|
|
||||||
|
The public QML interface does not change. A fixture overlaps requests and closes during
|
||||||
|
OCR to prove an old callback cannot set `ready`, `error`, or replace the new result.
|
||||||
|
|
||||||
|
#### Event-driven privacy state
|
||||||
|
|
||||||
|
Privacy monitoring uses Quickshell's PipeWire registry, node, link, and property change
|
||||||
|
signals. It does not fork `pw-dump` on an idle timer. Construction may perform at most
|
||||||
|
one initial registry read; every later update reacts to graph changes.
|
||||||
|
|
||||||
|
The existing curated-event and privacy interfaces remain intact. A contract runs an
|
||||||
|
isolated registry fixture long enough to prove no periodic process launches occur and
|
||||||
|
that camera, microphone, and screen-capture transitions still publish the same state.
|
||||||
|
|
||||||
|
#### Owned wallpaper processes and atomic writes
|
||||||
|
|
||||||
|
Video wallpaper cleanup signals only processes Panama launched. It tracks process IDs
|
||||||
|
and start times or uses a dedicated user-service cgroup. Global `pkill -x mpvpaper` and
|
||||||
|
global `pgrep` are removed.
|
||||||
|
|
||||||
|
Helpers that rewrite Compose, settings, or generated configuration write a same-directory
|
||||||
|
temporary file, preserve ownership and mode, flush and fsync, validate the temporary
|
||||||
|
content, then atomically replace the destination. A failed validation or write leaves the
|
||||||
|
original byte-for-byte intact.
|
||||||
|
|
||||||
|
#### Pinned speech assets
|
||||||
|
|
||||||
|
The Whisper container uses an immutable digest. The model has a committed URL, expected
|
||||||
|
size, and SHA-256. Downloads go to a temporary file and become active only after all
|
||||||
|
checks pass. A mismatch removes the temporary file and preserves the installed model.
|
||||||
|
|
||||||
|
### Package 5: remaining hardening and documentation
|
||||||
|
|
||||||
|
#### Desktop entries and media outputs
|
||||||
|
|
||||||
|
`panama-webapp` rejects NUL, newline, carriage return, and unsupported URL schemes.
|
||||||
|
It parses the URL, requires one logical argument, and escapes each Desktop Entry field
|
||||||
|
according to the specification. Browser switches cannot be introduced through the URL.
|
||||||
|
|
||||||
|
`panama-transcode` reserves a unique temporary output in the destination directory,
|
||||||
|
writes only to that path, and atomically renames after success. Failure cleanup removes
|
||||||
|
only the inode it created.
|
||||||
|
|
||||||
|
#### Documentation and policy alignment
|
||||||
|
|
||||||
|
- README role behavior, contract count, safe-test meaning, and sudo requirements match
|
||||||
|
the implemented commands.
|
||||||
|
- The manual uses the current Settings route names and hidden-leaf taxonomy.
|
||||||
|
- Migration guidance describes the actual interactive and noninteractive privilege
|
||||||
|
policy. Tests validate each command invocation, not file-wide word presence.
|
||||||
|
- Server documentation distinguishes policy Panama enforces from external firewall or
|
||||||
|
hosting assumptions.
|
||||||
|
- Generated settings documentation remains `--check` clean.
|
||||||
|
|
||||||
|
## Verification strategy
|
||||||
|
|
||||||
|
Every behavior follows one red-green cycle through an agreed interface:
|
||||||
|
|
||||||
|
| Repair | Interface under test | System adapter |
|
||||||
|
|---|---|---|
|
||||||
|
| Contract safety | `panama test` | temporary manifest and fixture contracts |
|
||||||
|
| Update safety | `panama update` | local Git remote and stub installer |
|
||||||
|
| Root bootstrap | `boot --server` | stub accounts, sshd, systemd, filesystem |
|
||||||
|
| Firewall | `setup-server` | stub firewall-cmd and systemctl |
|
||||||
|
| Installer state | `install` | temporary HOME/state and stub gsettings/stages |
|
||||||
|
| Server management | `panama server` | temporary catalog/HOME and stub systemctl/compose |
|
||||||
|
| Image updater | updater command | stateful Podman/systemd fixture |
|
||||||
|
| Capture | Capture QML interface | two-screen semantic harness |
|
||||||
|
| Dictation | helper CLI | fixture recorder processes and temporary runtime dir |
|
||||||
|
| Screen Intelligence | QML interface | delayed fixture processes |
|
||||||
|
| Privacy | privacy QML state | isolated PipeWire fixture |
|
||||||
|
|
||||||
|
After each package:
|
||||||
|
|
||||||
|
1. Run the focused contracts changed by that package.
|
||||||
|
2. Run `panama test --safe` under the new manifest.
|
||||||
|
3. Run syntax checks for every touched shell, Python, Lua, QML, YAML, and systemd file
|
||||||
|
using the tools available on the host.
|
||||||
|
4. Request independent code review and resolve Critical and Important findings.
|
||||||
|
5. Commit only that package.
|
||||||
|
|
||||||
|
Final repository verification includes the complete hermetic suite, Hyprland config
|
||||||
|
validation, generated-document checks, Compose rendering with fixture env files, secret
|
||||||
|
scanning, and `git diff --check`.
|
||||||
|
|
||||||
|
Live desktop checks are a separate, explicitly approved gate after all hermetic work is
|
||||||
|
green. Server cutover, service restarts, SSH reload, firewall mutation, and production
|
||||||
|
deployment are not part of this implementation branch.
|
||||||
|
|
||||||
|
## Audit finding ledger
|
||||||
|
|
||||||
|
This table prevents a smaller issue from disappearing behind the larger repairs.
|
||||||
|
|
||||||
|
| Finding | Package |
|
||||||
|
|---|---|
|
||||||
|
| SSH hardening lockout | 2 |
|
||||||
|
| Unverified root installation inputs | 2 |
|
||||||
|
| Missing documented firewall policy | 2 |
|
||||||
|
| Update executes restored work-in-progress | 3 |
|
||||||
|
| Interrupted update recovery | 3 |
|
||||||
|
| Pull failure followed by success status | 3 |
|
||||||
|
| Hidden sudo prompt on noninteractive update | 3 |
|
||||||
|
| Hard-coded idle restoration | 3 |
|
||||||
|
| Automatic migration baseline inference | 3 |
|
||||||
|
| Unresolved secret migration marked complete | 3 |
|
||||||
|
| Missing required stage skipped | 3 |
|
||||||
|
| Backup collisions and foreign symlink loss | 3 |
|
||||||
|
| Dotenv sourced and evaluated as shell | 3 |
|
||||||
|
| Invalid container health gate and premature prune | 3 |
|
||||||
|
| Server disable false success | 3 |
|
||||||
|
| Hard-coded home and runtime UID | 3 |
|
||||||
|
| Service-name path components | 3 |
|
||||||
|
| Definition warning acknowledged before apply | 3 |
|
||||||
|
| Existing `.env` mode and symlink trust | 3 |
|
||||||
|
| Concurrent updater runs | 3 |
|
||||||
|
| Custom `PANAMA_PATH` update unit | 3 |
|
||||||
|
| Floating images with Podman socket access | 3 |
|
||||||
|
| Sidecar secret over-distribution | 3 |
|
||||||
|
| Inline SMTP placeholders outside `.env` | 3 |
|
||||||
|
| Multi-monitor capture mismatch | 4 |
|
||||||
|
| Dictation concurrent start and reusable PID | 4 |
|
||||||
|
| Stale Screen Intelligence callbacks | 4 |
|
||||||
|
| Permanent `pw-dump` polling | 4 |
|
||||||
|
| Global `mpvpaper` process cleanup | 4 |
|
||||||
|
| Non-atomic source/config rewrites | 4 |
|
||||||
|
| Mutable speech image and model | 4 |
|
||||||
|
| Capture filename collisions and synchronous frame load | 4 |
|
||||||
|
| Date-expiring agent-usage contract | 1 |
|
||||||
|
| Secret-scan prose false positive | 1 |
|
||||||
|
| False-green update contract | 1 |
|
||||||
|
| Incomplete safe-test classification | 1 |
|
||||||
|
| No runner timeout and hidden stderr | 1 |
|
||||||
|
| Contracts mutating tracked/live-linked paths | 1 |
|
||||||
|
| Contracts depending on real installed settings | 1 |
|
||||||
|
| Weak migration privilege policy test | 5 |
|
||||||
|
| Web-app Desktop Entry injection | 5 |
|
||||||
|
| Transcode output deletion race | 5 |
|
||||||
|
| Documentation drift | 5 |
|
||||||
|
|
||||||
|
## Out of scope
|
||||||
|
|
||||||
|
- Running the bootstrap on a real VPS.
|
||||||
|
- Applying firewalld rules to a real host.
|
||||||
|
- Restarting or migrating any existing server service.
|
||||||
|
- Activating a new Hyprland session or changing monitor state.
|
||||||
|
- Visual redesign of Settings, capture, notifications, or other shell surfaces.
|
||||||
|
- Replacing Podman, Quickshell, Hyprland, or the existing command vocabulary.
|
||||||
|
- Broad refactoring unrelated to an audited failure path.
|
||||||
|
|
||||||
|
## Completion criteria
|
||||||
|
|
||||||
|
The remediation is complete when every ledger row has a verified implementation. A row
|
||||||
|
may leave the ledger only when a failing behavioral test disproves the audit finding and
|
||||||
|
Gabriel approves that removal. The hermetic suite must be green with no hidden stderr;
|
||||||
|
no contract classified safe may touch live desktop, network, or privileged state;
|
||||||
|
generated documentation and configuration validators must pass; and an independent
|
||||||
|
final review must find no unresolved Critical or Important issue.
|
||||||
Reference in New Issue
Block a user