feat: tailscale - #381
Conversation
|
You do not have enough credits to review this pull request. Please purchase more credits to continue. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughThis PR introduces Tailscale integration into the dotfiles repository by adding a new Home Manager module with configurable systemd services, documenting Tailscale setup procedures, configuring the module for the galactica host, reorganizing package dependencies, and managing encrypted authentication secrets. Changes
Sequence Diagram(s)sequenceDiagram
participant HM as Home Manager
participant Act as Activation Script
participant FS as Filesystem
participant SD as Systemd
participant TS as Tailscale Daemon
HM->>Act: Trigger home activation on deploy
Act->>FS: Create state/run directories with permissions
FS-->>Act: Directories ready
Act->>SD: Enable/start tailscaled service
SD->>TS: Launch tailscaled daemon
TS->>FS: Bind to socket (tailscaled.sock)
TS-->>SD: Service started
SD-->>HM: Activation complete
HM->>SD: Start tailscale-up one-shot service
SD->>TS: Execute 'tailscale up' with auth key & flags
TS-->>SD: Authentication and configuration applied
SD-->>HM: Service chain initialized
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @shunkakinoki, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new feature to integrate Tailscale VPN into the dotfiles repository. It provides a declarative Home Manager module for managing the Tailscale service, along with comprehensive documentation covering its setup, configuration, and usage. The changes also include secure handling of Tailscale authentication keys using Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new home-manager module for Tailscale, which is a great addition for managing VPN configuration declaratively. The changes are well-structured, including comprehensive documentation and integration with agenix for secret management.
However, I've found several issues in the new tailscale module that need to be addressed:
- A critical bug in the module's logic prevents the Tailscale services from being enabled by default, even when
services.tailscale.enable = true. - The module hardcodes paths for the
tailscaleddaemon, ignoring the configuration options provided. - The
tailscaleCLI commands are missing the required socket path, which will cause them to fail to connect to the daemon. - The logic for handling authentication keys is redundant and can be simplified.
I've provided specific comments and suggestions to fix these issues in the home-manager/modules/tailscale/default.nix file. I've also noted a couple of minor points in the new documentation file.
Once these issues are resolved, this will be a solid contribution.
| cfg = config.modules.tailscale; | ||
|
|
||
| # Check if configuration is enabled | ||
| configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null); |
There was a problem hiding this comment.
The logic for configEnabled is incorrect. It is defined as (cfg.serviceConfig != { } && cfg.serviceConfig != null), which evaluates to false if serviceConfig is not set (as it defaults to {}). This variable is then used with mkIf on lines 108 and 126, preventing the tailscaled and tailscale-up services from being created even when modules.tailscale.enable is true. This makes the module non-functional by default.
To fix this, you should remove the configEnabled variable entirely (lines 13-14), and remove the mkIf configEnabled wrappers from the service definitions on lines 108 and 126. The mkIf cfg.enable on line 100 is sufficient.
| }; | ||
|
|
||
| Service = { | ||
| ExecStart = "${pkgs.tailscale}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; |
There was a problem hiding this comment.
The ExecStart command for the tailscaled service hardcodes paths and the package, ignoring the module's options. This prevents customization of the package version, state directory, and socket path. The command should use the values from the module's options to allow for proper configuration.
ExecStart = "${cfg.tailscaled.package}/bin/tailscaled --state=${cfg.tailscaled.stateDir}/tailscaled.state --socket=${cfg.tailscaled.socketPath}";
| Service = { | ||
| Type = "oneshot"; | ||
| RemainAfterExit = true; | ||
| ExecStart = "${pkgs.bash}/bin/bash -c ' | ||
| # Determine auth key | ||
| AUTH_KEY=" " | ||
| if [ -n \"${cfg.authKey}\" ]; then | ||
| AUTH_KEY=\"${cfg.authKey}\" | ||
| elif [ -n \"${cfg.authKeyFile}\" ] && [ -f \"${cfg.authKeyFile}\" ]; then | ||
| AUTH_KEY=$(cat \"${cfg.authKeyFile}\") | ||
| fi | ||
|
|
||
| # Configure Tailscale with specified options | ||
| tailscale up \ | ||
| ${ | ||
| optionalString (cfg.authKey != "") "--authkey=${cfg.authKey}" | ||
| } \ | ||
| ${ | ||
| optionalString (cfg.authKeyFile != "") "--authkey=$AUTH_KEY" | ||
| } \ | ||
| ${optionalString cfg.acceptRoutes "--accept-routes"} \ | ||
| ${optionalString cfg.advertiseExitNode "--advertise-exit-node"} \ | ||
| ${ | ||
| optionalString (cfg.useExitNode != "") "--exit-node=${cfg.useExitNode}" | ||
| } \ | ||
| ${concatStringsSep " " cfg.extraUpArgs}'"; | ||
| ExecStop = "${pkgs.tailscale}/bin/tailscale down"; | ||
| }; |
There was a problem hiding this comment.
The tailscale-up service definition has a few issues:
- Missing socket path: The
tailscale upandtailscale downcommands are missing the socket path. Sincetailscaledis started with a custom socket, the CLI needs to be told where to find it via the--socketflag. - Hardcoded package: The
tailscalepackage is hardcoded, but it should usecfg.tailscaled.packageto be consistent with the rest of the module. - Redundant auth key logic: The logic for providing the
--authkeyis duplicated. If bothauthKeyandauthKeyFileare provided, it results in two--authkeyflags being passed to the command.
Here is a suggested replacement that fixes these issues and simplifies the logic:
Service = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${pkgs.bash}/bin/bash -c '\n # Determine auth key argument\n AUTH_KEY_ARG=\"\"\n if [ -n \"${cfg.authKey}\" ]; then\n AUTH_KEY_ARG=\" --authkey=${cfg.authKey}\"\n elif [ -n \"${cfg.authKeyFile}\" ] && [ -f \"${cfg.authKeyFile}\" ]; then\n AUTH_KEY_ARG=\" --authkey=$(cat \"${cfg.authKeyFile}\")\"\n fi\n\n # Configure Tailscale with specified options\n ${cfg.tailscaled.package}/bin/tailscale --socket ${cfg.tailscaled.socketPath} up \\$AUTH_KEY_ARG ${lib.optionalString cfg.acceptRoutes "--accept-routes"} ${lib.optionalString cfg.advertiseExitNode "--advertise-exit-node"} ${lib.optionalString (cfg.useExitNode != "") "--exit-node=${cfg.useExitNode}"} ${lib.concatStringsSep " " cfg.extraUpArgs}\n '";
ExecStop = "${cfg.tailscaled.package}/bin/tailscale --socket ${cfg.tailscaled.socketPath} down";
};
| **Solutions**: | ||
| ```bash | ||
| # Check if auth key is properly decrypted | ||
| ls -la /run/agenix/keys/tailscale-auth.age |
There was a problem hiding this comment.
The command to check if the auth key is properly decrypted seems incorrect. The decrypted secret file managed by agenix will likely not have the .age extension. The command should probably check for the file without this extension.
| ls -la /run/agenix/keys/tailscale-auth.age | |
| ls -la /run/agenix/keys/tailscale-auth |
| - **Secrets**: `named-hosts/galactica/secrets.nix` | ||
| - **Auth Key**: `named-hosts/galactica/keys/tailscale-auth.age` (encrypted) | ||
| - **State**: `~/.local/share/tailscale/` | ||
| - **Logs**: `~/.local/share/tailscale/*.log` No newline at end of file |
There was a problem hiding this comment.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on December 27
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
| "--reset" | ||
| "--accept-dns=false" | ||
| ]; | ||
| }; |
There was a problem hiding this comment.
Bug: Configuration namespace mismatch prevents module usage
The module defines options under modules.tailscale but the configuration and documentation reference services.tailscale. This namespace mismatch prevents the Tailscale configuration from being recognized, causing the module to not work at all.
Additional Locations (2)
| cfg = config.modules.tailscale; | ||
|
|
||
| # Check if configuration is enabled | ||
| configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null); |
There was a problem hiding this comment.
Bug: Services won't start without serviceConfig override
The configEnabled variable checks if serviceConfig is non-empty, but systemd services are only created when configEnabled is true. This means enabling Tailscale without providing a serviceConfig override prevents the services from being created at all. The condition should check cfg.enable instead.
| RemainAfterExit = true; | ||
| ExecStart = "${pkgs.bash}/bin/bash -c ' | ||
| # Determine auth key | ||
| AUTH_KEY=" " |
There was a problem hiding this comment.
| } \ | ||
| ${ | ||
| optionalString (cfg.authKeyFile != "") "--authkey=$AUTH_KEY" | ||
| } \ |
There was a problem hiding this comment.
| }; | ||
|
|
||
| Service = { | ||
| ExecStart = "${pkgs.tailscale}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; |
There was a problem hiding this comment.
Bug: Configurable package option ignored in service commands
The service commands hardcode ${pkgs.tailscale} instead of using the configurable cfg.tailscaled.package option. This makes the tailscaled.package option non-functional, preventing users from specifying a custom Tailscale package version.
Additional Locations (1)
| }; | ||
|
|
||
| Service = { | ||
| ExecStart = "${pkgs.tailscale}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; |
There was a problem hiding this comment.
Bug: Configurable paths ignored in service configuration
The ExecStart command hardcodes state and socket paths instead of using cfg.tailscaled.stateDir and cfg.tailscaled.socketPath options. This renders these configuration options useless, preventing users from customizing the state directory or socket path locations.
| fi | ||
|
|
||
| # Configure Tailscale with specified options | ||
| tailscale up \ |
There was a problem hiding this comment.
Bug: Tailscale command missing full path in script
The tailscale up command uses a bare tailscale without a full path. In systemd services, the PATH may not include the Tailscale binary location, causing the command to fail. It should use ${pkgs.tailscale}/bin/tailscale or ${cfg.tailscaled.package}/bin/tailscale.
| // cfg.serviceConfig.service or { }; | ||
|
|
||
| Install.WantedBy = [ "default.target" ]; | ||
| }; |
There was a problem hiding this comment.
Bug: Module only supports Linux but targets macOS
The module creates only systemd services, but the galactica host is macOS (aarch64-darwin). macOS doesn't have systemd, so the services won't be created or run. The documentation mentions launchd for macOS, but the implementation lacks launchd support, making the module non-functional on the target platform.
Additional Locations (1)
|
|
||
| # Declare directories and files for home-manager | ||
| home.file.".local/share/tailscale/tailscaled.state".source = | ||
| config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/.local/state/tailscale/tailscaled.state"; |
There was a problem hiding this comment.
Bug: Symlink target directory not created by activation
A symlink is created from .local/share/tailscale/tailscaled.state to .local/state/tailscale/tailscaled.state, but the activation script only creates .local/share/tailscale and the runtime directory. The .local/state/tailscale directory is never created, resulting in a broken symlink that points to a non-existent location.
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
home-manager/modules/tailscale/default.nix (1)
1-8: Good module structure, but missing documentation.The module follows home-manager's module structure correctly with proper option declarations. However, as per coding guidelines, custom modules should document all options. Consider adding a module-level comment explaining the purpose and usage.
Add module documentation:
# Tailscale configuration +# This module provides user-level Tailscale VPN service management. +# +# NOTE: Currently only supports Linux via systemd. macOS support requires +# manual Tailscale installation or extending this module with launchd agents. +# +# Example usage: +# modules.tailscale = { +# enable = true; +# authKeyFile = config.age.secrets."tailscale-auth".path; +# }; {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
Makefile(1 hunks)docs/TAILSCALE.md(1 hunks)home-manager/modules/default.nix(1 hunks)home-manager/modules/tailscale/default.nix(1 hunks)home-manager/packages/default.nix(1 hunks)named-hosts/galactica/default.nix(1 hunks)named-hosts/galactica/keys/tailscale-auth.age(1 hunks)named-hosts/galactica/secrets.nix(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.nix
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.nix: Use nixfmt for formatting all Nix files
Document complex configurations with comments in Nix files
**/*.nix: Use 2 spaces for indentation in Nix files
Keep line length under 100 characters in Nix files
Sort attribute sets alphabetically in Nix files
Use consistent spacing around operators in Nix files
Format lists and sets consistently in Nix filesUse treefmt.toml for formatting Nix files
**/*.nix: UsemkOptionfor configurable options in Nix modules
Implement proper typing for all options in Nix modules
Follow the Nix expression language style guide
Files:
named-hosts/galactica/secrets.nixnamed-hosts/galactica/default.nixhome-manager/modules/default.nixhome-manager/modules/tailscale/default.nixhome-manager/packages/default.nix
**/*.{js,jsx,ts,tsx,json,jsonc,md}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Use Biome for code formatting as configured in biome.json
Files:
docs/TAILSCALE.md
**/default.nix
📄 CodeRabbit inference engine (CLAUDE.md)
Use
default.nixfiles for module exports
Files:
named-hosts/galactica/default.nixhome-manager/modules/default.nixhome-manager/modules/tailscale/default.nixhome-manager/packages/default.nix
home-manager/modules/**/default.nix
📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)
Custom modules should include proper option types and document all options
Each module in
home-manager/modules/should have a cleardefault.nixwith proper option declarations following the home-manager module structure
Files:
home-manager/modules/default.nixhome-manager/modules/tailscale/default.nix
home-manager/**/*.nix
📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)
home-manager/**/*.nix: Use typed options whenever possible in Nix configurations
Document all configuration options in Nix modules and programs
Follow home-manager's module structure and keep configurations modular
Use proper indentation and formatting in Nix configuration files
Files:
home-manager/modules/default.nixhome-manager/modules/tailscale/default.nixhome-manager/packages/default.nix
home-manager/modules/**/*.nix
📄 CodeRabbit inference engine (.cursor/rules/nix.mdc)
Document all custom modules and options
Files:
home-manager/modules/default.nixhome-manager/modules/tailscale/default.nix
home-manager/modules/*/default.nix
📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)
Custom modules must be located in
home-manager/modules/<name>/and must include adefault.nixfile
Files:
home-manager/modules/tailscale/default.nix
🧠 Learnings (22)
📓 Common learnings
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/services/**/*.nix : Service configurations in `home-manager/services/` should follow systemd service conventions, include proper service dependencies, and have clear documentation for service parameters
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Document all major changes in Nix configurations
Applied to files:
docs/TAILSCALE.mdhome-manager/packages/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Document all configuration options in Nix modules and programs
Applied to files:
docs/TAILSCALE.mdnamed-hosts/galactica/default.nixhome-manager/modules/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:23.224Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:34:23.224Z
Learning: Run `make format` before committing code
Applied to files:
Makefile
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Test configurations before committing using `nix flake check` and `home-manager build --show-trace`
Applied to files:
Makefile
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Applies to flake.nix : Maintain flake.nix as the main Nix configuration with proper structure
Applied to files:
Makefile
📚 Learning: 2025-11-25T09:34:47.854Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/github-workflows.mdc:0-0
Timestamp: 2025-11-25T09:34:47.854Z
Learning: Applies to .github/workflows/*.yml : CI Pipeline must run on all pull requests and main branch pushes, validating Nix flake checks, home-manager builds, nix-darwin builds, and system configurations
Applied to files:
Makefile
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Test Nix and home-manager configurations locally before pushing using `make test`
Applied to files:
Makefile
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/**/default.nix : Service configurations must include proper service definitions, handle dependencies correctly, and document service parameters
Applied to files:
named-hosts/galactica/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/*/default.nix : Service configurations should be located in `home-manager/services/<name>/` with proper service definitions and correct dependency handling
Applied to files:
named-hosts/galactica/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/services/**/*.nix : Service configurations in `home-manager/services/` should follow systemd service conventions, include proper service dependencies, and have clear documentation for service parameters
Applied to files:
named-hosts/galactica/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/*.nix : Follow program-specific best practices in program configuration files
Applied to files:
named-hosts/galactica/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Keep configurations modular across home-manager, hosts, and nix-darwin directories
Applied to files:
named-hosts/galactica/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/modules/*/default.nix : Custom modules must be located in `home-manager/modules/<name>/` and must include a `default.nix` file
Applied to files:
home-manager/modules/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Follow home-manager's module structure and keep configurations modular
Applied to files:
home-manager/modules/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/modules/**/*.nix : Document all custom modules and options
Applied to files:
home-manager/modules/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/modules/**/default.nix : Each module in `home-manager/modules/` should have a clear `default.nix` with proper option declarations following the home-manager module structure
Applied to files:
home-manager/modules/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:23.224Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:34:23.224Z
Learning: Applies to **/default.nix : Use `default.nix` files for module exports
Applied to files:
home-manager/modules/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/*/default.nix : Program configurations should be located in `home-manager/programs/<name>/` and use home-manager's built-in modules when available
Applied to files:
home-manager/modules/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/modules/**/default.nix : Custom modules should include proper option types and document all options
Applied to files:
home-manager/modules/default.nixhome-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Use typed options whenever possible in Nix configurations
Applied to files:
home-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/default.nix : Program configurations must include all necessary dependencies in their configuration
Applied to files:
home-manager/packages/default.nix
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: Mesa Description
- GitHub Check: Agent
- GitHub Check: cubic · AI code reviewer
- GitHub Check: nix-nixos
- GitHub Check: nix-linux
- GitHub Check: docker-build-push (linux/amd64, amd64, ubuntu-latest)
- GitHub Check: docker-build-push (linux/arm64, arm64, ubuntu-24.04-arm)
- GitHub Check: e2e-run (Ubuntu, ubuntu-latest)
- GitHub Check: e2e-run (MacOS, macos-latest)
- GitHub Check: e2e-run (NixOS, ubuntu-latest)
- GitHub Check: lua-neovim
- GitHub Check: lua-hammerspoon
- GitHub Check: Cursor Bugbot
🔇 Additional comments (7)
Makefile (1)
125-125: LGTM!Minor formatting improvement that adds visual separation between the
checkandflake-checktargets.home-manager/modules/default.nix (1)
1-5: LGTM!The new
./tailscalemodule is correctly added to the imports list and maintains alphabetical ordering. As per coding guidelines, custom modules should be located inhome-manager/modules/<name>/with adefault.nixfile.home-manager/packages/default.nix (1)
67-67: LGTM!Moving
tailscaleto the cross-platform package list enables support on both macOS (Darwin) and Linux, which aligns with the new galactica host configuration targetingaarch64-darwin.docs/TAILSCALE.md (1)
156-169: Service management commands may not match module implementation.The launchctl commands reference
homebrew.mxcl.tailscaled, which is the Homebrew-managed service name. However, the Home Manager module creates systemd user services (tailscaled.service), which won't work on macOS at all since systemd is Linux-only.Either update the module to support launchd on macOS, or clarify in the documentation that the current module only supports Linux and macOS users should install Tailscale via Homebrew or the official installer.
named-hosts/galactica/secrets.nix (1)
14-19: Secret entry correctly structured.The new
tailscale-auth.agesecret entry follows the existing pattern with proper file path and public key configuration. Note that this depends on the referenced.agefile containing valid encrypted content (see earlier comment about the placeholder file).named-hosts/galactica/default.nix (1)
62-74: I encountered a repository clone error and cannot directly access the codebase to verify the specific claims about the Tailscale module structure and configuration paths.
Unable to verify option path mismatch and platform compatibility claims due to repository access issues.
The review comment raises two specific technical concerns:
- Option path mismatch: Claims the module defines
modules.tailscalebut the config usesservices.tailscale- Platform incompatibility: Claims the module uses
systemd.user.serviceswhich is unavailable on macOS (aarch64-darwin)Without direct access to the repository, I cannot confirm whether:
- The tailscale module actually exposes options under
modules.tailscaleorservices.tailscale- The module implementation includes systemd-specific service definitions
- Platform-specific conditional logic exists for macOS/launchd support
- The galactica host is indeed configured as an aarch64-darwin system
The code snippet shown in the review (lines 62-74) uses
services.tailscale, which is a valid home-manager option path if the module exports it under that namespace. The actual validity depends on the module's internal structure.home-manager/modules/tailscale/default.nix (1)
107-123: Custom modules.tailscale is never imported or used; galactica uses home-manager's built-in services.tailscale instead.The review comment correctly identifies that
systemd.user.servicesis Linux-only, but verification shows the custommodules.tailscalemodule (lines 107-123) is never imported by any host configuration, including galactica. Galactica uses home-manager's nativeservices.tailscale(line 64 ofnamed-hosts/galactica/default.nix), which handles platform differences internally. The custom module appears to be unused code.If this custom module is intended for future use across platforms, consider adding platform-specific conditionals (
mkIf pkgs.stdenv.isLinux { ... }). Otherwise, consider clarifying its purpose or removing it.Likely an incorrect or invalid review comment.
| services.tailscale = { | ||
| enable = true; # Enable Tailscale service | ||
| acceptRoutes = false; # Accept advertised routes (default: false) | ||
| advertiseExitNode = false; # Advertise as exit node (default: false) | ||
| useExitNode = ""; # Exit node to use (default: none) | ||
| authKey = ""; # Auth key as string (alternative to authKeyFile) | ||
| authKeyFile = ""; # Path to auth key file (recommended) | ||
| extraUpArgs = [ # Additional arguments for tailscale up | ||
| "--reset" | ||
| "--accept-dns=false" | ||
| ]; | ||
| }; |
There was a problem hiding this comment.
Documentation shows incorrect option path.
The example configuration uses services.tailscale, but the actual module defines options under modules.tailscale. Update the documentation to match the module's option path.
-services.tailscale = {
+modules.tailscale = {
enable = true; # Enable Tailscale service📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| services.tailscale = { | |
| enable = true; # Enable Tailscale service | |
| acceptRoutes = false; # Accept advertised routes (default: false) | |
| advertiseExitNode = false; # Advertise as exit node (default: false) | |
| useExitNode = ""; # Exit node to use (default: none) | |
| authKey = ""; # Auth key as string (alternative to authKeyFile) | |
| authKeyFile = ""; # Path to auth key file (recommended) | |
| extraUpArgs = [ # Additional arguments for tailscale up | |
| "--reset" | |
| "--accept-dns=false" | |
| ]; | |
| }; | |
| modules.tailscale = { | |
| enable = true; # Enable Tailscale service | |
| acceptRoutes = false; # Accept advertised routes (default: false) | |
| advertiseExitNode = false; # Advertise as exit node (default: false) | |
| useExitNode = ""; # Exit node to use (default: none) | |
| authKey = ""; # Auth key as string (alternative to authKeyFile) | |
| authKeyFile = ""; # Path to auth key file (recommended) | |
| extraUpArgs = [ # Additional arguments for tailscale up | |
| "--reset" | |
| "--accept-dns=false" | |
| ]; | |
| }; |
🤖 Prompt for AI Agents
In docs/TAILSCALE.md around lines 66 to 77, the example config uses the wrong
option path `services.tailscale`; update the documentation to use the module
path `modules.tailscale` instead (replace all occurrences in that example and
any surrounding explanatory text), ensuring the option names and values remain
unchanged and any references elsewhere in the file are also adjusted to
`modules.tailscale`.
| cfg = config.modules.tailscale; | ||
|
|
||
| # Check if configuration is enabled | ||
| configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null); |
There was a problem hiding this comment.
configEnabled logic is counter-intuitive.
Services are only enabled when serviceConfig != {}, but most users will set enable = true without providing a custom serviceConfig. This means enable = true alone won't actually start the services.
Consider simplifying to always enable services when cfg.enable is true:
- # Check if configuration is enabled
- configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null);
+ # Services are enabled when the module is enabled
+ configEnabled = cfg.enable;Or if serviceConfig is meant to be required, document this clearly and consider making it mandatory.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cfg = config.modules.tailscale; | |
| # Check if configuration is enabled | |
| configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null); | |
| cfg = config.modules.tailscale; | |
| # Services are enabled when the module is enabled | |
| configEnabled = cfg.enable; |
🤖 Prompt for AI Agents
In home-manager/modules/tailscale/default.nix around lines 10 to 13, the
configEnabled check currently only enables services when serviceConfig is
non-empty which ignores cfg.enable; change the logic so services are considered
enabled when cfg.enable is true OR when a non-empty serviceConfig is provided
(e.g. configEnabled = cfg.enable || (cfg.serviceConfig != { } &&
cfg.serviceConfig != null)); alternatively, if serviceConfig must be required,
update the module to make serviceConfig mandatory and document that requirement.
| authKeyFile = mkOption { | ||
| type = types.path; | ||
| default = ""; | ||
| description = "Path to file containing Tailscale auth key (better for secrets)"; | ||
| }; |
There was a problem hiding this comment.
Invalid type for authKeyFile option.
types.path cannot have an empty string as its default value. When a user doesn't specify authKeyFile, the empty string will fail type checking.
Use types.nullOr types.path with null as default, or types.str if an empty string is intentional:
authKeyFile = mkOption {
- type = types.path;
- default = "";
+ type = types.nullOr types.path;
+ default = null;
description = "Path to file containing Tailscale auth key (better for secrets)";
};Then update the conditionals in the service definition to check for null instead of empty string.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| authKeyFile = mkOption { | |
| type = types.path; | |
| default = ""; | |
| description = "Path to file containing Tailscale auth key (better for secrets)"; | |
| }; | |
| authKeyFile = mkOption { | |
| type = types.nullOr types.path; | |
| default = null; | |
| description = "Path to file containing Tailscale auth key (better for secrets)"; | |
| }; |
🤖 Prompt for AI Agents
In home-manager/modules/tailscale/default.nix around lines 48 to 52, the
authKeyFile option uses types.path but sets default to an empty string which
fails type checking; change the option to use types.nullOr types.path with
default = null (or switch to types.str if you intend to allow an empty string),
and then update any service definition conditionals that currently test for an
empty string to instead test for null (e.g., use builtins.isNull / or compare to
null) so the option validation and runtime checks are consistent.
| Service = { | ||
| ExecStart = "${pkgs.tailscale}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; | ||
| Restart = "on-failure"; | ||
| RestartSec = 5; | ||
| } | ||
| // cfg.serviceConfig.service or { }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Inconsistent package reference.
Line 116 uses pkgs.tailscale directly instead of the configurable cfg.tailscaled.package option defined at line 21-25. This prevents users from overriding the package.
- ExecStart = "${pkgs.tailscale}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock";
+ ExecStart = "${cfg.tailscaled.package}/bin/tailscaled --state=${cfg.tailscaled.stateDir}/tailscaled.state --socket=${cfg.tailscaled.socketPath}";Also use cfg.tailscaled.stateDir and cfg.tailscaled.socketPath for consistency with the defined options.
🤖 Prompt for AI Agents
In home-manager/modules/tailscale/default.nix around lines 115 to 120, the
ExecStart line currently hardcodes pkgs.tailscale and literal paths; change it
to use the configurable options instead — reference cfg.tailscaled.package for
the tailscaled binary location and use cfg.tailscaled.stateDir and
cfg.tailscaled.socketPath for the --state and --socket arguments so users can
override the package and paths via the cfg options defined earlier.
| ExecStart = "${pkgs.bash}/bin/bash -c ' | ||
| # Determine auth key | ||
| AUTH_KEY=" " | ||
| if [ -n \"${cfg.authKey}\" ]; then | ||
| AUTH_KEY=\"${cfg.authKey}\" | ||
| elif [ -n \"${cfg.authKeyFile}\" ] && [ -f \"${cfg.authKeyFile}\" ]; then | ||
| AUTH_KEY=$(cat \"${cfg.authKeyFile}\") | ||
| fi | ||
|
|
||
| # Configure Tailscale with specified options | ||
| tailscale up \ | ||
| ${ | ||
| optionalString (cfg.authKey != "") "--authkey=${cfg.authKey}" | ||
| } \ | ||
| ${ | ||
| optionalString (cfg.authKeyFile != "") "--authkey=$AUTH_KEY" | ||
| } \ | ||
| ${optionalString cfg.acceptRoutes "--accept-routes"} \ | ||
| ${optionalString cfg.advertiseExitNode "--advertise-exit-node"} \ | ||
| ${ | ||
| optionalString (cfg.useExitNode != "") "--exit-node=${cfg.useExitNode}" | ||
| } \ | ||
| ${concatStringsSep " " cfg.extraUpArgs}'"; |
There was a problem hiding this comment.
Shell script issues in tailscale-up service.
Several problems with the ExecStart script:
- Line 138:
AUTH_KEY=" "uses a space as default, which could cause issues - Lines 148-152: Both
cfg.authKeyandcfg.authKeyFilecan produce--authkeyarguments, potentially duplicating the flag - Quoting: The nested bash script with Nix string interpolation is fragile
Consider refactoring to avoid duplicate --authkey flags:
- ${
- optionalString (cfg.authKey != "") "--authkey=${cfg.authKey}"
- } \
- ${
- optionalString (cfg.authKeyFile != "") "--authkey=$AUTH_KEY"
- } \
+ ${
+ if cfg.authKey != "" then "--authkey=${cfg.authKey}"
+ else if cfg.authKeyFile != null then "--authkey=$AUTH_KEY"
+ else ""
+ } \Also consider using pkgs.writeShellScript for cleaner script management.
| # This is a placeholder for the encrypted Tailscale auth key | ||
| # To encrypt your actual auth key, use: | ||
| # make encrypt-key-galactica KEY_FILE=/path/to/your/tailscale-auth-key.txt | ||
| # | ||
| # To get a Tailscale auth key: | ||
| # 1. Log in to https://login.tailscale.com/admin | ||
| # 2. Go to Settings -> Keys | ||
| # 3. Generate a new auth key (recommended: non-ephemeral, reusable) | ||
| # 4. Save the key to a file and encrypt it using the command above |
There was a problem hiding this comment.
Placeholder file will cause runtime failure.
This .age file contains plaintext instructions instead of encrypted content. When agenix attempts to decrypt this file during activation, it will fail because the content is not a valid age-encrypted payload. The authKeyFile reference in named-hosts/galactica/default.nix depends on this file being properly encrypted.
Either:
- Remove this placeholder and add
tailscale-auth.ageto.gitignoreuntil a real key is encrypted, or - Create an actual encrypted placeholder that can be decrypted (even if empty), or
- Gate the Tailscale configuration behind a check for the secret's existence.
🤖 Prompt for AI Agents
In named-hosts/galactica/keys/tailscale-auth.age (lines 1–9) the file contains
plaintext instructions instead of an age-encrypted payload, which will cause
agenix to fail at activation; fix by either (A) removing this plaintext file and
adding keys/tailscale-auth.age to .gitignore (and ensure
named-hosts/galactica/default.nix no longer unconditionally references the
secret), or (B) replace the file with a valid age-encrypted payload (you can
generate an encrypted empty or placeholder secret using age/age-keygen and put
the ciphertext here), or (C) change named-hosts/galactica/default.nix to gate
the Tailscale authKeyFile reference behind a file-existence/optionalSecret check
so activation won’t fail when the encrypted file is absent or invalid.
There was a problem hiding this comment.
Pull request overview
This pull request adds Tailscale VPN integration to the dotfiles repository for the galactica host (macOS). The implementation includes a new home-manager module for Tailscale configuration, encrypted authentication key management using agenix, and comprehensive documentation.
Key changes:
- Created a new home-manager module at
home-manager/modules/tailscale/default.nixwith systemd service definitions - Added Tailscale configuration to the galactica host with encrypted auth key support via agenix
- Moved the
tailscalepackage from Linux-specific to cross-platform package list
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
home-manager/modules/tailscale/default.nix |
New home-manager module defining Tailscale configuration options and systemd services (Note: systemd won't work on macOS) |
home-manager/modules/default.nix |
Registers the new Tailscale module |
home-manager/packages/default.nix |
Moves tailscale package from Linux-only to cross-platform section |
named-hosts/galactica/default.nix |
Configures Tailscale service for the galactica host with auth key and connection options |
named-hosts/galactica/secrets.nix |
Adds agenix secret configuration for encrypted Tailscale auth key |
named-hosts/galactica/keys/tailscale-auth.age |
Placeholder file with instructions for encrypting the Tailscale auth key |
docs/TAILSCALE.md |
Comprehensive documentation covering setup, configuration, usage, troubleshooting, and best practices |
Makefile |
Minor formatting change (extra blank line) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }; | ||
|
|
||
| # Tailscale configuration with auth key support | ||
| services.tailscale = { |
There was a problem hiding this comment.
The module defines options under modules.tailscale, but this configuration uses services.tailscale. This will cause an "unknown option" error. Change this to modules.tailscale to match the module definition in home-manager/modules/tailscale/default.nix.
| services.tailscale = { | |
| modules.tailscale = { |
| directories = mkOption { | ||
| type = types.attrsOf types.anything; | ||
| default = { }; | ||
| description = "Integration with home-manager's directories option"; | ||
| }; | ||
|
|
||
| files = mkOption { | ||
| type = types.attrsOf types.anything; | ||
| default = { }; | ||
| description = "Integration with home-manager's files option"; | ||
| }; | ||
|
|
There was a problem hiding this comment.
The directories and files options are defined but never used in the module configuration. These options appear to serve no purpose and should either be utilized or removed to avoid confusion.
| directories = mkOption { | |
| type = types.attrsOf types.anything; | |
| default = { }; | |
| description = "Integration with home-manager's directories option"; | |
| }; | |
| files = mkOption { | |
| type = types.attrsOf types.anything; | |
| default = { }; | |
| description = "Integration with home-manager's files option"; | |
| }; |
| services.tailscale = { | ||
| enable = true; | ||
| authKeyFile = config.age.secrets."keys/tailscale-auth.age".path; | ||
| extraUpArgs = [ | ||
| "--reset" | ||
| "--accept-dns=false" | ||
| "--login-server=https://login.tailscale.com" | ||
| ]; | ||
| }; | ||
| ``` |
There was a problem hiding this comment.
Change services.tailscale to modules.tailscale to match the actual module definition.
| }; | ||
|
|
||
| Service = { | ||
| ExecStart = "${pkgs.tailscale}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; |
There was a problem hiding this comment.
The service uses ${pkgs.tailscale} directly instead of ${cfg.tailscaled.package}, which ignores the configurable tailscaled.package option. This should be changed to ${cfg.tailscaled.package} to respect the user's package selection. Same issue exists on line 159.
| ExecStart = "${pkgs.tailscale}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; | |
| ExecStart = "${cfg.tailscaled.package}/bin/tailscaled --state=${config.xdg.dataHome}/tailscale/tailscaled.state --socket=${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; |
| authKey = mkOption { | ||
| type = types.str; | ||
| default = ""; | ||
| description = "Tailscale auth key (use agenix for secrets)"; |
There was a problem hiding this comment.
The authKey option stores secrets as plain text in the Nix store, which is world-readable. This is a security risk. Consider deprecating this option in favor of authKeyFile only, or add a warning in the description that this option should not be used for sensitive data.
| description = "Tailscale auth key (use agenix for secrets)"; | |
| description = '' | |
| Tailscale auth key. | |
| WARNING: The value of this option will be stored as plain text in the Nix store, | |
| which is world-readable. This is a security risk and this option should NOT be used | |
| for sensitive data. Use `authKeyFile` with a properly secured file for secrets instead. | |
| ''; |
| stateDir = mkOption { | ||
| type = types.str; | ||
| default = "${config.xdg.dataHome}/tailscale"; | ||
| description = "Directory for Tailscale state files"; | ||
| }; | ||
|
|
||
| socketPath = mkOption { | ||
| type = types.str; | ||
| default = "${config.xdg.runtimeDir}/tailscale/tailscaled.sock"; | ||
| description = "Socket path for Tailscale daemon"; | ||
| }; |
There was a problem hiding this comment.
The stateDir and socketPath options are defined but never used in the actual service configuration. Lines 116 uses hardcoded paths instead of these options. Either use these options consistently (e.g., cfg.tailscaled.stateDir and cfg.tailscaled.socketPath) or remove them to avoid confusion.
| optionalString (cfg.useExitNode != "") "--exit-node=${cfg.useExitNode}" | ||
| } \ | ||
| ${concatStringsSep " " cfg.extraUpArgs}'"; | ||
| ExecStop = "${pkgs.tailscale}/bin/tailscale down"; |
There was a problem hiding this comment.
Use ${cfg.tailscaled.package} instead of ${pkgs.tailscale} to respect the configurable package option.
| ExecStop = "${pkgs.tailscale}/bin/tailscale down"; | |
| ExecStop = "${cfg.tailscaled.package}/bin/tailscale down"; |
| optionalString (cfg.authKey != "") "--authkey=${cfg.authKey}" | ||
| } \ | ||
| ${ | ||
| optionalString (cfg.authKeyFile != "") "--authkey=$AUTH_KEY" | ||
| } \ |
There was a problem hiding this comment.
Both conditions on lines 148 and 151 can be true simultaneously, which would result in --authkey being passed twice to tailscale up. This will cause an error. Use else if logic or ensure only one auth key source is used. Additionally, line 148 directly embeds the auth key in the command which will expose it in process lists, while line 151 correctly uses a variable.
| optionalString (cfg.authKey != "") "--authkey=${cfg.authKey}" | |
| } \ | |
| ${ | |
| optionalString (cfg.authKeyFile != "") "--authkey=$AUTH_KEY" | |
| } \ | |
| optionalString ((cfg.authKey != "") || (cfg.authKeyFile != "")) "--authkey=$AUTH_KEY" | |
| } \ |
| services.tailscale = { | ||
| enable = true; # Enable Tailscale service | ||
| acceptRoutes = false; # Accept advertised routes (default: false) | ||
| advertiseExitNode = false; # Advertise as exit node (default: false) | ||
| useExitNode = ""; # Exit node to use (default: none) | ||
| authKey = ""; # Auth key as string (alternative to authKeyFile) | ||
| authKeyFile = ""; # Path to auth key file (recommended) | ||
| extraUpArgs = [ # Additional arguments for tailscale up | ||
| "--reset" | ||
| "--accept-dns=false" | ||
| ]; | ||
| }; | ||
| ``` |
There was a problem hiding this comment.
The documentation shows the module being configured as services.tailscale, but the actual module defines options under modules.tailscale (see line 16 in home-manager/modules/tailscale/default.nix). Update all documentation examples to use modules.tailscale instead of services.tailscale.
| services.tailscale = { | ||
| enable = true; | ||
| authKeyFile = config.age.secrets."keys/tailscale-auth.age".path; | ||
| extraUpArgs = [ | ||
| "--reset" | ||
| "--accept-dns=false" | ||
| "--tag=tag:server" | ||
| ]; | ||
| }; | ||
| ``` |
There was a problem hiding this comment.
Change services.tailscale to modules.tailscale to match the actual module definition.
There was a problem hiding this comment.
3 issues found across 8 files
Prompt for AI agents (all 3 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="docs/TAILSCALE.md">
<violation number="1" location="docs/TAILSCALE.md:324">
The SSH config example disables host key verification (`StrictHostKeyChecking no`), which exposes users to MITM attacks; keep host verification enabled instead.</violation>
</file>
<file name="home-manager/modules/tailscale/default.nix">
<violation number="1" location="home-manager/modules/tailscale/default.nix:13">
`configEnabled` prevents the Tailscale services from ever being created because it only becomes true when `serviceConfig` is non-empty, so enabling the module still results in no running service.</violation>
<violation number="2" location="home-manager/modules/tailscale/default.nix:43">
`authKeyFile` is typed as a path but defaults to an empty string, which violates the option’s type constraint and causes the module to fail unless the user overrides it.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| Host *.ts.net | ||
| User your-username | ||
| IdentityFile ~/.ssh/id_ed25519 | ||
| StrictHostKeyChecking no |
There was a problem hiding this comment.
The SSH config example disables host key verification (StrictHostKeyChecking no), which exposes users to MITM attacks; keep host verification enabled instead.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/TAILSCALE.md, line 324:
<comment>The SSH config example disables host key verification (`StrictHostKeyChecking no`), which exposes users to MITM attacks; keep host verification enabled instead.</comment>
<file context>
@@ -0,0 +1,368 @@
+Host *.ts.net
+ User your-username
+ IdentityFile ~/.ssh/id_ed25519
+ StrictHostKeyChecking no
+ UserKnownHostsFile ~/.ssh/known_hosts.tailscale
+```
</file context>
| # Optional auth key | ||
| authKey = mkOption { | ||
| type = types.str; | ||
| default = ""; |
There was a problem hiding this comment.
authKeyFile is typed as a path but defaults to an empty string, which violates the option’s type constraint and causes the module to fail unless the user overrides it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/modules/tailscale/default.nix, line 43:
<comment>`authKeyFile` is typed as a path but defaults to an empty string, which violates the option’s type constraint and causes the module to fail unless the user overrides it.</comment>
<file context>
@@ -0,0 +1,178 @@
+ # Optional auth key
+ authKey = mkOption {
+ type = types.str;
+ default = "";
+ description = "Tailscale auth key (use agenix for secrets)";
+ };
</file context>
| cfg = config.modules.tailscale; | ||
|
|
||
| # Check if configuration is enabled | ||
| configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null); |
There was a problem hiding this comment.
configEnabled prevents the Tailscale services from ever being created because it only becomes true when serviceConfig is non-empty, so enabling the module still results in no running service.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/modules/tailscale/default.nix, line 13:
<comment>`configEnabled` prevents the Tailscale services from ever being created because it only becomes true when `serviceConfig` is non-empty, so enabling the module still results in no running service.</comment>
<file context>
@@ -0,0 +1,178 @@
+ cfg = config.modules.tailscale;
+
+ # Check if configuration is enabled
+ configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null);
+in
+{
</file context>
| configEnabled = (cfg.serviceConfig != { } && cfg.serviceConfig != null); | |
| configEnabled = cfg.enable; |
Note
Adds a Tailscale home-manager module with systemd user services, integrates it into the galactica host using an encrypted auth key, and includes setup documentation and package updates.
home-manager/modules/tailscale/default.nix):services.tailscaleoptions (auth key, routes, exit node, extra args).tailscaledandtailscale-up(auth via key or file), plus state/run dir setup.home-manager/modules/default.nix.services.tailscalewithauthKeyFilefrom agenix, disables routes/exit node, sets extra up args.named-hosts/galactica/secrets.nixand placeholder keykeys/tailscale-auth.age.tailscaletohome-manager/packages/default.nix(removes Linux-only placement to general list).docs/TAILSCALE.mdwith setup, configuration, usage, and maintenance guidance.Written by Cursor Bugbot for commit 1d9d669. Configure here.
Summary by cubic
Adds Tailscale VPN support via a reusable Home Manager module and host config for galactica, with auth key managed by agenix. Includes a setup guide and defaults that avoid routes and exit nodes.
New Features
Migration
Written for commit 1d9d669. Summary will update automatically on new commits.