The first run of the suite on a laptop found five contracts asserting the desktop instead of the code. settings-system pinned DP-2 at 4500x3000 in XRGB2101010; it now asks Hyprland what is actually primary. ssh-keys hardcoded id_ed25519; it now uses whichever key exists. switcher's live half stepped a session with one window, which step() deliberately refuses. displays raced the service's revert readback -- the compositor looks restored while verification still holds busy, so an immediate apply was refused with its error already cleared; the harness now exposes settled and the contract waits for it. declared-dependencies gets an OPTIONAL list for docker: the aliases serve machines that run Docker deliberately, Panama's runtime is rootless podman, and a missing docker fails by naming the command, which is loud enough. Claude-Session: https://claude.ai/code/session_01Epx9ZC1gwm81K3jm9x9CKh
121 lines
5.7 KiB
Bash
Executable File
121 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# SSH keys, and the two things this page must never do.
|
|
#
|
|
# The rules:
|
|
#
|
|
# 1. A private key is never read for its contents and never leaves the
|
|
# machine's disk. Fingerprints and comments come from the .pub file.
|
|
# 2. No passphrase passes through this tool. Adding an encrypted key lets
|
|
# ssh-add prompt through the system's own askpass; collecting one here and
|
|
# handing it on would be a worse place for it to live, and putting one in
|
|
# argv would publish it to every process on the machine.
|
|
# 3. Key paths are confined to ~/.ssh, resolved and compared, so a name cannot
|
|
# walk out of the directory.
|
|
# 4. A control that cannot do what it says is not offered. gnome-keyring's
|
|
# agent lists every key it finds in ~/.ssh, so `ssh-add -d` reports
|
|
# "Identity removed" and the key is still offered a second later. Measured
|
|
# on this machine: a plain ssh-agent removes durably, that one does not.
|
|
# 5. Copying a public key never splices a path into shell source.
|
|
#
|
|
# Read-only against the real configuration. Nothing here adds, removes or
|
|
# rewrites a key, an agent entry, or a known host.
|
|
|
|
set -uo pipefail
|
|
|
|
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
helper="$repo_dir/config/dot/quickshell/scripts/panama-ssh-keys"
|
|
service="$repo_dir/config/dot/quickshell/services/SshKeys.qml"
|
|
page="$repo_dir/config/dot/quickshell/modules/settings/SshKeysPage.qml"
|
|
|
|
fail() {
|
|
printf 'ssh keys contract: %s\n' "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
for path in "$helper" "$service" "$page"; do
|
|
[[ -r "$path" ]] || fail "missing $path"
|
|
done
|
|
[[ -x "$helper" ]] || fail 'panama-ssh-keys is not executable'
|
|
|
|
field() { python3 -c "import json,sys; print(json.load(sys.stdin)$1)"; }
|
|
|
|
state="$("$helper" snapshot)" || fail 'snapshot failed'
|
|
|
|
# ── 1. Private key material never surfaces ──────────────────────────────────
|
|
#
|
|
# Checked against the payload rather than the source: whatever the code intends,
|
|
# what actually reaches the page must not contain key material.
|
|
|
|
printf '%s' "$state" | python3 -c "
|
|
import json, sys
|
|
raw = sys.stdin.read()
|
|
for marker in ('BEGIN OPENSSH PRIVATE KEY', 'BEGIN RSA PRIVATE KEY', 'BEGIN EC PRIVATE KEY'):
|
|
if marker in raw:
|
|
raise SystemExit(f'the snapshot contains {marker}')
|
|
state = json.loads(raw)
|
|
for key in state['keys']:
|
|
for name, value in key.items():
|
|
if isinstance(value, str) and len(value) > 200:
|
|
raise SystemExit(f'{name} is long enough to be key material')
|
|
" || fail 'private key material reached the snapshot'
|
|
|
|
# The helper must never read a private key for its bytes. The one place it opens
|
|
# one is ssh-keygen -y, which can only ever emit the public half.
|
|
grep -q 'read_text' "$helper" && ! grep -q 'KNOWN_HOSTS.read_text' "$helper" \
|
|
&& fail 'something reads a file directly that is not known_hosts'
|
|
|
|
# ── 2. No passphrase anywhere ───────────────────────────────────────────────
|
|
|
|
grep -qE '\-N["'"'"' ]' "$helper" \
|
|
&& fail 'ssh-keygen -N appears, which would put a passphrase in argv'
|
|
grep -qi 'passphrase' "$service" && ! grep -qi 'never\|prompt' "$service" \
|
|
&& fail 'the service mentions passphrases without saying it does not handle them'
|
|
|
|
# ── 3. Paths are confined ───────────────────────────────────────────────────
|
|
|
|
grep -q 'def resolve_key' "$helper" || fail 'key paths are not resolved before use'
|
|
grep -q 'resolved.parent != SSH_DIR' "$helper" \
|
|
|| fail 'a key path is not compared against the SSH directory, so it could escape'
|
|
|
|
reason="$(printf '%s' "$("$helper" agent-add /etc/hostname)" | field "['error']")"
|
|
[[ "$reason" == *"not in the SSH directory"* ]] \
|
|
|| fail "a path outside ~/.ssh was not refused with a reason (got: $reason)"
|
|
|
|
reason="$(printf '%s' "$("$helper" agent-add /home/nonexistent/.ssh/nope)" | field "['error']")"
|
|
[[ -n "$reason" ]] || fail 'a missing key was accepted'
|
|
|
|
reason="$(printf '%s' "$("$helper" forget-host 'not a host name')" | field "['error']")"
|
|
[[ "$reason" == *"not a host name"* ]] \
|
|
|| fail "an invalid host was not refused with a reason (got: $reason)"
|
|
|
|
# ── 4. A control that cannot deliver is not offered ─────────────────────────
|
|
|
|
grep -q 'durableRemoval' "$helper" \
|
|
|| fail 'the helper does not record whether removal from this agent sticks'
|
|
|
|
kind="$(printf '%s' "$state" | field "['agent'].get('kind','')")"
|
|
if [[ "$kind" == "gnome-keyring" ]]; then
|
|
# Whichever key this machine actually has. This used to hardcode
|
|
# id_ed25519, which asserted the author's machine: any other key name
|
|
# earned "That key no longer exists" instead of the refusal under test.
|
|
# No key at all means the property cannot be exercised here, not that it
|
|
# failed.
|
|
real_key="$(compgen -G "$HOME/.ssh/id_*.pub" | head -1)"
|
|
real_key="${real_key%.pub}"
|
|
if [[ -n "$real_key" ]]; then
|
|
reason="$(printf '%s' "$("$helper" agent-remove "$real_key")" | field "['error']")"
|
|
[[ "$reason" == *"does not stick"* ]] \
|
|
|| fail "removal against a keyring agent was not refused with its reason (got: $reason)"
|
|
fi
|
|
grep -q 'does not stick' "$page" \
|
|
|| fail 'the page does not say that removing a key from this agent has no effect'
|
|
fi
|
|
|
|
# ── 5. Copying does not build shell source from a path ──────────────────────
|
|
|
|
grep -q 'exec wl-copy < "\$1"' "$service" \
|
|
|| fail 'the public key copy does not pass its path as an argument'
|
|
|
|
printf 'ssh keys contract: ok\n'
|