From 044139ed63ef34f490d302585318c6b50bf5fc4d Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Wed, 26 Aug 2026 21:11:25 -0400 Subject: [PATCH] Plan verification gate remediation --- ...026-08-26-verification-gate-remediation.md | 720 ++++++++++++++++++ ...-26-repository-audit-remediation-design.md | 14 +- 2 files changed, 729 insertions(+), 5 deletions(-) create mode 100644 docs/superpowers/plans/2026-08-26-verification-gate-remediation.md diff --git a/docs/superpowers/plans/2026-08-26-verification-gate-remediation.md b/docs/superpowers/plans/2026-08-26-verification-gate-remediation.md new file mode 100644 index 0000000..2835c0c --- /dev/null +++ b/docs/superpowers/plans/2026-08-26-verification-gate-remediation.md @@ -0,0 +1,720 @@ +# Verification Gate Remediation Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan. + +**Goal:** Make Panama's contract gate honest, safe by default when requested, diagnostic on failure, and capable of proving the later repository-audit fixes. + +**Architecture:** Replace the incomplete desktop-hijacking ledger with one explicit manifest covering every collected contract. `bin/panama` remains the public runner: it parses that manifest, applies capability policy, executes each selected contract under a bounded timeout, and preserves its diagnostics. Contracts that currently depend on the calendar, tracked files, the live settings store, or source-text inspection are changed to exercise disposable fixtures and real public commands. + +**Tech Stack:** Bash 5, Python 3 standard library, Git fixture repositories, existing Panama contract executables, Quickshell test harnesses. + +**Spec:** `docs/superpowers/specs/2026-08-26-repository-audit-remediation-design.md`, Package 1: Verification gate. + +## Global Constraints + +- Preserve the user's existing `config/bash/.bashrc` changes. Do not stage or edit that file. +- Do not run plain `panama test` during implementation. It is intentionally interactive once this plan lands and several entries manipulate the live desktop. +- Do not start or restart the production Quickshell, Hyprland, or system services. +- Use `apply_patch` for every repository edit. +- Test public behavior. Source inspection may enforce a narrow declarative invariant, but must not substitute for executing `bin/panama` or a helper. +- Keep every contract self-cleaning on success, failure, signal, and timeout. +- Commit after each task with only that task's files staged. + +--- + +## Task 1: Replace the desktop ledger with a complete contract manifest + +**Files:** + +- Create: `tests/contracts.manifest` +- Create: `tests/setup/contract-manifest-contract` +- Delete: `tests/setup/desktop-hijacking-contract` +- Delete: `tests/desktop-hijacking` +- Modify: `README.md` + +### Step 1: Write the failing manifest contract + +Create `tests/setup/contract-manifest-contract` as an executable Bash contract. It must independently discover contracts exactly as the runner does: + +```bash +while IFS= read -r path; do + [[ -x "$path" || "$path" == *_test.py ]] || continue + printf 'tests/%s\n' "${path#"$repo_dir/tests/"}" +done < <(find "$repo_dir/tests" -type f \ + -not -path '*/fixtures/*' -not -path '*__pycache__*' | sort) +``` + +Parse non-comment manifest lines as two whitespace-separated fields: + +```text + +``` + +Assert all of the following: + +- every discovered contract appears exactly once; +- every manifest path is discovered by the runner; +- paths are sorted lexicographically; +- `hermetic` appears alone; +- non-hermetic entries use only `live-host`, `live-compositor`, `live-desktop`, `network`, and `privileged`; +- every non-hermetic entry has a directly preceding comment explaining the external effect; +- no path or capability is duplicated on one line; +- the manifest contains at least one entry for each capability except `privileged`, which is supported but not currently required by a contract. + +Include a parser-fixture section in the same contract. Copy the manifest parser logic into a temporary malformed manifest for each rejection case (missing contract, stale path, duplicate path, unknown capability, `hermetic,network`, unsorted paths, and uncommented non-hermetic entry) and assert each fixture fails with a message naming the defect. + +Run: + +```bash +chmod +x tests/setup/contract-manifest-contract +tests/setup/contract-manifest-contract +``` + +Expected: FAIL because `tests/contracts.manifest` does not exist. + +### Step 2: Add the complete manifest + +Add one line for each contract discovered by the command in Step 1. Start every path not named below as `hermetic`. Apply this audited non-hermetic classification exactly: + +| Capabilities | Contract | +|---|---| +| `live-compositor,live-desktop` | `tests/quickshell/activity-indicator-contract` | +| `live-desktop` | `tests/quickshell/activity-state-contract` | +| `live-host` | `tests/quickshell/adwaita-accent-contract` | +| `live-host` | `tests/quickshell/application-volume-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/calendar-agenda-contract` | +| `live-host` | `tests/quickshell/calendar-agenda-helper-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/cheatsheet-contract` | +| `live-host` | `tests/quickshell/connectivity-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/control-center-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/control-center-services-contract` | +| `live-desktop` | `tests/quickshell/default-apps-roles-contract` | +| `live-host` | `tests/quickshell/default-apps-family-contract` | +| `live-desktop` | `tests/quickshell/display-arrangement-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/displays-contract` | +| `live-host` | `tests/quickshell/disks-contract` | +| `live-desktop` | `tests/quickshell/dock-position-contract` | +| `live-compositor` | `tests/quickshell/enum-hypr-map-contract` | +| `network` | `tests/setup/extras-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/focus-session-contract` | +| `live-desktop` | `tests/quickshell/focus-session-expiry` | +| `live-desktop` | `tests/quickshell/focus-session-restart` | +| `live-host` | `tests/quickshell/firewall-contract` | +| `live-host` | `tests/quickshell/gaming-contract` | +| `live-desktop` | `tests/quickshell/health-ui-contract` | +| `live-compositor` | `tests/hypr/keybind-categories-contract` | +| `live-compositor` | `tests/quickshell/keybind-rebind-contract` | +| `live-compositor` | `tests/quickshell/keybinds-contract` | +| `network` | `tests/quickshell/home-assistant-helper-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/my-home-settings-contract` | +| `live-host` | `tests/quickshell/overview-window-actions-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/overview-live-actions` | +| `live-compositor,live-desktop` | `tests/quickshell/overview-search-contract` | +| `live-desktop` | `tests/quickshell/panama-action-ipc-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/phone-page-contract` | +| `live-host` | `tests/quickshell/polkit-agent-contract` | +| `live-host` | `tests/quickshell/printers-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/scratchpad-shelf-contract` | +| `live-compositor` | `tests/quickshell/schema-hypr-shape-contract` | +| `live-desktop` | `tests/quickshell/screen-intelligence-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/settings-hyprland-write-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/settings-pages-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/settings-system-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/settings-window-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/settings-write-sweep-contract` | +| `live-host` | `tests/quickshell/sharing-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/signal-glass-contract` | +| `live-host` | `tests/quickshell/snapshots-contract` | +| `live-host` | `tests/quickshell/sound-page-contract` | +| `live-host` | `tests/quickshell/ssh-keys-contract` | +| `live-desktop` | `tests/quickshell/status-events-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/switcher-contract` | +| `live-host` | `tests/quickshell/updates-contract` | +| `live-host` | `tests/quickshell/user-accounts-contract` | +| `live-host` | `tests/setup/hardware-predicates-contract` | +| `live-compositor,live-desktop` | `tests/quickshell/welcome-contract` | + +For each non-hermetic line, move the useful explanation from `tests/desktop-hijacking` directly above the entry. Add concise comments for the newly discovered entries describing the exact network, compositor-read, or window-mapping behavior. + +Run: + +```bash +tests/setup/contract-manifest-contract +``` + +Expected: PASS with the discovered and manifested counts equal. + +### Step 3: Remove the old ledger and update the documented count + +Delete `tests/desktop-hijacking` and `tests/setup/desktop-hijacking-contract`. Update the exact contract count in `README.md`; removing one executable and adding one executable keeps the current count at 185 at this point. + +Run: + +```bash +tests/setup/readme-contract +git diff --check +``` + +Expected: both PASS. + +### Step 4: Commit + +```bash +git add tests/contracts.manifest tests/setup/contract-manifest-contract \ + tests/setup/desktop-hijacking-contract tests/desktop-hijacking README.md +git commit -m "Test: Classify every contract capability" +``` + +--- + +## Task 2: Make `panama test` enforce the manifest and preserve diagnostics + +**Files:** + +- Create: `tests/setup/test-runner-contract` +- Modify: `bin/panama` +- Modify: `tests/contracts.manifest` +- Modify: `README.md` + +### Step 1: Write a public runner contract + +Create `tests/setup/test-runner-contract`. Build a temporary repository containing a copy of `bin/panama`, a minimal `tests/contracts.manifest`, and executable fixture contracts named `pass-contract`, `fail-contract`, `stderr-contract`, `hang-contract`, `host-contract`, `desktop-contract`, and `network-contract`. Initialize it as a Git repository so the copied CLI behaves like the real installation. + +The fixtures must record executions beneath the temporary directory and produce these behaviors: + +```bash +# pass-contract +printf 'pass stdout\n' + +# fail-contract +printf 'failure stdout\n' +printf 'failure stderr\n' >&2 +exit 7 + +# stderr-contract +printf 'warning on success\n' >&2 + +# hang-contract +trap 'printf terminated >"$PANAMA_TEST_FIXTURE/terminated"; exit 124' TERM +while :; do sleep 1; done +``` + +Assert the copied `panama` executable provides these public behaviors: + +1. `panama test --safe` runs only `hermetic` fixtures and reports each skipped capability count, including `live-host`. +2. `panama test desktop` in a non-TTY fails without running the fixture and tells automation to pass `--allow live-desktop`. +3. `panama test --allow live-desktop desktop` runs it without a prompt. +4. Multiple `--allow` flags are repeatable and capability-specific; allowing desktop does not allow network. +5. An unknown flag, a second pattern, an unknown capability, and `--safe --allow live-desktop` are usage errors. +6. `PANAMA_TEST_TIMEOUT_SECONDS=1 panama test hang` terminates the fixture, reports a timeout, and exits nonzero. +7. A failed contract prints both captured stdout and captured stderr. +8. A successful contract with stderr prints a warning and the captured stderr. +9. Successful stdout stays hidden to keep the normal run scannable. +10. A pattern matching only skipped contracts is a distinct error from no pattern match. +11. Capture files are removed after success and failure. +12. `panama contracts ` labels hits with all manifest capabilities. + +Run: + +```bash +chmod +x tests/setup/test-runner-contract +tests/setup/test-runner-contract +``` + +Expected: FAIL against the current runner at the first manifest-policy assertion. + +### Step 2: Replace ledger parsing with manifest parsing + +In `bin/panama`, replace `DESKTOP_HIJACKING_LEDGER` and `hijacking_entries` with: + +```bash +CONTRACT_MANIFEST="tests/contracts.manifest" +CONTRACT_CAPABILITIES=(hermetic live-host live-compositor live-desktop network privileged) + +contract_manifest_entries() { + local line capabilities path + while IFS= read -r line || [[ -n "$line" ]]; do + line="${line%%#*}" + read -r capabilities path _ <<<"$line" + [[ -n "${capabilities:-}" && -n "${path:-}" ]] || continue + printf '%s\t%s\n' "$path" "$capabilities" + done < "$PANAMA_DIR/$CONTRACT_MANIFEST" +} +``` + +Do not make a missing manifest mean “everything is safe.” `cmd_test` and `cmd_contracts` must fail clearly if the file cannot be read. The manifest contract owns deeper format validation; the CLI owns the runtime read failure. + +### Step 3: Implement argument and capability policy + +Parse position-independent arguments with one optional pattern and repeatable `--allow `. Apply these rules: + +- `--safe` means only `hermetic` entries; +- `--safe` and any `--allow` together are a usage error; +- `--allow hermetic` is a usage error because hermetic contracts need no grant; +- plain `panama test` selects all matching manifest entries; +- selected non-hermetic capabilities missing from `--allow` require confirmation only when stdin and stderr are TTYs; +- non-TTY execution fails before running anything and names every missing capability; +- the prompt lists selected contract count and each external capability; default is no; +- there is no `--allow-all` path. + +Use associative arrays for selected grants, manifest capabilities, and skipped counts so ordering stays deterministic. + +### Step 4: Bound execution and retain output + +At the beginning of `cmd_test`, validate: + +```bash +local timeout_seconds="${PANAMA_TEST_TIMEOUT_SECONDS:-180}" +[[ "$timeout_seconds" =~ ^[1-9][0-9]*$ ]] || { + err 'PANAMA_TEST_TIMEOUT_SECONDS must be a positive integer.' + return 2 +} +``` + +Run the implementation body in a subshell, create one capture directory with `mktemp -d`, and trap its removal on `EXIT`, `INT`, and `TERM` inside that subshell. This keeps cleanup reliable without leaking or overwriting traps in the parent CLI process. For each contract, run either `python3 path` or the executable through: + +```bash +timeout --signal=TERM --kill-after=5 "$timeout_seconds" \ + "${runner[@]}" >"$stdout_file" 2>"$stderr_file" +``` + +Capture the exit status explicitly instead of relying on `set -e`. Treat status 124 or 137 as timeout. On failure, print a labeled stdout section when nonempty and a labeled stderr section when nonempty. On success, suppress stdout; if stderr is nonempty, call `warn` and print it. Continue through the selected suite and return nonzero if any contract failed or timed out. + +### Step 5: Update `panama contracts` + +Load the same manifest mapping and render labels such as: + +```text +tests/quickshell/settings-pages-contract [live-compositor,live-desktop] +tests/setup/readme-contract [hermetic] +``` + +The grep-based relationship search remains unchanged. Its capability label must come only from the manifest. + +### Step 6: Make the tests pass and update the count + +Add `hermetic tests/setup/test-runner-contract` to `tests/contracts.manifest`. Update the README count from 185 to 186. + +Run: + +```bash +tests/setup/contract-manifest-contract +tests/setup/test-runner-contract +tests/setup/readme-contract +./bin/panama test --safe test-runner +``` + +Expected: all PASS. The final command reports one passing contract and does not request permission. + +### Step 7: Commit + +```bash +git add bin/panama tests/contracts.manifest tests/setup/test-runner-contract README.md +git commit -m "Fix: Make contract execution safe and diagnostic" +``` + +--- + +## Task 3: Remove the calendar-pinned agent usage failure + +**Files:** + +- Modify: `tests/quickshell/agent-usage-contract` + +### Step 1: Prove the current fixture is date-dependent + +Run: + +```bash +tests/quickshell/agent-usage-contract +``` + +Expected before the change: FAIL on `todayTotalTokens` when the current day is not 2026-08-25. + +### Step 2: Generate the session path and timestamps dynamically + +Replace the fixed `2026/08/25` directory and timestamps with local-day fixture values, matching the collector's `datetime.now()` and `astimezone()` behavior: + +```bash +session_day="$(date +%Y/%m/%d)" +session_date="$(date +%Y-%m-%d)" +session_offset="$(date +%:z)" +mkdir -p "$work/codex/sessions/$session_day" + +jq -nc --arg timestamp "${session_date}T10:00:00${session_offset}" \ + '{type:"token_count",timestamp:$timestamp,payload:{type:"token_count",info:{total_token_usage:{input_tokens:999999,output_tokens:999999},last_token_usage:{input_tokens:1200,cached_input_tokens:1000,output_tokens:300}}}}' +``` + +Write two records at local `10:00:00` and `10:05:00` with `session_offset`, preserving the existing expectation of 3,000 last-turn tokens. Do not add a production clock override: only the fixture was wrong. + +### Step 3: Verify and commit + +Run: + +```bash +tests/quickshell/agent-usage-contract +./bin/panama test --safe agent-usage +``` + +Expected: both PASS with `todayTotalTokens == 3000`. + +```bash +git add tests/quickshell/agent-usage-contract +git commit -m "Test: Make agent usage fixtures date independent" +``` + +--- + +## Task 4: Replace regex secret scanning with semantic fixtures + +**Files:** + +- Create: `tests/server/scan-tracked-secrets.py` +- Create: `tests/server/fixtures/secrets/clean/compose.yml` +- Create: `tests/server/fixtures/secrets/clean/.env.example` +- Create: `tests/server/fixtures/secrets/clean/README.md` +- Create: `tests/server/fixtures/secrets/leaked/compose.yml` +- Create: `tests/server/fixtures/secrets/leaked/.env.example` +- Modify: `tests/server/compose-secrets-contract` + +### Step 1: Add false-positive and true-positive fixtures + +The clean fixture must include: + +- Compose interpolation such as `POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}`; +- `CHANGE_ME`, empty values, and boolean switches in `.env.example`; +- prose containing `password: example`, `secret key`, and the current server README sentence that triggered the audit. + +The leaked fixture must include: + +- a literal YAML credential `POSTGRES_PASSWORD: fixture-should-be-rejected`; +- a literal env credential `API_TOKEN=fixture-should-be-rejected`. + +Use intentionally invalid fixture strings, not realistic provider token formats. + +### Step 2: Write the scanner with only the Python standard library + +`tests/server/scan-tracked-secrets.py` takes a root directory followed by tracked paths on argv. It must: + +- parse `.env` and `.env.example` lines as key/value records; +- parse YAML Compose files by indentation-aware `KEY: VALUE` / `- KEY=VALUE` environment entries and top-level secret-bearing scalar assignments; +- treat `${VAR}`, `${VAR:-default}`, empty strings, `CHANGE_ME`, and booleans as non-secret; +- ignore keys ending `_FILE`, `_PATH`, `_NAME`, or `_KEY_NAME`; +- scan all text file types only for PEM private-key headers and known provider-token signatures; +- never interpret Markdown credential-shaped prose as a YAML assignment; +- print `path:line: key` for semantic leaks and return 1 when any are found. + +Keep the parser deliberately scoped to Compose and env syntax; do not add a general YAML dependency that the installer does not provide. + +### Step 3: Make the contract prove both directions + +Before scanning the real tracked `server/` paths, have `tests/server/compose-secrets-contract` call the scanner on the clean fixture and require success, then on each leaked fixture and require failure with the expected key named. Finally pass the actual paths from: + +```bash +git -C "$repo_dir" ls-files 'server/**' 'server/*' +``` + +Keep the existing `.gitignore` and tracked-`.env` assertions. + +Run: + +```bash +tests/server/compose-secrets-contract +``` + +Expected: PASS; the README prose is accepted while both literal fixture secrets are rejected. + +### Step 4: Commit + +```bash +git add tests/server/scan-tracked-secrets.py tests/server/fixtures/secrets \ + tests/server/compose-secrets-contract +git commit -m "Test: Scan compose secrets by data shape" +``` + +--- + +## Task 5: Make the update contract execute the real CLI + +**Files:** + +- Modify: `tests/setup/update-command-contract` + +### Step 1: Replace the source-body assertions with a failing CLI fixture + +Keep the existing `install --upgrade` stage and package-hash assertions, but replace the `sed`/`grep` inspection of `cmd_update` and `cmd_sync` with disposable Git repositories: + +1. create a bare `origin.git`; +2. create an `upstream` clone with a copied `bin/panama` and a stub executable `install`; +3. push the initial branch; +4. clone it to `machine`; +5. append an upstream commit; +6. run `machine/bin/panama update` with `PANAMA_UPDATE_FIXTURE_LOG` consumed by the copied stub installer. + +The installer stub must record its argv and optionally fail according to `PANAMA_UPDATE_INSTALL_RC`. + +Add assertions that the real CLI: + +- fast-forwards a clean machine clone to the new upstream commit; +- invokes the fixture installer with `--upgrade`; +- returns the installer's nonzero status; +- leaves `panama sync` separate from the installer path; +- on a dirty-tree stash-pop conflict, leaves no conflict markers and preserves a recoverable stash. + +Do not yet assert that installation happens after WIP restoration. Package 3 of the approved design changes that ordering and will extend this same executable fixture with the new failing assertion before changing production code. + +### Step 2: Repair status propagation in the contract harness + +Change `run_install` so it returns the installer's status rather than `cat`'s status: + +```bash +local status=0 +PATH="$root/shim:$PATH" PANAMA_PATH="$root" PANAMA_RAN="$root/ran" \ + XDG_STATE_HOME="$root/state" bash "$root/install" "$@" \ + >"$root/out" 2>&1 || status=$? +cat "$root/ran" +return "$status" +``` + +Replace the indented-assignment parser with a tolerant anchored expression: + +```python +match = re.match(r'^\s*STAGES=\((.*)\)\s*$', line) +``` + +Fail explicitly when the assignment is not found. Do not run parser code in process substitution whose exit status is ignored. + +### Step 3: Verify and commit + +Run: + +```bash +tests/setup/update-command-contract +./bin/panama test --safe update-command +``` + +Expected: both PASS and the fixture log proves `bin/panama update` actually ran. + +```bash +git add tests/setup/update-command-contract +git commit -m "Test: Exercise updates through the real command" +``` + +--- + +## Task 6: Stop contracts from mutating tracked files or reading live preferences + +**Files:** + +- Modify: `config/dot/quickshell/scripts/panama-settings-docs` +- Modify: `tests/quickshell/settings-docs-contract` +- Modify: `tests/quickshell/settings-sync-contract` + +### Step 1: Add a failing output-path contract for generated settings docs + +Extend `tests/quickshell/settings-docs-contract` to copy the committed document to a temporary path, append drift to the copy, and run: + +```bash +"$generator" --check --output "$scratch/settings.md" +``` + +Capture `git diff -- docs/settings.md` before and after the contract and require byte-for-byte equality. Run the contract now. + +Expected: FAIL because the generator does not accept `--output` and the current test still edits the tracked document. + +### Step 2: Add a real output seam to the generator + +Add: + +```python +parser.add_argument("--output", type=pathlib.Path, default=OUTPUT) +``` + +Resolve relative explicit paths against the current working directory, use that path for write/check behavior, and keep the existing default unchanged. `--stdout` must remain mutually exclusive with writing but may coexist with no explicit output. + +Update the contract so the stale-copy check never writes `docs/settings.md`. Its trap should only remove the temporary directory. + +Run: + +```bash +tests/quickshell/settings-docs-contract +git diff --exit-code -- docs/settings.md +``` + +Expected: PASS and no diff. + +### Step 3: Seed settings-sync from a fixture instead of the live settings store + +In `tests/quickshell/settings-sync-contract`, set `XDG_CONFIG_HOME="$work/source-config"` before the first export and create a representative `panama/settings.json` there from schema-valid values. Include at least: + +- one boolean; +- one integer; +- one numeric enum; +- one string; +- one setting omitted from the import bundle to prove merge semantics. + +Remove every read of `${XDG_CONFIG_HOME:-$HOME/.config}/panama/settings.json` that occurs before the temporary home is established. Keep the allow-list completeness assertion, but compare against the explicit fixture rather than the user's preferences. + +Run: + +```bash +tests/quickshell/settings-sync-contract +``` + +Expected: PASS without reading or writing the real settings store. + +### Step 4: Commit + +```bash +git add config/dot/quickshell/scripts/panama-settings-docs \ + tests/quickshell/settings-docs-contract tests/quickshell/settings-sync-contract +git commit -m "Test: Isolate generated docs and settings fixtures" +``` + +--- + +## Task 7: Isolate the dock geometry contract + +**Files:** + +- Modify: `tests/quickshell/dock-position-contract` + +### Step 1: Write the safety assertions before changing the harness + +At contract start, record whether `config/dot/quickshell/dock-position-probe.qml` exists and its checksum if present. At every exit, assert the source tree matches that initial state. Also fail if the contract reads `${HOME}/.config/panama/settings.json`. + +Run: + +```bash +tests/quickshell/dock-position-contract +``` + +Expected: FAIL because the contract creates its probe inside the tracked QML tree and reads live settings. + +### Step 2: Copy the QML tree and seed deterministic settings + +After creating `work`, copy the Quickshell tree to a fixture root: + +```bash +fixture_shell="$work/quickshell" +cp -a "$shell_dir/." "$fixture_shell/" +probe="$fixture_shell/dock-position-probe.qml" +``` + +Write the probe only to `$probe`. Seed `$work/config/panama/settings.json` with the schema defaults needed by the dock plus the position under test; do not copy the user's settings. Run each `qs -p` invocation from `$fixture_shell` with `XDG_CONFIG_HOME="$work/config"`. + +The contract still maps isolated panel surfaces into the current Wayland session. Keep its manifest capability as `live-desktop`: moving its files and settings into temporary storage removes mutation risk but does not make the visible surfaces hermetic. + +### Step 3: Verify isolation under an explicit desktop grant + +Run: + +```bash +tests/quickshell/dock-position-contract +tests/setup/contract-manifest-contract +./bin/panama test --allow live-desktop dock-position +``` + +Expected: all PASS, the source-tree checksum is unchanged, and the manifest entry remains `live-desktop`. + +### Step 4: Commit + +```bash +git add tests/quickshell/dock-position-contract +git commit -m "Test: Isolate dock geometry fixtures" +``` + +--- + +## Task 8: Update operator documentation and run the Package 1 gate + +**Files:** + +- Modify: `README.md` +- Modify: `.claude/skills/panama/SKILL.md` +- Modify: `skills/panama-desktop/SKILL.md` +- Modify: `bin/panama` + +### Step 1: Update the public command documentation + +Document: + +```text +panama test --safe +panama test --allow live-host updates +panama test --allow live-compositor keybinds +PANAMA_TEST_TIMEOUT_SECONDS=300 panama test --safe +``` + +State that: + +- `tests/contracts.manifest` classifies every contract; +- `--safe` means hermetic only; +- plain full runs prompt in a terminal before any non-hermetic contract; +- automation must grant each required capability with repeatable `--allow`; +- failures print captured stdout/stderr and every contract has a default 180-second outer timeout. + +Remove current claims that `--safe` is defined by `tests/desktop-hijacking`. Update `bin/panama`'s top comment, usage text, `cmd_test` comments, and `cmd_contracts` comments to match behavior. Leave historical design specs unchanged. + +### Step 2: Run focused verification + +```bash +bash -n bin/panama \ + tests/setup/contract-manifest-contract \ + tests/setup/test-runner-contract \ + tests/setup/update-command-contract \ + tests/quickshell/agent-usage-contract \ + tests/quickshell/settings-docs-contract \ + tests/quickshell/settings-sync-contract \ + tests/server/compose-secrets-contract +python3 -m py_compile \ + config/dot/quickshell/scripts/panama-settings-docs \ + tests/server/scan-tracked-secrets.py +tests/setup/contract-manifest-contract +tests/setup/test-runner-contract +tests/setup/update-command-contract +tests/quickshell/agent-usage-contract +tests/quickshell/settings-docs-contract +tests/quickshell/settings-sync-contract +tests/server/compose-secrets-contract +tests/setup/readme-contract +git diff --check +``` + +Expected: every command exits 0. + +### Step 3: Run the complete hermetic gate + +```bash +./bin/panama test --safe +``` + +Expected: all selected hermetic contracts pass; the summary reports skipped counts for `live-host`, `live-compositor`, `live-desktop`, and `network`; no confirmation appears; no production shell or service is restarted. + +If a manifest-labeled hermetic contract reaches the network, live compositor, live settings, root prompt, or tracked-file write, stop and reclassify or isolate it before continuing. Do not grant a capability merely to make this gate green. + +### Step 4: Confirm worktree scope + +```bash +git status --short +git diff -- config/bash/.bashrc +``` + +Expected: the pre-existing `.bashrc` modification remains unstaged and unchanged from its pre-plan state; only Package 1 files are staged or committed. + +### Step 5: Commit + +```bash +git add README.md .claude/skills/panama/SKILL.md skills/panama-desktop/SKILL.md bin/panama +git commit -m "Docs: Explain contract capability gates" +``` + +### Step 6: Record the package handoff + +Capture these facts in the implementation summary before beginning Package 2: + +- final hermetic pass/fail/skip counts; +- every non-hermetic capability (`live-host`, `live-compositor`, `live-desktop`, `network`, and `privileged`) and its contract count; +- focused verification commands and exit codes; +- confirmation that `config/bash/.bashrc` stayed out of all commits; +- any contract retained as non-hermetic after an attempted isolation, with the exact reason. diff --git a/docs/superpowers/specs/2026-08-26-repository-audit-remediation-design.md b/docs/superpowers/specs/2026-08-26-repository-audit-remediation-design.md index 276c8ed..41bbf01 100644 --- a/docs/superpowers/specs/2026-08-26-repository-audit-remediation-design.md +++ b/docs/superpowers/specs/2026-08-26-repository-audit-remediation-design.md @@ -50,6 +50,7 @@ comments: ```text hermetic tests/setup/boot-contract +live-host tests/quickshell/updates-contract live-compositor tests/hypr/keybind-categories-contract live-desktop tests/quickshell/settings-pages-contract network tests/quickshell/home-assistant-helper-contract @@ -59,6 +60,7 @@ privileged tests/setup/root-server-bootstrap-contract The vocabulary is deliberately small: - `hermetic`: temporary state and stubbed system commands only. +- `live-host`: reads the real machine or session without changing it or contacting a non-fixture endpoint. - `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. @@ -69,7 +71,7 @@ Capabilities may be combined. `panama test --safe` runs only `hermetic` contract `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." +`--allow live-host --allow live-compositor`; 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 @@ -424,9 +426,10 @@ Final repository verification includes the complete hermetic suite, Hyprland con 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. +Non-hermetic checks are separate, explicitly granted gates after all hermetic work is +green. `live-host` remains read-only; compositor, desktop, and network checks receive +only their named grants. Server cutover, service restarts, SSH reload, firewall mutation, +and production deployment are not part of this implementation branch. ## Audit finding ledger @@ -493,6 +496,7 @@ This table prevents a smaller issue from disappearing behind the larger repairs. 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; +no contract classified safe may read live host/compositor state or 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.