Skip to content

Keychain fixes, docs, smoke tests, and keychain delete - #1231

Open
theoephraim wants to merge 7 commits into
mainfrom
keychain-smoke-tests
Open

theoephraim wants to merge 7 commits into
mainfrom
keychain-smoke-tests

Conversation

@theoephraim

@theoephraim theoephraim commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Lands the reusable parts of #847 by @bjesuiter (credited as co-author on both commits).

  • Keychain smoke tests for keychain set, keychain import, and the new keychain delete. They're opt-in (pnpm run test:keychain in smoke-tests, macOS only) because they touch the real login keychain and need a helper signed with a stable Team ID. A preflight asks varlock which helper it resolves and fails early if that binary is ad-hoc signed.
  • varlock keychain delete: removes exactly one Keychain item (service + account required), with a clear error when nothing matches. Docs updated, plus guidance on choosing "Always Allow" for items Varlock didn't create.
  • Actionable keychain() errors: a failed read now says whether the item is missing, not accessible, or ambiguous, and prints the exact varlock keychain set ... or varlock keychain fix-access ... command for that ref. The helper also no longer reports an access-denied generic item as "not found" (it used to swallow the error and retry as an internet password).
  • Fix keychain() positional service with named args: keychain("svc", account="x") ignored "svc" and could return a different service's item with the same account; keychain("svc", keychain="y") ignored the keychain. They now combine, and duplicate or non-static args are schema errors.
  • keychain() on other platforms and optional items: the macOS check moved from schema processing to resolve time, so if(eq($VARLOCK_OS, "darwin"), keychain(...), ...) no longer breaks the schema on Linux/Windows. New allowMissing=true resolves to empty when the item does not exist, so fallback(keychain(..., allowMissing=true), ...) works (same meaning as the plugins' allowMissing; other OSes and real failures still error).
  • Keychain docs pass: fixed the invalid field="password" example (field only returns metadata), the list filter description, the non-Mac fallback() advice, and the troubleshooting section; added a short section on sharing committed refs with a team.
  • Allow deno as a daemon client in the Swift and Rust helpers, matching node/bun. Closes Allow Deno as a VarlockEnclave IPC client #842.

Left out from #847: the fix-access rewrite (the existing ACL-based flow works when tested against an item that trusts no apps), cloneToOwned, and the Deno completion and smoke-runner changes.

theoephraim and others added 2 commits October 13, 2026 18:35
Ports the reusable parts of #847: gated macOS Keychain smoke tests for
`set` and `import`, a daemon reset helper, a signing preflight, and a
`keychain delete` command. Tests run with `pnpm run test:keychain` in
smoke-tests and require a helper signed with a stable Team ID.

Co-authored-by: Benjamin Jesuiter <bjesuiter@gmail.com>
Closes #842

Co-authored-by: Benjamin Jesuiter <bjesuiter@gmail.com>
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

bumpy-frog

The changes in this PR will be included in the next version bump.

minor Minor releases

  • @varlock/native-helper-darwin 1.23.0 → 1.24.0
  • @varlock/native-helper-linux-arm64 1.23.0 → 1.24.0
  • @varlock/native-helper-linux-x64 1.23.0 → 1.24.0
  • @varlock/native-helper-win32-x64 1.23.0 → 1.24.0
  • varlock 1.23.0 → 1.24.0

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

📦 Bundle size

⚠️ grows the bundle by 11.2 KB (+0.2%)

Metric main This PR Δ
Total dist 5078.8 KB 5090.0 KB +11.2 KB (+0.2%)
JS 1921.7 KB 1925.5 KB +3.8 KB (+0.2%)
Sourcemaps 3026.4 KB 3033.8 KB +7.4 KB (+0.2%)
Type defs 130.7 KB 130.7 KB —
Other 0.0 KB 0.0 KB —

dist/ only; native binaries are versioned separately and not counted here.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
varlock-website 1ac0019 Commit Preview URL

Branch Preview URL
Oct 15 2026, 06:19 AM

@pkg-pr-new

pkg-pr-new Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

varlock

npm i https://pkg.pr.new/varlock@1231

@varlock/native-helper-darwin

npm i https://pkg.pr.new/@varlock/native-helper-darwin@1231

@varlock/native-helper-linux-arm64

npm i https://pkg.pr.new/@varlock/native-helper-linux-arm64@1231

@varlock/native-helper-linux-x64

npm i https://pkg.pr.new/@varlock/native-helper-linux-x64@1231

@varlock/native-helper-win32-x64

npm i https://pkg.pr.new/@varlock/native-helper-win32-x64@1231

commit: 1ac0019

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The opt-in smoke suites share a daemon but run in parallel, so their reset hooks can interrupt each other's requests.

Reviewed changes: Reviewed the keychain deletion flow, smoke-test setup and cleanup, documentation, and Deno peer allowlists.

  • Keychain deletion: Adds the CLI command, typed IPC client method, Swift handler, and missing-item error reporting.
  • Keychain smoke coverage: Adds opt-in set/delete and import/readback suites with signature preflight and fixture cleanup.
  • Deno daemon access: Allows Deno executable names alongside Node and Bun on macOS, Linux, and Windows.
  • User guidance: Documents deletion and persistent access permission for externally created items.

Build and targeted unit tests passed (17 passed, 6 skipped). Real macOS Keychain behavior could not be exercised on this Linux runner.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread smoke-tests/package.json
"test": "vitest run",
"test:watch": "vitest"
"test:watch": "vitest",
"test:keychain": "VARLOCK_RUN_KEYCHAIN_SMOKE=1 vitest run tests/keychain-set.test.ts tests/keychain-import.test.ts"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Both files run in parallel by default, but their beforeEach/afterEach hooks call resetVarlockDaemon() against the same user daemon. One worker can therefore kill the helper and unlink its socket while the other is importing, reading back a secret, or running signature preflight, making this smoke command fail intermittently even when the implementation works.

Technical details
# Shared daemon reset races between smoke suites

## Affected sites
- `smoke-tests/package.json:10`: launches both keychain test files without disabling file parallelism.
- `smoke-tests/tests/keychain-set.test.ts:32-40`: resets the shared daemon before and after every test.
- `smoke-tests/tests/keychain-import.test.ts:47-57`: resets the same daemon before and after its test.
- `smoke-tests/helpers/keychain-daemon.ts:18-49`: sends SIGTERM and unconditionally removes the shared PID, info, socket and lock paths.

## Required outcome
- Keychain suites must not reset a daemon that another suite is using, both for `test:keychain` and when opted in via `VARLOCK_RUN_KEYCHAIN_SMOKE=1` with the ordinary test command.

## Suggested approach
- Serialize the opted-in keychain run in the Vitest configuration, or isolate each suite's daemon state and propagate that configuration to every child command and reset hook. Merely using separate keychain service names does not isolate the daemon.
- Vitest documents `fileParallelism` as true by default: https://vitest.dev/config/fileparallelism
- Confirm both suites complete together on macOS without connection interruptions.

Report missing, access-denied and ambiguous items separately, each with the
exact command that fixes it. Also stop the helper from reporting an
access-denied generic item as "not found", and restart the daemon once per
smoke-test file instead of per test to cut Touch ID prompts.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The new access-denied guidance can suggest a command that fails validation or targets a different Keychain service.

Reviewed changes: Reviewed the updates since the prior review, with emphasis on error propagation and recovery-command correctness.

  • Improved read errors: Distinguished missing, inaccessible, and ambiguous items and added ref-specific recovery guidance.
  • Preserved Swift failures: Limited internet-password fallback to missing generic items and classified canceled access prompts as access denied.
  • Reduced daemon resets: Moved smoke-suite resets to file-level hooks and asserted missing-item guidance through load.
  • Simplified deletion wording: Removed generic-password terminology from the command description and docs.

The varlock build and targeted unit tests passed (17 passed, 6 skipped). Real macOS Keychain behavior could not be exercised on this Linux runner.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

throw new ResolutionError(`Varlock is not allowed to read this Keychain item: ${(err as Error).message}`, {
tip: [
'Grant access with:',
` varlock keychain fix-access ${refFlags}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Only suggest fix-access when the command preserves the lookup target. For a valid service-only ref such as keychain("com.company.db"), this prints varlock keychain fix-access --service com.company.db, which immediately fails with Missing --account for keychain fix-access; for an account-only ref, the printed command silently defaults the service to varlock rather than fixing the item found by the original cross-service lookup.

Technical details
# Recovery commands for incomplete refs

## Affected sites
- `packages/varlock/src/lib/local-encrypt/keychain-resolver.ts:178-184`: emits a fix-access command for every password access denial, including service-only and account-only refs.
- `packages/varlock/src/cli/commands/keychain.command.ts:460-471`: requires an account and forwards the CLI service.
- `packages/varlock/src/cli/commands/keychain.command-spec.ts:27-34`: defaults the service to varlock.

## Required outcome
- Suggested commands must be accepted by the CLI and identify the same item as the failing ref.
- When the ref lacks identifiers needed by fix-access, direct the user to discover and supply those identifiers instead of presenting an incorrect executable command.

## Suggested approach
- Gate the exact fix-access command on both service and account, as the missing-item set suggestion already does; provide discovery or disambiguation guidance otherwise.
- Cover accessDenied for service-only, account-only, and fully specified refs in resolver tests.

keychain("svc", account="x") ignored the positional service and could
return another service's item; keychain("svc", keychain="y") ignored
the keychain arg. Positional service now combines with named args, and
non-static or duplicate args are schema errors.

Docs: fix the invalid field="password" example (field only returns
metadata), correct the list filter description, replace the fallback()
advice for non-Mac teammates, update troubleshooting for the new error
messages, and add a short section on sharing committed refs.
@theoephraim theoephraim changed the title Keychain smoke tests, keychain delete, and Deno daemon access Keychain fixes, docs, smoke tests, and keychain delete Oct 15, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No new issues found in this delta. Previously reported concerns remain open, so this is not an approval.

Reviewed changes: Reviewed the resolver argument fix and documentation updates since 98252e3f.

  • Fixed mixed arguments: Preserved the positional service when combined with named account, keychain, or metadata field arguments.
  • Validated lookup arguments: Rejected duplicate service specifications, extra positional arguments, and non-static or non-string named lookup arguments.
  • Corrected user guidance: Clarified metadata fields, non-macOS limitations, list filtering, profile defaults, access management, and sharing committed refs across developers.

The varlock build and targeted unit tests passed (17 passed, 6 skipped). Direct resolver argument checks passed with a simulated macOS platform; real macOS Keychain behavior could not be exercised on this Linux runner.

Pullfrog  | Fix it ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

allowMissing=true resolves to empty when the item is missing or the
machine is not a Mac, so fallback() can move to the next source. Other
failures (access denied, cancelled prompt, daemon errors) still error.
Checking the platform at resolve time means a keychain() in an if()
branch that does not run no longer breaks the schema on Linux/Windows.
Docs cover the three patterns for non-Mac teammates.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No new issues found in this delta. Previously reported concerns remain open, so this is not an approval.

Reviewed changes: Reviewed the optional Keychain lookup behavior and platform-check changes since 3d766a16.

  • Added optional lookups: Introduced allowMissing=true for missing items and non-macOS hosts while preserving other failures.
  • Deferred platform validation: Moved the macOS check to resolution so untaken if() branches can contain Keychain refs.
  • Added regression coverage: Tested non-macOS fallback, conditional branches, resolution errors, and duplicate service arguments.
  • Documented alternative sources: Explained optional fallback, OS branching, and developer-local overrides.

The varlock build and targeted tests passed (21 passed, 6 skipped). Simulated macOS checks verified missing-item handling and preservation of other errors; real macOS Keychain behavior could not be exercised on this Linux runner.

Pullfrog  | Fix it ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Running on another OS is no longer treated as missing; use an if() on
$VARLOCK_OS or a per-developer .env.local for that. Keeps the meaning in
line with the plugins and @import, and keeps the actionable "run keychain
set" error for Mac users who have not stored the item.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No new issues found in this delta. Previously reported concerns remain open, so this is not an approval.

Reviewed changes: Reviewed the allowMissing contract correction since 6014727a.

  • Narrowed optional lookups: Kept allowMissing=true limited to missing items; unsupported platforms now fail before evaluating that argument.
  • Updated regression coverage: Asserted that non-macOS fallback still errors with allowMissing=true and that platform guidance recommends OS branching.
  • Aligned documentation: Separated cross-platform alternatives from optional-item fallback and corrected the reference and release description.

The varlock build and targeted tests passed (21 passed, 6 skipped). Real macOS Keychain behavior could not be exercised on this Linux runner.

Pullfrog  | Fix it ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow Deno as a VarlockEnclave IPC client

1 participant