diff --git a/.github/workflows/workstation-keyboard-policy.yml b/.github/workflows/workstation-keyboard-policy.yml new file mode 100644 index 0000000..7fab53c --- /dev/null +++ b/.github/workflows/workstation-keyboard-policy.yml @@ -0,0 +1,92 @@ +name: workstation-keyboard-policy + +on: + pull_request: + paths: + - 'profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh' + - 'profiles/linux-dev/workstation-v0/gnome/input-install.sh' + - 'profiles/linux-dev/workstation-v0/gnome/README.md' + - 'profiles/linux-dev/workstation-v0/manifest.yaml' + - '.github/workflows/workstation-keyboard-policy.yml' + push: + branches: + - main + paths: + - 'profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh' + - 'profiles/linux-dev/workstation-v0/gnome/input-install.sh' + - 'profiles/linux-dev/workstation-v0/gnome/README.md' + - 'profiles/linux-dev/workstation-v0/manifest.yaml' + - '.github/workflows/workstation-keyboard-policy.yml' + +jobs: + keyboard-policy-smoke: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Syntax check keyboard policy scripts + run: | + set -euo pipefail + bash -n profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh + bash -n profiles/linux-dev/workstation-v0/gnome/input-install.sh + + - name: Smoke: keyboard policy helper default backend + run: | + set -euo pipefail + helper='profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh' + tmp_home=$(mktemp -d) + out=$(HOME="$tmp_home" XDG_CONFIG_HOME="$tmp_home/.config" bash "$helper") + grep -F 'default_backend=input-remapper' <<<"$out" >/dev/null + grep -F 'primary_backend=input-remapper' <<<"$out" >/dev/null + grep -F 'compatibility_backends=xremap,kinto' <<<"$out" >/dev/null + grep -F 'wayland_first=yes' <<<"$out" >/dev/null + grep -F 'kinto_auto_install=no' <<<"$out" >/dev/null + grep -F 'selected_backend=input-remapper' <<<"$out" >/dev/null + grep -F 'backend_valid=yes' <<<"$out" >/dev/null + grep -F 'selected_backend_available=missing' <<<"$out" >/dev/null + grep -F 'input_installer=present' <<<"$out" >/dev/null + grep -F 'policy_ok=yes' <<<"$out" >/dev/null + + - name: Smoke: keyboard policy helper detects selected backend availability + run: | + set -euo pipefail + helper='profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh' + tmp_home=$(mktemp -d) + stub_bin=$(mktemp -d) + cat > "$stub_bin/input-remapper-control" <<'EOF' + #!/usr/bin/env bash + exit 0 + EOF + chmod +x "$stub_bin/input-remapper-control" + out=$(HOME="$tmp_home" XDG_CONFIG_HOME="$tmp_home/.config" PATH="$stub_bin:$PATH" bash "$helper") + grep -F 'input_remapper=present' <<<"$out" >/dev/null + grep -F 'selected_backend_available=present' <<<"$out" >/dev/null + grep -F 'policy_ok=yes' <<<"$out" >/dev/null + + - name: Smoke: keyboard policy helper rejects invalid backend + run: | + set -euo pipefail + helper='profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh' + tmp_home=$(mktemp -d) + out=$(HOME="$tmp_home" XDG_CONFIG_HOME="$tmp_home/.config" SOURCEOS_REMAP_BACKEND=invalid bash "$helper") + grep -F 'selected_backend=invalid' <<<"$out" >/dev/null + grep -F 'backend_valid=no' <<<"$out" >/dev/null + grep -F 'selected_backend_available=invalid' <<<"$out" >/dev/null + grep -F 'policy_ok=no' <<<"$out" >/dev/null + + - name: Smoke: input installer writes xremap template in compatibility mode + run: | + set -euo pipefail + installer='profiles/linux-dev/workstation-v0/gnome/input-install.sh' + tmp_home=$(mktemp -d) + HOME="$tmp_home" XDG_CONFIG_HOME="$tmp_home/.config" XDG_CURRENT_DESKTOP=GNOME SOURCEOS_REMAP_BACKEND=xremap bash "$installer" + tmpl="$tmp_home/.config/sourceos/input/xremap-macos-compat.yml" + test -s "$tmpl" + grep -F 'CapsLock: Esc' "$tmpl" >/dev/null + grep -F 'Control_L: Super_L' "$tmpl" >/dev/null + grep -F 'Super_L: Alt_L' "$tmpl" >/dev/null + grep -F 'Alt_L: Control_L' "$tmpl" >/dev/null + grep -F 'Control_R: Super_R' "$tmpl" >/dev/null + grep -F 'Super_R: Alt_R' "$tmpl" >/dev/null + grep -F 'Alt_R: Control_R' "$tmpl" >/dev/null diff --git a/profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh b/profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh new file mode 100644 index 0000000..d9e95ad --- /dev/null +++ b/profiles/linux-dev/workstation-v0/bin/check-keyboard-policy.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Validate workstation-v0 keyboard/remap policy without requiring root access. +# Emits key=value lines for doctor/status or CI consumption. + +have(){ command -v "$1" >/dev/null 2>&1; } + +profile_dir(){ + cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd +} + +backend(){ + printf '%s\n' "${SOURCEOS_REMAP_BACKEND:-input-remapper}" +} + +template_path(){ + printf '%s/sourceos/input/xremap-macos-compat.yml\n' "${XDG_CONFIG_HOME:-$HOME/.config}" +} + +present_or_missing(){ + if have "$1"; then + printf 'present\n' + else + printf 'missing\n' + fi +} + +main(){ + local pdir b tmpl backend_valid input_remapper xremap_bin xkeysnail selected_available policy_ok + pdir="$(profile_dir)" + b="$(backend)" + tmpl="$(template_path)" + backend_valid=no + selected_available=unknown + policy_ok=no + + printf 'profile_dir=%s\n' "$pdir" + printf 'default_backend=input-remapper\n' + printf 'primary_backend=input-remapper\n' + printf 'compatibility_backends=xremap,kinto\n' + printf 'wayland_first=yes\n' + printf 'kinto_auto_install=no\n' + printf 'selected_backend=%s\n' "$b" + + case "$b" in + input-remapper|xremap|kinto) + backend_valid=yes + ;; + esac + printf 'backend_valid=%s\n' "$backend_valid" + + input_remapper="$(present_or_missing input-remapper-control)" + xremap_bin="$(present_or_missing xremap)" + xkeysnail="$(present_or_missing xkeysnail)" + + printf 'input_remapper=%s\n' "$input_remapper" + printf 'xremap=%s\n' "$xremap_bin" + printf 'xkeysnail=%s\n' "$xkeysnail" + + case "$b" in + input-remapper) + selected_available="$input_remapper" + ;; + xremap) + selected_available="$xremap_bin" + ;; + kinto) + selected_available="$xkeysnail" + ;; + *) + selected_available=invalid + ;; + esac + printf 'selected_backend_available=%s\n' "$selected_available" + + if [[ -f "$tmpl" ]]; then + printf 'xremap_template=present\n' + else + printf 'xremap_template=missing\n' + fi + printf 'xremap_template_path=%s\n' "$tmpl" + + if [[ -f "$pdir/gnome/input-install.sh" ]]; then + printf 'input_installer=present\n' + else + printf 'input_installer=missing\n' + fi + + if [[ "$backend_valid" == "yes" ]]; then + policy_ok=yes + fi + printf 'policy_ok=%s\n' "$policy_ok" +} + +main "$@" diff --git a/profiles/linux-dev/workstation-v0/gnome/README.md b/profiles/linux-dev/workstation-v0/gnome/README.md index 16650b8..422dbb0 100644 --- a/profiles/linux-dev/workstation-v0/gnome/README.md +++ b/profiles/linux-dev/workstation-v0/gnome/README.md @@ -17,6 +17,7 @@ Principles: ./appearance-apply.sh ./files-sidebar.sh ./mac-defaults.sh +./input-install.sh ``` ## Current baseline (v0) @@ -49,6 +50,15 @@ This lane adds bounded visual/workflow polish without replacing GNOME Shell or l - `files-sidebar.sh` seeds GTK/Nautilus bookmarks for Desktop, Documents, Downloads, Pictures, Screenshots, Music, Videos, and Public. - The workstation installer runs both helpers best-effort after the extension pinset and before input/gesture setup. +## Keyboard/remap policy v1 + +The workstation keeps keyboard remapping explicit and policy-gated: + +- `input-remapper` remains the default Fedora/GNOME backend because it is packaged and works at the evdev layer. +- `xremap` is the advanced compatibility lane; the installer writes a template at `$XDG_CONFIG_HOME/sourceos/input/xremap-macos-compat.yml`. +- Kinto remains an explicit compatibility lane for X11/xkeysnail-style workflows and is not auto-installed in the Wayland-first profile. +- `check-keyboard-policy.sh` emits key=value status for CI and future doctor/status integration. + ## Follow-on work - Wayland-safe keyboard remap lane expansion