Skip to content

ci(cli): check keepiq ssh-agent on macOS - #1142

Merged
rubenvdlinde merged 1 commit into
developmentfrom
ci/1042-ssh-agent-macos
Oct 4, 2026
Merged

rubenvdlinde merged 1 commit into
developmentfrom
ci/1042-ssh-agent-macos

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1042

Nobody on the team has a Mac, so this checks keepiq ssh-agent on a macos-latest runner instead (Ruben's call, 4 October). The job needs no secrets and no Nextcloud server.

What the job runs

New workflow .github/workflows/cli-macos.yml, on pull requests that touch cli/, sdk/go/, sdk/testdata/ or the workflow itself, and on demand.

  1. Go tests. go vet and go test ./... for cli/. The step fails if TestRealSSHThroughTheAgent (real ssh against a throwaway sshd), TestEvalReturnsAndTheAgentKeepsServing (the fix(cli): page the secret list and let eval start the SSH agent (#786 live checks) #1022 hang) or TestVaultUnlockerReadsOnlyCiphertext did not pass, so a skip cannot read as green.
  2. The README's recipe in a real shell. cli/scripts/ssh-agent-e2e.sh starts a fake Keepiq (cli/internal/fakevault, test only, not in the release build) and an sshd run as the runner user on a high port with its own host key and authorized_keys. The vault key exists only in the fake vault, so a login can only come from the agent. It then checks:
    • eval "$(keepiq ssh-agent)" returns, exports SSH_AUTH_SOCK and SSH_AGENT_PID, and the socket sits at the README's macOS default $TMPDIR/keepiq-<uid>/agent.sock, mode 0600 in a 0700 folder
    • ssh-add -l lists the vault key and skips the login secret
    • ssh and git clone over SSH log in with it
    • ssh-add -x locks: no keys, login refused with Permission denied; a wrong password does not unlock
    • ssh-add -X with the master password unlocks, and the login works again
    • ssh-add <file>, ssh-add -d and ssh-add -D are refused
    • kill $SSH_AGENT_PID stops the agent and removes the socket
  3. The README's launchd plist. The same script takes the plist out of cli/README.md, runs plutil -lint, checks its ProgramArguments, fills in the binary path and home, and loads it with the README's own launchctl load. It then checks the agent starts locked, unlocks with ssh-add -X, serves a login, and comes back locked after a kill (KeepAlive). If the runner refuses to load a LaunchAgent, the step records what launchctl said and warns.

Verified

  • The e2e script passes on Linux in golang:1.25 as a non-root user (the macOS case): all seven checks.
  • actionlint 1.7.7 with shellcheck 0.11.0: no findings. shellcheck on the script: clean. gofmt: clean.
  • macOS: green run https://github.com/ConductionNL/keepiq/actions/runs/37209235179 on macOS 26.6.2 with OpenSSH 10.3p1. The three ssh-agent Go tests passed, none skipped. All seven recipe checks passed, with the socket at $TMPDIR/keepiq-501/agent.sock. The README's launchctl load worked: the agent started locked, unlocked with ssh-add -X, served a login, and came back locked after a kill (KeepAlive).

Not covered on a runner

The launchd check loads the plist into a running session. Whether the agent starts at a real login (a reboot and a fresh login) cannot be tested on a runner.

Inherited findings: none in the files this PR adds.

A macos-latest job runs the CLI's Go tests (the real-sshd integration
test and the eval test must pass, not skip), then the README's recipe
in a real shell against a fake Keepiq and a throwaway sshd started as
the runner user: eval, ssh-add -l, ssh and git clone over SSH, -x lock,
-X unlock, refusal of ssh-add <file>/-d/-D, and kill. It then loads the
README's launchd plist and checks the agent it starts, unlock, login
and KeepAlive restart.

Refs #1042
@rubenvdlinde
rubenvdlinde merged commit 8ad04aa into development Oct 4, 2026
57 of 60 checks passed
rubenvdlinde added a commit that referenced this pull request Oct 4, 2026
Under systemd the agent's stdout is the journal, not a terminal, so it took
the eval path (#1022): it started a background copy and its main process
exited 0. systemd then stopped the unit and killed the copy with the cgroup,
so the README's service never kept running. Found by the macOS CI lane (#1142).

--foreground keeps the agent in the process systemd started; the README unit
uses it. The detach decision is now shouldDetach(), pinned by a test.
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/keepiq @ 4ea50fb

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ✅
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-manifest ✅
test-l10n ✅
format ✅
check-l10n-js ✅
check-schema-l10n ✅
composer ✅ ✅ 114/114
npm ✅ ✅ 660/660
app:check-code ⏭️
info.xml ✅
REUSE ✅
lockfile sync ✅
PHPUnit ❌
Newman ❌
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ✅

Quality workflow — 2026-10-04 14:34 UTC

Download the full PDF report from the workflow artifacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant