Add sprint 04 validation docs
Authored by
mfwolffe <wolffemf@dukes.jmu.edu>
- SHA
649608aaf987695e8d49b9e73ff384d5f4729dd1- Parents
-
1b09a6f - Tree
34f9154
649608a
649608aaf987695e8d49b9e73ff384d5f4729dd11b09a6f
34f9154| Status | File | + | - |
|---|---|---|---|
| M |
README.md
|
32 | 0 |
| A |
RELEASE_NOTES.md
|
26 | 0 |
| A |
examples/sprint-04-validation-report-2026-02-20.md
|
27 | 0 |
| A |
examples/sprint-04-validation.md
|
48 | 0 |
| A |
examples/validate-sprint-04.sh
|
109 | 0 |
README.mdmodified@@ -12,6 +12,15 @@ | |||
| 12 | 2. `cargo run -p garcardctl -- status` | 12 | 2. `cargo run -p garcardctl -- status` |
| 13 | 3. `cargo run -p garcard -- prompt --mode secret --message "Validation prompt"` | 13 | 3. `cargo run -p garcard -- prompt --mode secret --message "Validation prompt"` |
| 14 | 14 | ||
| 15 | +## User Service | ||
| 16 | +1. Install unit file: | ||
| 17 | + - `install -Dm644 garcard.service ~/.config/systemd/user/garcard.service` | ||
| 18 | +2. Enable and start: | ||
| 19 | + - `systemctl --user daemon-reload` | ||
| 20 | + - `systemctl --user enable --now garcard` | ||
| 21 | +3. Check health: | ||
| 22 | + - `cargo run -q -p garcardctl -- status` | ||
| 23 | + | ||
| 15 | ## Config | 24 | ## Config |
| 16 | Default config path: `~/.config/garcard/config.toml` | 25 | Default config path: `~/.config/garcard/config.toml` |
| 17 | 26 | ||
@@ -34,3 +43,26 @@ See `examples/config.toml` for a minimal local starter file. | |||
| 34 | `GARCARD_PROMPT_COMMAND` is optional. If unset, `garcard` runs the built-in | 43 | `GARCARD_PROMPT_COMMAND` is optional. If unset, `garcard` runs the built-in |
| 35 | `garcard prompt` gartk dialog path and falls back to `systemd-ask-password` | 44 | `garcard prompt` gartk dialog path and falls back to `systemd-ask-password` |
| 36 | when the X11 prompt backend is unavailable. | 45 | when the X11 prompt backend is unavailable. |
| 46 | + | ||
| 47 | +## Validation Docs | ||
| 48 | +1. `examples/sprint-02-validation.md` | ||
| 49 | +2. `examples/sprint-03-validation-report-2026-02-18.md` | ||
| 50 | +3. `examples/sprint-04-validation.md` | ||
| 51 | +4. `examples/validate-sprint-02.sh` | ||
| 52 | +5. `examples/validate-sprint-03-integration.sh` | ||
| 53 | +6. `examples/validate-sprint-04.sh` | ||
| 54 | + | ||
| 55 | +## Troubleshooting | ||
| 56 | +1. `Authorization requires authentication but no agent is available` | ||
| 57 | + - ensure daemon is running: `cargo run -q -p garcardctl -- ping` | ||
| 58 | + - restart daemon after polkit restart: `cargo run -q -p garcardctl -- quit` then relaunch | ||
| 59 | +2. `failed to connect to garcard daemon ...` | ||
| 60 | + - check socket path from `garcardctl status` | ||
| 61 | + - if using custom socket, export the same `GARCARD_SOCKET` for both daemon and ctl | ||
| 62 | +3. Prompt did not open in X11 | ||
| 63 | + - run with debug logs: `RUST_LOG=garcard=debug cargo run -p garcard -- daemon` | ||
| 64 | + - verify fallback path by setting `GARCARD_PROMPT_COMMAND` explicitly | ||
| 65 | + | ||
| 66 | +## Known Limitations | ||
| 67 | +1. Policy results are host-specific; some actions may auto-authorize and not trigger prompts. | ||
| 68 | +2. Current implementation targets logged-in user sessions on X11. | ||
RELEASE_NOTES.mdadded@@ -0,0 +1,26 @@ | |||
| 1 | +# garcard 0.1.0-rc1 | ||
| 2 | + | ||
| 3 | +## Highlights | ||
| 4 | +1. Polkit authentication agent backend with queue-aware auth state tracking. | ||
| 5 | +2. Built-in gartk prompt path with timeout/cancel behavior and ask-password fallback. | ||
| 6 | +3. Daemon health/reconnect loop with forced reconnect support (`SIGHUP` + maintenance pass). | ||
| 7 | +4. `garcardctl` operational commands: `ping`, `status`, `version`, `auth-summary`, `quit`. | ||
| 8 | + | ||
| 9 | +## Hardening Included In Sprint 04 | ||
| 10 | +1. Same-UID enforcement for local IPC control clients. | ||
| 11 | +2. Reduced panic surface in prompt color setup paths. | ||
| 12 | +3. Best-effort scrubbing of helper prompt response buffers after use. | ||
| 13 | + | ||
| 14 | +## Validation Coverage | ||
| 15 | +1. Sprint 02 live callback and reconnect validation: | ||
| 16 | + - `examples/sprint-02-validation-report-2026-02-18.md` | ||
| 17 | +2. Sprint 03 ecosystem + runtime probes: | ||
| 18 | + - `examples/sprint-03-validation-report-2026-02-18.md` | ||
| 19 | +3. Sprint 04 reliability harness/checklist: | ||
| 20 | + - `examples/validate-sprint-04.sh` | ||
| 21 | + - `examples/sprint-04-validation.md` | ||
| 22 | + | ||
| 23 | +## Known Limitations | ||
| 24 | +1. Challenge prompting depends on host polkit policy; some actions may auto-authorize. | ||
| 25 | +2. Scope is logged-in user sessions (X11), not greeter/session-manager flows. | ||
| 26 | +3. Full panel controls in `gargears` remain limited to discovery/visibility for now. | ||
examples/sprint-04-validation-report-2026-02-20.mdadded@@ -0,0 +1,27 @@ | |||
| 1 | +# Sprint 04 Validation Report (2026-02-20) | ||
| 2 | + | ||
| 3 | +## Scope | ||
| 4 | +1. Hardening regression checks after Sprint 04 code changes. | ||
| 5 | +2. Automated reliability checks for daemon restart resilience. | ||
| 6 | + | ||
| 7 | +## Commands | ||
| 8 | +1. `cargo test --workspace` | ||
| 9 | +2. `./examples/validate-sprint-04.sh` (executed with default `stub` backend) | ||
| 10 | + | ||
| 11 | +## Results | ||
| 12 | +1. Workspace tests passed (`39` garcard tests + workspace crates). | ||
| 13 | +2. `validate-sprint-04.sh` passed baseline and restart loop checks: | ||
| 14 | + - daemon reachable via `ping`/`status` | ||
| 15 | + - restart loop completed (`3` stop/start iterations) | ||
| 16 | + - post-restart status and auth summary remained healthy (`idle`) | ||
| 17 | +3. Optional interactive `pkcheck` loop was intentionally skipped in this run: | ||
| 18 | + - requires live polkit challenge flow and operator interaction. | ||
| 19 | + | ||
| 20 | +## Hardening Outcomes Confirmed | ||
| 21 | +1. IPC control path now validates same-UID peer credentials. | ||
| 22 | +2. Prompt UI runtime path no longer relies on panic/`expect` for color parsing. | ||
| 23 | +3. Helper response buffers are scrubbed after sending to helper socket. | ||
| 24 | + | ||
| 25 | +## Remaining Manual Sprint 04 Checks | ||
| 26 | +1. Daemon restart during an active prompt in polkit mode. | ||
| 27 | +2. Session shutdown/logout race while prompt is active. | ||
examples/sprint-04-validation.mdadded@@ -0,0 +1,48 @@ | |||
| 1 | +# Sprint 04 Validation Checklist | ||
| 2 | + | ||
| 3 | +Run these checks from an active X11 user session. | ||
| 4 | + | ||
| 5 | +## Automated Baseline | ||
| 6 | +1. `cargo test --workspace` | ||
| 7 | +2. `./examples/validate-sprint-04.sh` | ||
| 8 | + | ||
| 9 | +Expected: | ||
| 10 | +1. All tests pass. | ||
| 11 | +2. Daemon survives restart loop and remains reachable over IPC. | ||
| 12 | + | ||
| 13 | +## Interactive Challenge Loop | ||
| 14 | +1. `GARCARD_SPRINT04_BACKEND=polkit ./examples/validate-sprint-04.sh` | ||
| 15 | +2. Complete two `pkcheck` prompts (cancel/deny/success combinations). | ||
| 16 | + | ||
| 17 | +Expected: | ||
| 18 | +1. Prompt appears for challenge actions. | ||
| 19 | +2. `garcardctl auth-summary` updates and remains responsive across iterations. | ||
| 20 | + | ||
| 21 | +## Daemon Restart During Active Prompt | ||
| 22 | +1. Start daemon in one terminal: | ||
| 23 | + - `RUST_LOG=garcard=debug GARCARD_AGENT_BACKEND=polkit cargo run -p garcard -- daemon` | ||
| 24 | +2. Trigger challenge in another terminal: | ||
| 25 | + - `pkcheck --allow-user-interaction --process $$ --action-id com.mesonbuild.install.run` | ||
| 26 | +3. While prompt is visible, restart daemon: | ||
| 27 | + - `cargo run -q -p garcardctl -- quit` | ||
| 28 | + - relaunch daemon command from step 1. | ||
| 29 | +4. Re-run the same `pkcheck` command. | ||
| 30 | + | ||
| 31 | +Expected: | ||
| 32 | +1. Active prompt interruption does not wedge daemon state. | ||
| 33 | +2. Relaunched daemon accepts new requests with clean `auth-summary`. | ||
| 34 | + | ||
| 35 | +## Session Shutdown/Logout Race | ||
| 36 | +1. Start daemon with debug logs. | ||
| 37 | +2. Trigger an auth prompt. | ||
| 38 | +3. Send `SIGTERM` to daemon PID while request is active. | ||
| 39 | +4. Relaunch daemon and run `garcardctl status`. | ||
| 40 | + | ||
| 41 | +Expected: | ||
| 42 | +1. Daemon exits cleanly without stale socket. | ||
| 43 | +2. Relaunch succeeds without manual socket cleanup. | ||
| 44 | + | ||
| 45 | +## Security Spot Checks | ||
| 46 | +1. Verify secret response handling does not log plaintext values. | ||
| 47 | +2. Confirm IPC control socket mode remains owner-only in production (`600`). | ||
| 48 | +3. Validate only same-UID peers can control daemon IPC. | ||
examples/validate-sprint-04.shadded@@ -0,0 +1,109 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +set -euo pipefail | ||
| 3 | + | ||
| 4 | +SOCKET_PATH="${GARCARD_SPRINT04_SOCKET:-${PWD}/target/garcard-sprint04.sock}" | ||
| 5 | +BACKEND="${GARCARD_SPRINT04_BACKEND:-stub}" | ||
| 6 | +RESTART_LOOPS="${GARCARD_SPRINT04_RESTART_LOOPS:-3}" | ||
| 7 | +PKCHECK_LOOPS="${GARCARD_SPRINT04_PKCHECK_LOOPS:-2}" | ||
| 8 | +ACTION_ID="${GARCARD_SPRINT04_ACTION_ID:-com.mesonbuild.install.run}" | ||
| 9 | +LOG_FILE="${GARCARD_SPRINT04_LOG:-${PWD}/target/garcard-sprint04.log}" | ||
| 10 | + | ||
| 11 | +if command -v garcard >/dev/null 2>&1; then | ||
| 12 | + DAEMON_CMD=(garcard daemon) | ||
| 13 | +else | ||
| 14 | + DAEMON_CMD=(cargo run -q -p garcard -- daemon) | ||
| 15 | +fi | ||
| 16 | + | ||
| 17 | +if command -v garcardctl >/dev/null 2>&1; then | ||
| 18 | + CTL_CMD=(garcardctl) | ||
| 19 | +else | ||
| 20 | + CTL_CMD=(cargo run -q -p garcardctl --) | ||
| 21 | +fi | ||
| 22 | + | ||
| 23 | +DAEMON_PID=0 | ||
| 24 | + | ||
| 25 | +run_ctl() { | ||
| 26 | + GARCARD_SOCKET="${SOCKET_PATH}" "${CTL_CMD[@]}" "$@" | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +wait_for_daemon() { | ||
| 30 | + local tries=100 | ||
| 31 | + while (( tries > 0 )); do | ||
| 32 | + if run_ctl ping >/dev/null 2>&1; then | ||
| 33 | + return 0 | ||
| 34 | + fi | ||
| 35 | + sleep 0.2 | ||
| 36 | + tries=$((tries - 1)) | ||
| 37 | + done | ||
| 38 | + echo "daemon did not become ready in time" | ||
| 39 | + return 1 | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +start_daemon() { | ||
| 43 | + GARCARD_SOCKET="${SOCKET_PATH}" \ | ||
| 44 | + GARCARD_AGENT_BACKEND="${BACKEND}" \ | ||
| 45 | + "${DAEMON_CMD[@]}" >>"${LOG_FILE}" 2>&1 & | ||
| 46 | + DAEMON_PID=$! | ||
| 47 | + wait_for_daemon | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +stop_daemon() { | ||
| 51 | + if [[ "${DAEMON_PID}" -gt 0 ]] && kill -0 "${DAEMON_PID}" 2>/dev/null; then | ||
| 52 | + run_ctl quit >/dev/null 2>&1 || true | ||
| 53 | + wait "${DAEMON_PID}" 2>/dev/null || true | ||
| 54 | + fi | ||
| 55 | + DAEMON_PID=0 | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +cleanup() { | ||
| 59 | + stop_daemon | ||
| 60 | + rm -f "${SOCKET_PATH}" | ||
| 61 | +} | ||
| 62 | +trap cleanup EXIT | ||
| 63 | + | ||
| 64 | +echo "Sprint 04 validation" | ||
| 65 | +echo " socket: ${SOCKET_PATH}" | ||
| 66 | +echo " backend: ${BACKEND}" | ||
| 67 | +echo " log: ${LOG_FILE}" | ||
| 68 | + | ||
| 69 | +mkdir -p "$(dirname "${SOCKET_PATH}")" | ||
| 70 | +mkdir -p "$(dirname "${LOG_FILE}")" | ||
| 71 | +rm -f "${SOCKET_PATH}" "${LOG_FILE}" | ||
| 72 | +start_daemon | ||
| 73 | + | ||
| 74 | +echo "[1/4] Baseline daemon health" | ||
| 75 | +run_ctl ping | ||
| 76 | +run_ctl status | ||
| 77 | +run_ctl auth-summary | ||
| 78 | + | ||
| 79 | +echo "[2/4] Restart resilience loop (${RESTART_LOOPS} iterations)" | ||
| 80 | +for i in $(seq 1 "${RESTART_LOOPS}"); do | ||
| 81 | + echo " iteration ${i}: stop/start daemon" | ||
| 82 | + run_ctl quit >/dev/null | ||
| 83 | + wait "${DAEMON_PID}" 2>/dev/null || true | ||
| 84 | + DAEMON_PID=0 | ||
| 85 | + start_daemon | ||
| 86 | + run_ctl ping >/dev/null | ||
| 87 | +done | ||
| 88 | + | ||
| 89 | +echo "[3/4] Post-restart health" | ||
| 90 | +run_ctl status | ||
| 91 | +run_ctl auth-summary | ||
| 92 | + | ||
| 93 | +echo "[4/4] Optional interactive auth loop" | ||
| 94 | +if [[ "${BACKEND}" == "polkit" ]] && command -v pkcheck >/dev/null 2>&1; then | ||
| 95 | + echo " running ${PKCHECK_LOOPS} pkcheck attempts for action ${ACTION_ID}" | ||
| 96 | + for i in $(seq 1 "${PKCHECK_LOOPS}"); do | ||
| 97 | + set +e | ||
| 98 | + pkcheck --allow-user-interaction --process "$$" --action-id "${ACTION_ID}" | ||
| 99 | + rc=$? | ||
| 100 | + set -e | ||
| 101 | + echo " pkcheck[${i}] rc=${rc}" | ||
| 102 | + run_ctl auth-summary || true | ||
| 103 | + done | ||
| 104 | +else | ||
| 105 | + echo " skipped (requires BACKEND=polkit and pkcheck installed)" | ||
| 106 | +fi | ||
| 107 | + | ||
| 108 | +echo "Validation complete. Log output:" | ||
| 109 | +echo " ${LOG_FILE}" | ||