Files
arca/PLAN.md
Kyle Isom ea7e09bdfb M1: make mount/unmount idempotent
mount now detects already-unlocked and already-mounted devices, returning
the existing mount point instead of failing. unmount handles already-locked
devices gracefully and skips unmount if not mounted before locking.

Adds IsMounted helper to udisks client. Updates PLAN.md with refined
v1.0.0 milestones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 07:58:25 -07:00

4.4 KiB

arca — v1.0.0 Plan

Current State (v0.1.0)

Working proof of concept. FIDO2 unlock via cryptsetup with passphrase fallback, privileged mount/unmount, config aliases with method sequencing, init and status commands.

M1: Idempotent mount/unmount

mount and unmount should be safe to run at any point in a device's lifecycle without producing confusing errors.

Files changed

  • cmd/mount.go
  • cmd/unmount.go
  • internal/udisks/client.go

Work

  1. In runMount, after FindDevice, check if the device is already unlocked (CleartextDevice succeeds). If the cleartext device is already mounted, print the existing mount point and return success. If unlocked but not mounted, skip unlock and go straight to mount.

  2. In runUnmount, handle each failure case:

    • CleartextDevice fails (already locked): print "already locked" and return success.
    • Unmount fails because not mounted: proceed to lock anyway.
    • Lock fails because already locked: return success.
  3. Add client.IsMounted(dev) helper that returns (mountpoint, bool) to reduce duplicated mount-point checking logic.


M2: Error messages

Replace generic D-Bus errors with actionable messages.

Files changed

  • internal/udisks/client.go
  • cmd/mount.go, cmd/unmount.go, cmd/init.go, cmd/status.go

Work

  1. Wrap the dbus.SystemBus() error in NewClient to detect "connection refused" or "no such file" and print: "cannot connect to udisks2 — is the udisks2 service running?"

  2. In FindDevice, when no device matches, include what was searched and suggest arca status or arca init: "device /dev/sda1 not found (run 'arca status' to list devices)"

  3. In the unlock sequencer, prefix each method error with context: "fido2: cryptsetup open --token-only: exit status 5 (is the FIDO2 key plugged in?)"


M3: Unit tests

Cover pure logic that doesn't need D-Bus or real devices.

Files changed

  • internal/config/config_test.go (new)
  • internal/cryptsetup/cryptsetup_test.go (new)

Work

  1. config_test.go — test cases:

    • ResolveDevice with exact alias match
    • ResolveDevice with device path match (/dev/sda1 -> sda1)
    • ResolveDevice with unknown name returns default methods
    • ResolveDevice with empty methods list defaults to [passphrase]
    • AliasFor finds alias by UUID
    • AliasFor returns "" for unknown UUID
    • Load with nonexistent file returns empty config
    • Load with valid YAML parses correctly
  2. cryptsetup_test.go — test cases:

    • MapperName("/dev/sda1") == "arca-sda1"
    • MapperName("/dev/nvme0n1p2") == "arca-nvme0n1p2"
    • hasTokenPlugins with a temp dir containing a matching .so
    • hasTokenPlugins with an empty temp dir

M4: CLI polish

Small usability improvements.

Files changed

  • cmd/root.go
  • cmd/mount.go
  • cmd/init.go
  • main.go
  • .gitignore (new)

Work

  1. Add var version = "dev" to main.go. Set rootCmd.Version in cmd/root.go. Build with -ldflags "-X main.version=..." in flake.nix.

  2. Add --mountpoint / -m flag to mount subcommand. When set, pass it to cryptsetup.Mount (privileged path) or log a warning that udisks2 doesn't support custom mount points.

  3. In init, use first 8 chars of UUID as alias instead of device path basename. Example: b8b2f8e3 instead of sda1. UUIDs are stable across boots; device paths are not.

  4. Create .gitignore containing /arca.


M5: Documentation and packaging

Make the project installable and the README trustworthy.

Files changed

  • README.md
  • flake.nix

Work

  1. Update README.md:

    • Replace placeholder UUIDs with realistic examples from actual tested usage.
    • Add "NixOS notes" section documenting the LD_LIBRARY_PATH requirement for FIDO2/TPM2 and why --external-tokens-path doesn't work.
    • Add "Troubleshooting" section: no FIDO2 token enrolled, udisks2 not running, permission denied on mount.
    • Document init subcommand.
  2. Verify flake.nix:

    • Run nix build and confirm it produces a working binary.
    • Add -ldflags for version injection from self.rev or a version variable.
    • Test the flake output: ./result/bin/arca --version.
  3. Tag v1.0.0.


Non-goals for v1.0.0

  • --dry-run flag
  • --json output for status
  • udev auto-mount on plug
  • Keyfile creation/management
  • Multiple config files or config includes