Skip to content

test: the Windows tray job asserts the old behaviour #110

test: the Windows tray job asserts the old behaviour

test: the Windows tray job asserts the old behaviour #110

Workflow file for this run

name: CI
on:
push:
pull_request:
jobs:
test-offline:
# The full suite - including init, seed-pack install, selftest, store,
# search, shred, lock, unlock - runs with the runtime offline guard
# active: any attempt to create a network socket aborts the process.
# This is the executable proof of the zero-network claim.
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python: ["3.11", "3.12"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install (network allowed for dependency download only)
run: pip install -e .[dev]
- name: Test suite with offline guard active
env:
COMPARTMENT_ASSERT_OFFLINE: "1"
run: pytest tests/ -q
- name: Dashboard tests (loopback socket; offline guard intentionally off)
# `compartment dash` binds 127.0.0.1 by design and is never run under the
# offline guard, so its tests run here with the guard off.
run: pytest tests/test_dash.py -q
windows-tray:
# The tray app has to actually start on Windows, and "it starts" is the
# failure the unit tests cannot see: the macOS app once launched, ran, and
# showed nothing at all. The runner has a desktop session, so the app can
# really be drawn here - the screenshot is uploaded so a human can look at
# the panel without owning a Windows machine.
runs-on: windows-latest
# Nothing here should take twenty minutes. Without a cap, one command
# waiting on a passphrase prompt that no one can answer held a runner
# for 2h40m: init crashed on a non-ASCII character, left the vault
# locked, and the next command sat asking for input.
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install with the tray extra
run: pip install -e .[tray]
- name: A vault to look at
# Five ordinary-looking memories, so the screenshot shows the panel
# doing its job instead of an empty list.
run: |
compartment init --passphrase ci-only-not-a-secret
compartment store "Deploys go out Tuesday and Thursday mornings, never on a Friday."
compartment store "Approved (answered OK): send the release notes to the team now?"
compartment store "Staging runs Postgres 16 behind pgbouncer on port 6432."
compartment store "Prefers spaces over tabs everywhere except Go."
compartment store "This laptop has 16 GB, so keep parallel jobs at 4."
python -c "from compartment import menubar as m; m.set_setting(m.default_vault(), 'capture_hook', True)"
- name: The panel, without a window (what it would say)
run: compartment tray --self-check
- name: Changing the passphrase has to work here too
# The apps grew a Change password button, and Windows is the side
# with no one sitting in front of it. Prove the whole round trip:
# the new passphrase opens the vault and the old one does not.
shell: pwsh
run: |
"Locksmith-ci-only" | compartment rekey --new-passphrase-stdin
if ($LASTEXITCODE -ne 0) { Write-Error "rekey failed"; exit 1 }
compartment lock
$old = "ci-only-not-a-secret" | compartment unlock --passphrase-stdin 2>&1
if ($LASTEXITCODE -eq 0) { Write-Error "the OLD passphrase still opens it"; exit 1 }
Write-Host "old passphrase correctly rejected"
"Locksmith-ci-only" | compartment unlock --passphrase-stdin
if ($LASTEXITCODE -ne 0) { Write-Error "the NEW passphrase does not open it"; exit 1 }
Write-Host "new passphrase accepted"
- name: A bigger screen than the 1024x768 default
shell: pwsh
continue-on-error: true
run: |
Set-DisplayResolution -Width 1920 -Height 1080 -Force
Start-Sleep -Seconds 3
- name: A second copy stands down instead of adding another icon
# `compartment init` above already started the tray app, which is the
# whole point of it. So a launch now must hand off and exit 0, and
# the copy that was already there must still be running afterwards.
shell: pwsh
run: |
$before = @(Get-Process compartment -ErrorAction SilentlyContinue).Count
if ($before -lt 1) { Write-Error "init did not start the tray app"; exit 1 }
compartment tray --show
if ($LASTEXITCODE -ne 0) { Write-Error "the second copy failed instead of standing down"; exit 1 }
$after = @(Get-Process compartment -ErrorAction SilentlyContinue).Count
if ($after -ne $before) { Write-Error "second copy changed the count: $before -> $after"; exit 1 }
Write-Host "one copy before, one copy after"
Get-Process compartment -ErrorAction SilentlyContinue | Stop-Process -Force
Start-Sleep -Seconds 2
- name: Start the tray app and prove it is still alive
# At the DEFAULT scale, which is what nearly everyone runs. The
# high-DPI path below must not be the only one exercised.
shell: pwsh
run: |
$p = Start-Process -PassThru -FilePath compartment -ArgumentList 'tray','--show'
Start-Sleep -Seconds 25
if ($p.HasExited) {
Write-Error "the tray app exited on its own with $($p.ExitCode)"
exit 1
}
Write-Host "still running after 25s (pid $($p.Id))"
Stop-Process -Id $p.Id -Force
Start-Sleep -Seconds 2
- name: Start it again at 2x, the way a high-DPI laptop draws it
# The runner's display is 96 DPI, so this is the only way to see the
# scaled path render here - and it is what produces a screenshot
# sharp enough to sit beside the Retina macOS one.
shell: pwsh
env:
COMPARTMENT_UI_SCALE: "2"
run: |
$p = Start-Process -PassThru -FilePath compartment -ArgumentList 'tray','--show'
Start-Sleep -Seconds 25
if ($p.HasExited) {
Write-Error "the tray app exited at 2x scale with $($p.ExitCode)"
exit 1
}
Write-Host "still running at 2x after 25s (pid $($p.Id))"
- name: Screenshot the panel, cropped by Windows itself
shell: pwsh
run: |
Add-Type -AssemblyName System.Windows.Forms,System.Drawing
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class NativeWin {
[DllImport("user32.dll", CharSet=CharSet.Unicode)]
public static extern IntPtr FindWindow(string cls, string name);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr h);
[StructLayout(LayoutKind.Sequential)]
public struct RECT { public int Left, Top, Right, Bottom; }
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(
IntPtr h, int attr, out RECT r, int size);
}
"@
# The whole desktop first, so this step always produces something
# even if the precise capture below cannot find the window.
$b = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
Write-Host "desktop: $($b.Width)x$($b.Height)"
$full = New-Object System.Drawing.Bitmap $b.Width, $b.Height
$g2 = [System.Drawing.Graphics]::FromImage($full)
$g2.CopyFromScreen($b.Location, [System.Drawing.Point]::Empty, $b.Size)
$full.Save("$PWD\tray.png", [System.Drawing.Imaging.ImageFormat]::Png)
# Ask the process for its own window rather than FindWindow: passing
# $null for a string parameter through P/Invoke marshals as "" in
# PowerShell, which then matches a window class literally named
# empty and finds nothing.
Write-Host "windows with a title:"
Get-Process | Where-Object { $_.MainWindowHandle -ne 0 } |
ForEach-Object { Write-Host " $($_.ProcessName): '$($_.MainWindowTitle)'" }
$proc = Get-Process |
Where-Object { $_.MainWindowHandle -ne 0 -and
($_.ProcessName -like "*compartment*" -or
$_.MainWindowTitle -eq "Compartment") } |
Select-Object -First 1
if (-not $proc) {
Write-Warning "no Compartment window found; desktop shot only"
exit 0
}
$h = $proc.MainWindowHandle
[void][NativeWin]::SetForegroundWindow($h)
Start-Sleep -Milliseconds 900
$r = New-Object NativeWin+RECT
# 9 = DWMWA_EXTENDED_FRAME_BOUNDS: the real frame, without the
# invisible resize border a plain GetWindowRect includes.
[void][NativeWin]::DwmGetWindowAttribute($h, 9, [ref]$r, 16)
$w = $r.Right - $r.Left; $ht = $r.Bottom - $r.Top
if ($w -lt 50 -or $ht -lt 50) {
Write-Warning "implausible window rect ${w}x${ht}; desktop shot only"
exit 0
}
$bmp = New-Object System.Drawing.Bitmap $w, $ht
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.CopyFromScreen($r.Left, $r.Top, 0, 0,
(New-Object System.Drawing.Size $w, $ht))
$bmp.Save("$PWD\compartment-windows-panel.png",
[System.Drawing.Imaging.ImageFormat]::Png)
Write-Host "panel: ${w}x${ht}"
- uses: actions/upload-artifact@v4
with:
name: windows-tray-screenshot
path: |
compartment-windows-panel.png
tray.png