From d8555e5047bc71b48badcdd2cfeb740de7a227e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 18:52:51 +0000 Subject: [PATCH 1/2] Initial plan From 4f6642488feaa40dc7ce305e18c783115e2a7d66 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 18:57:26 +0000 Subject: [PATCH 2/2] feat(workstation-v0): add GNOME extension/dock validation helper - Add gnome/check-gnome-extensions.sh emitting key=value status for gnome_detected, gnome_extensions_cli, gsettings, dash_to_dock, appindicator, favorite_apps, dock_position, dock_autohide, dock_intellihide. Degrades gracefully outside a GNOME session. - Add .github/workflows/workstation-gnome-ext.yml with focused CI smoke: syntax check, key-presence assertions, and stub-based extension state tests (enabled / present-but-not-enabled / missing). - Add tests/workstation-gnome-ext-contract.nix: static Nix contract covering file existence, bash -n, key/UUID grep, and runtime key presence. - Update gnome/README.md with helper documentation and key table. Agent-Logs-Url: https://github.com/SociOS-Linux/source-os/sessions/4cdc1910-e33b-47d2-a594-c5ac40f5204a Co-authored-by: mdheller <21163552+mdheller@users.noreply.github.com> --- .github/workflows/workstation-gnome-ext.yml | 108 ++++++++++++++++++ .../linux-dev/workstation-v0/gnome/README.md | 25 ++++ .../gnome/check-gnome-extensions.sh | 72 ++++++++++++ tests/workstation-gnome-ext-contract.nix | 43 +++++++ 4 files changed, 248 insertions(+) create mode 100644 .github/workflows/workstation-gnome-ext.yml create mode 100755 profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh create mode 100644 tests/workstation-gnome-ext-contract.nix diff --git a/.github/workflows/workstation-gnome-ext.yml b/.github/workflows/workstation-gnome-ext.yml new file mode 100644 index 0000000..91cb625 --- /dev/null +++ b/.github/workflows/workstation-gnome-ext.yml @@ -0,0 +1,108 @@ +name: workstation-gnome-ext + +on: + pull_request: + paths: + - 'profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh' + - 'profiles/linux-dev/workstation-v0/gnome/extensions-install.sh' + - 'profiles/linux-dev/workstation-v0/gnome/README.md' + - '.github/workflows/workstation-gnome-ext.yml' + push: + branches: + - main + paths: + - 'profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh' + - 'profiles/linux-dev/workstation-v0/gnome/extensions-install.sh' + - 'profiles/linux-dev/workstation-v0/gnome/README.md' + - '.github/workflows/workstation-gnome-ext.yml' + +jobs: + gnome-ext-smoke: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Syntax check + run: | + set -euo pipefail + bash -n profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh + bash -n profiles/linux-dev/workstation-v0/gnome/extensions-install.sh + + - name: Smoke: key presence in non-GNOME environment + run: | + set -euo pipefail + helper='profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh' + out=$(bash "$helper") + grep -F 'gnome_detected=' <<<"$out" >/dev/null + grep -F 'gnome_extensions_cli=' <<<"$out" >/dev/null + grep -F 'gsettings=' <<<"$out" >/dev/null + grep -F 'dash_to_dock=' <<<"$out" >/dev/null + grep -F 'appindicator=' <<<"$out" >/dev/null + grep -F 'favorite_apps=' <<<"$out" >/dev/null + grep -F 'dock_position=' <<<"$out" >/dev/null + grep -F 'dock_autohide=' <<<"$out" >/dev/null + grep -F 'dock_intellihide=' <<<"$out" >/dev/null + # Non-GNOME CI runner: detected=no, extension status=unknown + grep -F 'gnome_detected=no' <<<"$out" >/dev/null + grep -F 'dash_to_dock=unknown' <<<"$out" >/dev/null + grep -F 'appindicator=unknown' <<<"$out" >/dev/null + + - name: Smoke: stub gnome-extensions CLI detects enabled extensions + run: | + set -euo pipefail + helper='profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh' + stub_bin=$(mktemp -d) + # Both --enabled and plain list return the extensions (they are installed and enabled) + cat > "$stub_bin/gnome-extensions" <<'STUB' + #!/usr/bin/env bash + if [[ "${1:-}" == "list" && "${2:-}" == "--enabled" ]]; then + printf 'dash-to-dock@micxgx.gmail.com\n' + printf 'appindicatorsupport@rgcjonas.gmail.com\n' + elif [[ "${1:-}" == "list" ]]; then + printf 'dash-to-dock@micxgx.gmail.com\n' + printf 'appindicatorsupport@rgcjonas.gmail.com\n' + fi + STUB + chmod +x "$stub_bin/gnome-extensions" + out=$(PATH="$stub_bin:$PATH" bash "$helper") + grep -F 'gnome_extensions_cli=present' <<<"$out" >/dev/null + grep -F 'dash_to_dock=enabled' <<<"$out" >/dev/null + grep -F 'appindicator=enabled' <<<"$out" >/dev/null + + - name: Smoke: stub gnome-extensions CLI detects present-but-not-enabled + run: | + set -euo pipefail + helper='profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh' + stub_bin=$(mktemp -d) + # --enabled returns nothing; plain list returns both + cat > "$stub_bin/gnome-extensions" <<'STUB' + #!/usr/bin/env bash + if [[ "${1:-}" == "list" && "${2:-}" == "--enabled" ]]; then + exit 0 + elif [[ "${1:-}" == "list" ]]; then + printf 'dash-to-dock@micxgx.gmail.com\n' + printf 'appindicatorsupport@rgcjonas.gmail.com\n' + fi + STUB + chmod +x "$stub_bin/gnome-extensions" + out=$(PATH="$stub_bin:$PATH" bash "$helper") + grep -F 'dash_to_dock=present' <<<"$out" >/dev/null + grep -F 'appindicator=present' <<<"$out" >/dev/null + + - name: Smoke: stub gnome-extensions CLI detects missing extensions + run: | + set -euo pipefail + helper='profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh' + stub_bin=$(mktemp -d) + # Empty list — nothing installed + cat > "$stub_bin/gnome-extensions" <<'STUB' + #!/usr/bin/env bash + exit 0 + STUB + chmod +x "$stub_bin/gnome-extensions" + out=$(PATH="$stub_bin:$PATH" bash "$helper") + grep -F 'dash_to_dock=missing' <<<"$out" >/dev/null + grep -F 'appindicator=missing' <<<"$out" >/dev/null diff --git a/profiles/linux-dev/workstation-v0/gnome/README.md b/profiles/linux-dev/workstation-v0/gnome/README.md index 422dbb0..d76bd79 100644 --- a/profiles/linux-dev/workstation-v0/gnome/README.md +++ b/profiles/linux-dev/workstation-v0/gnome/README.md @@ -50,6 +50,31 @@ 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. +## Extension/dock validation helper + +`check-gnome-extensions.sh` emits `key=value` status for the GNOME extension and dock lane so that `doctor`, `status`, and CI can reason about it without a live GNOME session. + +Keys emitted: + +| Key | Values | +|-----|--------| +| `gnome_detected` | `yes` / `no` | +| `gnome_extensions_cli` | `present` / `missing` | +| `gsettings` | `present` / `missing` | +| `dash_to_dock` | `enabled` / `present` / `missing` / `unknown` | +| `appindicator` | `enabled` / `present` / `missing` / `unknown` | +| `favorite_apps` | gsettings value or `unknown` | +| `dock_position` | gsettings value or `unknown` | +| `dock_autohide` | gsettings value or `unknown` | +| `dock_intellihide` | gsettings value or `unknown` | + +**Known gaps:** extension status is `unknown` when `gnome-extensions` CLI is absent (e.g. on a CI runner or server). Dock gsettings keys are `unknown` when the Dash-to-Dock schema is not installed. + +```bash +bash -n gnome/check-gnome-extensions.sh # syntax check +bash gnome/check-gnome-extensions.sh # emit status +``` + ## Keyboard/remap policy v1 The workstation keeps keyboard remapping explicit and policy-gated: diff --git a/profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh b/profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh new file mode 100755 index 0000000..5f0c5e7 --- /dev/null +++ b/profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Lightweight GNOME extension/dock status helper for workstation-v0. +# Emits key=value lines so doctor/status/CI can reason about the dock and +# extension lane without broad GNOME rewrites. +# Safe to run outside a GNOME session; degrades gracefully to "unknown". + +have(){ command -v "$1" >/dev/null 2>&1; } + +is_gnome(){ + [[ "${XDG_CURRENT_DESKTOP:-}" == *GNOME* ]] && return 0 + [[ "${DESKTOP_SESSION:-}" == *gnome* ]] && return 0 + return 1 +} + +# Returns: enabled | present | missing | unknown +ext_status(){ + local uuid=$1 + if ! have gnome-extensions; then + printf 'unknown\n' + return + fi + if gnome-extensions list --enabled 2>/dev/null | grep -qx "$uuid"; then + printf 'enabled\n' + return + fi + if gnome-extensions list 2>/dev/null | grep -qx "$uuid"; then + printf 'present\n' + return + fi + printf 'missing\n' +} + +gsetting_get(){ + local schema=$1 key=$2 + if have gsettings; then + gsettings get "$schema" "$key" 2>/dev/null || printf 'unknown\n' + else + printf 'unknown\n' + fi +} + +main(){ + if is_gnome; then + printf 'gnome_detected=yes\n' + else + printf 'gnome_detected=no\n' + fi + + if have gnome-extensions; then + printf 'gnome_extensions_cli=present\n' + else + printf 'gnome_extensions_cli=missing\n' + fi + + if have gsettings; then + printf 'gsettings=present\n' + else + printf 'gsettings=missing\n' + fi + + printf 'dash_to_dock=%s\n' "$(ext_status 'dash-to-dock@micxgx.gmail.com')" + printf 'appindicator=%s\n' "$(ext_status 'appindicatorsupport@rgcjonas.gmail.com')" + + printf 'favorite_apps=%s\n' "$(gsetting_get org.gnome.shell favorite-apps)" + printf 'dock_position=%s\n' "$(gsetting_get org.gnome.shell.extensions.dash-to-dock dock-position)" + printf 'dock_autohide=%s\n' "$(gsetting_get org.gnome.shell.extensions.dash-to-dock autohide)" + printf 'dock_intellihide=%s\n' "$(gsetting_get org.gnome.shell.extensions.dash-to-dock intellihide)" +} + +main "$@" diff --git a/tests/workstation-gnome-ext-contract.nix b/tests/workstation-gnome-ext-contract.nix new file mode 100644 index 0000000..1a738c4 --- /dev/null +++ b/tests/workstation-gnome-ext-contract.nix @@ -0,0 +1,43 @@ +{ pkgs ? import {} }: +pkgs.runCommand "workstation-gnome-ext-contract" { + nativeBuildInputs = [ pkgs.bash pkgs.gnugrep ]; +} '' + helper=${../profiles/linux-dev/workstation-v0/gnome/check-gnome-extensions.sh} + + # File must exist and be non-empty + test -f "$helper" + test -s "$helper" + + # Syntax check + bash -n "$helper" + + # Static: required keys must be referenced in the script + grep -q 'gnome_detected' "$helper" + grep -q 'gnome_extensions_cli' "$helper" + grep -q 'gsettings' "$helper" + grep -q 'dash_to_dock' "$helper" + grep -q 'appindicator' "$helper" + grep -q 'favorite_apps' "$helper" + grep -q 'dock_position' "$helper" + grep -q 'dock_autohide' "$helper" + grep -q 'dock_intellihide' "$helper" + + # Static: pinned extension UUIDs must be present + grep -q 'dash-to-dock@micxgx.gmail.com' "$helper" + grep -q 'appindicatorsupport@rgcjonas.gmail.com' "$helper" + + # Runtime: run helper in non-GNOME sandbox (no GNOME session, no dbus) + helper_out=$(bash "$helper") + grep -F 'gnome_detected=' <<<"$helper_out" + grep -F 'gnome_extensions_cli=' <<<"$helper_out" + grep -F 'gsettings=' <<<"$helper_out" + grep -F 'dash_to_dock=' <<<"$helper_out" + grep -F 'appindicator=' <<<"$helper_out" + grep -F 'favorite_apps=' <<<"$helper_out" + grep -F 'dock_position=' <<<"$helper_out" + grep -F 'dock_autohide=' <<<"$helper_out" + grep -F 'dock_intellihide=' <<<"$helper_out" + + mkdir -p $out + echo validated > $out/result.txt +''