{"id":50994641,"url":"https://github.com/koudis/luks-automount","last_synced_at":"2026-06-20T07:31:55.869Z","repository":{"id":359835048,"uuid":"1244797743","full_name":"koudis/luks-automount","owner":"koudis","description":"Automount of LUKS encrypted USB devices","archived":false,"fork":false,"pushed_at":"2026-05-23T16:47:50.000Z","size":72,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T18:23:23.964Z","etag":null,"topics":["automount","automounter","automounting-usb-drives","luks","luks-encryption","luks2"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/koudis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-20T15:54:16.000Z","updated_at":"2026-05-23T16:47:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/koudis/luks-automount","commit_stats":null,"previous_names":["koudis/luks-automount"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/koudis/luks-automount","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koudis%2Fluks-automount","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koudis%2Fluks-automount/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koudis%2Fluks-automount/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koudis%2Fluks-automount/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/koudis","download_url":"https://codeload.github.com/koudis/luks-automount/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koudis%2Fluks-automount/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34561766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automount","automounter","automounting-usb-drives","luks","luks-encryption","luks2"],"created_at":"2026-06-20T07:31:55.210Z","updated_at":"2026-06-20T07:31:55.861Z","avatar_url":"https://github.com/koudis.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# luks-automount\n\nAutomatically unlocks and mounts whole-disk LUKS-encrypted USB SSDs when plugged in, and unmounts and locks them on removal. Passphrases are stored in GNOME Keyring. Privileged operations run through a short-lived worker subprocess invoked via `sudo`.\n\n## Usage\n\n### Register a disk\n\nPlug in the USB drive, then:\n\n```sh\nluks-automount add myusb\n```\n\nPrompts for device selection, mount point (must exist under `/mnt/`), filesystem type, mount options, and passphrase. The passphrase is stored in GNOME Keyring and never written to disk or logs.\n\n### List registered disks\n\n```sh\nluks-automount list\n```\n\n### Manually unlock / lock\n\n```sh\nluks-automount unlock myusb\nluks-automount lock myusb\n```\n\n### Run the daemon\n\n```sh\nluks-automount run\n```\n\nWatches for plug/unplug events and unlocks or locks registered disks automatically. Only one instance may run at a time.\n\n### Install\n\nThe user service cannot answer `sudo` password prompts. Run the installer from the built binary before enabling normal daemon use.\n\n```sh\nluks-automount install\n```\n\nThe command can install the binary to `/usr/local/bin/luks-automount`, write the sudoers drop-in, write `~/.config/systemd/user/luks-automount.service`, and enable it immediately. If a busy-mount warning does not appear from the user service, make sure the installed service file is current and restart it with `systemctl --user daemon-reload` and `systemctl --user restart luks-automount.service`.\n\n```sh\nluks-automount uninstall\n```\n\nThe command can disable and remove `~/.config/systemd/user/luks-automount.service`, remove `/etc/sudoers.d/luks-automount`, and remove `/usr/local/bin/luks-automount`.\n\n### Remove a disk registration\n\n```sh\nluks-automount lock myusb          # unmount first if mounted\nluks-automount remove myusb\n```\n\n## Requirements\n\n- Linux with device-mapper, `/dev/mapper`, block-device UEvent support, and mount support\n- A graphical user session with GNOME Keyring or another compatible Secret Service implementation\n- `sudo` installed and configured to allow the user to run `luks-automount worker` as root\n- Mount points created under `/mnt/` before registering a disk\n\n### Runtime requirements\n\n- The hidden `worker` subcommand must be executable through `sudo`\n- The user session must provide access to the Secret Service API so stored passphrases can be read\n- `install` and `uninstall` require a user `systemd` instance\n- The program validates mount points under `/mnt/`; bare `/mnt` and paths containing `..` are rejected\n- Busy-mount warnings use `zenity` when the graphical session is available\n\n### Build requirements\n\n- Go 1.26 or newer\n- A Linux system matching the runtime requirements above\n\n### External tools and services\n\n- Required for normal operation:\n  - `sudo`\n  - `cryptsetup`\n  - `systemctl` for `install` and `uninstall`\n  - GNOME Keyring or another Secret Service provider\n- Required for the integration smoke test:\n  - `dd`\n  - `losetup`\n  - `mkfs.ext4`\n  - root privileges\n  - a host or VM with working loop devices\n\n## Build\n\n```sh\ngo build -o luks-automount ./cmd/luks-automount\n```\n\nInstall the tool, user service, and sudoers rule:\n\n```sh\n./luks-automount install\n```\n\nThe installer asks for confirmation before each step. Root access is requested through `sudo` only for installing `/usr/local/bin/luks-automount` and `/etc/sudoers.d/luks-automount`.\n\n## sudo configuration\n\nThe installer writes this rule so the user service can run the worker without a password prompt:\n\n```\n# /etc/sudoers.d/luks-automount\nyouruser ALL=(root) NOPASSWD: /usr/local/bin/luks-automount worker\n```\n\nIf you manage sudoers manually, validate changes with `visudo` and keep the path equal to `/usr/local/bin/luks-automount`.\n\n## Maintenance\n\n### Changing requirements\n\nEdit `doc/requirements.md` first. All functional decisions are recorded there. Review for contradictions before touching any code.\n\n### Changing code\n\nThe main packages and their responsibilities:\n\n| Package | Responsibility |\n|---|---|\n| `internal/config` | TOML config, disk struct, validation |\n| `internal/keyring` | GNOME Keyring passphrase storage |\n| `internal/logging` | slog fan-out: stderr (text) + rotating JSON file |\n| `internal/monitor` | Netlink UEvent listener |\n| `internal/luks` | LUKS UUID read, unlock, lock |\n| `internal/worker` | Privileged worker protocol (server + client) |\n| `internal/engine` | Daemon orchestrator, per-disk state machine |\n| `cmd/luks-automount` | CLI (cobra subcommands) |\n\n### Running tests\n\nAutomated test targets:\n\n- `go test ./...`\n  - runs the regular unit and package tests\n  - covers config validation, CLI command behavior, daemon state transitions,\n    worker protocol handling, logging helpers, monitor logic, and the\n    mount-point-busy flow\n- `go test ./internal/dialog ./cmd/luks-automount`\n  - useful as a quick focused check when changing the GNOME warning dialog,\n    service installation, or CLI lock behavior\n- `go vet ./...`\n  - runs static checks across the whole project\n\nMakefile shortcuts:\n\n- `make test` runs `go test ./...`\n- `make vet` runs `go vet ./...`\n- `make test-integration` runs the privileged worker smoke test\n\n```sh\ngo test ./...\n```\n\nThe integration smoke test verifies the real worker path with privileged\noperations. It requires root and a kernel with loop-device support (bare metal\nor a VM, not a container):\n\n```sh\ngo test -tags integration -c -o /tmp/worker.test ./internal/worker/\nsudo /tmp/worker.test -test.run TestSmoke_WorkerProtocol -test.v\n```\n\nFor the mount-point-busy behavior, also do a manual graphical smoke test after\nchanging the dialog or user-service integration:\n\n1. Mount a configured disk.\n2. Keep a shell or another app open inside the mount point.\n3. Run `luks-automount lock \u003cname\u003e` or trigger daemon auto-lock.\n4. Confirm the unmount is blocked and the GNOME warning appears.\n5. Close the blocking app and retry.\n\n## License\n\nThis project is licensed under the Apache License 2.0. See `LICENSE`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkoudis%2Fluks-automount","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkoudis%2Fluks-automount","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkoudis%2Fluks-automount/lists"}