Skip to content

refactor: caddy extensions seperation from main module.#597

Merged
DaRacci merged 10 commits into
masterfrom
push-kkyupknwnwrn
Jun 24, 2026
Merged

refactor: caddy extensions seperation from main module.#597
DaRacci merged 10 commits into
masterfrom
push-kkyupknwnwrn

Conversation

@DaRacci

@DaRacci DaRacci commented Jun 24, 2026

Copy link
Copy Markdown
Owner

No description provided.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@DaRacci, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 45 minutes and 54 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a3535926-a71a-41de-ba14-dda8b7ff1939

📥 Commits

Reviewing files that changed from the base of the PR and between dcdfb90 and 2ac4e14.

📒 Files selected for processing (2)
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
📝 Walkthrough

Walkthrough

Adds a proxy extension registry, migrates L4, Kanidm, dashboard, and Cloudflared behaviour into dedicated modules, and rewires proxy config generation to select and render extensions through new helper functions. Related docs and Caddy plugin pins are updated.

Changes

Proxy extension registry refactor

Layer / File(s) Summary
Extension registry and vhost contracts
modules/nixos/server/proxy/options.nix
Replaces kanidmContexts with extensions, adds extension hook and ordering fields, and introduces _name plus a per-vhost extensions selector while removing the old direct vhost options.
proxyLib helpers and imports
modules/nixos/server/proxy/default.nix
Adds config to the module arguments, defines extension selection and global config helpers, exports them from proxyLib, and rewires imports to the granular extension modules.
L4 extension module
modules/nixos/server/proxy/extensions/l4.nix
Defines server.proxy.virtualHosts.*.l4, enables the extension when any vhost has L4 configured, renders grouped layer4 config from per-vhost listener settings, and adds firewall ports on the primary host.
Kanidm extension module
modules/nixos/server/proxy/extensions/kanidm.nix
Defines shared Kanidm context options and per-vhost Kanidm settings, derives context-to-vhost mappings and generated config fragments, wires per-vhost routing and global security config, and provisions the related SOPS and OAuth2 resources.
Dashboard and Cloudflared extension modules
modules/nixos/server/proxy/extensions/dashboard.nix, modules/nixos/server/proxy/extensions/cloudflared.nix
Adds the dashboard extension that maps virtual hosts to dashboard items, and the Cloudflared extension that marks public virtual hosts and configures tunnel ingress on the primary host.
config.nix delegation to extensions
modules/nixos/server/proxy/config.nix
Removes local L4 config construction, adds extension validity assertions, delegates global config rendering to the extension helpers, rewrites per-vhost extraConfig assembly through selected extensions, and removes the firewall port derivation.
Documentation and dependency updates
docs/src/modules/nixos/server/proxy.md, .opencode/skills/modules/SKILL.md, hosts/server/nixio/proxy.nix
Updates the proxy module docs with extension architecture content, adds the submodule extension guidance section to the skill guide, and bumps the Caddy L4 and security plugin versions with the matching derivation hash.

Sequence Diagram(s)

sequenceDiagram
  participant NixOS as NixOS evaluation
  participant Options as options.nix
  participant ProxyLib as default.nix
  participant Config as config.nix
  participant Extensions as extension modules

  NixOS->>Options: evaluate server.proxy.extensions and virtualHosts options
  NixOS->>ProxyLib: load getExtensionsForVhost and getGlobalConfigFromExtensions
  NixOS->>Extensions: evaluate l4, kanidm, dashboard, cloudflared modules
  Config->>ProxyLib: getGlobalConfigFromExtensions config
  ProxyLib->>Extensions: call each extension globalConfig
  ProxyLib-->>Config: concatenated global config
  Config->>ProxyLib: getExtensionsForVhost vhostAttr
  ProxyLib->>Extensions: filter, whitelist, and sort enabled extensions
  ProxyLib-->>Config: ordered per-vhost extension list
  Config->>NixOS: render services.caddy.globalConfig and per-vhost extraConfig
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 I hopped through the proxy warren bright,
With extensions neat and sorted just right.
L4, Kanidm, dash, and cloudflared sing,
While proxyLib helps each config spring.
A tidy burrow, modular and new —
Thump thump, the registry works through and through!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so there isn't enough content to judge its relevance. Add a short summary of what changed and why, such as the new extension architecture and module split.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main change: separating Caddy extensions from the main module.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch push-kkyupknwnwrn
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch push-kkyupknwnwrn

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@RacciDev-Bot RacciDev-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.

Hermes Code Review: PR #597

refactor: caddy extensions separation from main module

Reviewed 8 source files across 20 changed files. The PR extracts L4, Kanidm, Dashboard, and Cloudflared logic from config.nix into self-contained extension modules under modules/nixos/server/proxy/extensions/, with a clean extension registry system (server.proxy.extensions). Architecture is sound - NixOS module system submodule merging is the right pattern for this.

Verdict: COMMENT - all findings are minor or trivial. No blocking issues.

Summary of findings

# Severity File Issue
1 🟡 Minor options.nix:71-75 vhostModule defined but never consumed
2 🟡 Minor config.nix:53-131 Assertion logic duplicated 2x per block
3 🟡 Minor extensions/kanidm.nix:227 Always enabled - doesn't match spec
4 🔹 Trivial extensions/l4.nix 3 independent cross-host traversals

Comment thread modules/nixos/server/proxy/options.nix
Comment thread modules/nixos/server/proxy/config.nix
Comment thread modules/nixos/server/proxy/extensions/kanidm.nix
Comment thread modules/nixos/server/proxy/extensions/l4.nix

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/nixos/server/proxy/config.nix`:
- Around line 82-88: The extension selection logic in config.nix is filtering
over values from builtins.attrValues, which strips the attribute names and can
make ext._name unavailable when vh.extensions is set. Update the extension
collection in the proxy config to preserve names before filtering, then apply
the same change in the duplicated let block so both places use named extension
records when matching against vh.extensions and ext.enable.
- Around line 115-130: The current assertion in config.nix only rejects vhosts
with kanidm enabled and extensions = [ ], so it misses protected vhosts whose
extensions list does not include kanidm. Update the assertion around
config.server.proxy.virtualHosts to check vh.kanidm != null and require "kanidm"
to be present in vh.extensions, and keep the failure message listing the
affected vhosts by _name.

In `@modules/nixos/server/proxy/extensions/kanidm.nix`:
- Around line 224-232: The Kanidm extension’s default branch in the config
function is swallowing non-Kanidm vhost configuration because `enable =
mkDefault true` makes it selected for default vhosts while `consumesExtraConfig
= true` means the `vh.kanidm == null` case must not return an empty string.
Update the `server.proxy.extensions.kanidm` config logic so the `vh.kanidm ==
null` path preserves and forwards `vh._resolvedExtraConfig` instead of
discarding it, keeping non-Kanidm vhosts’ Caddy config intact.
- Around line 149-176: The kanidmContextsWithVirtualHosts mapping in kanidm.nix
eagerly calls builtins.head on vhList, which breaks evaluation for contexts that
have no matching virtual hosts. Update the context transformation to handle
empty vhList safely in the builtins.mapAttrs block by guarding originLanding
(and any other head-based access) so unused shared contexts are skipped or
emitted without originLanding rather than failing during evaluation.
- Around line 273-283: The Kanidm secret definition in sops.secrets sets owner
and group but is missing the restrictive file mode and a rotation hook. Update
the secret entries created in the kanidm.nix sops.secrets mapping to include
mode = "0400" and add the appropriate Kanidm provision/service restartUnits or
reloadUnits so changes to the secret refresh the basicSecretFile consumer.

In `@modules/nixos/server/proxy/extensions/l4.nix`:
- Around line 41-43: The L4 firewall configuration is opening UDP for every
listener even though the L4 option only exposes listenPort, so tighten this to
the minimal protocol set. Update the l4.nix logic around the L4 listener
definitions and firewall port derivation to default to TCP-only, or add an
explicit protocol option in the relevant vhost/listener config and only include
UDP when that option is enabled. Make sure the change is applied consistently in
the L4 listener processing and firewall port aggregation code, including the
related block used for the other L4 listeners.
- Around line 76-86: The L4 proxy config generation in allL4Entries is rewriting
loopback targets with hostCfg.host.name, which is the primary IO host and makes
replaceLocalHost a no-op for non-primary hosts. Update the mapping so
replaceLocalHost uses the owning virtual host’s host name from the current
vh/virtualHosts entry instead of the global host, ensuring localhost and
127.0.0.1 targets are rewritten to the correct host for each collected L4 entry.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6bc0ab64-8954-4e7c-a4d7-480529d9b35a

📥 Commits

Reviewing files that changed from the base of the PR and between 44457d4 and 12907fc.

⛔ Files ignored due to path filters (8)
  • openspec/changes/proxy-extension-registry/.openspec.yaml is excluded by !openspec/**
  • openspec/changes/proxy-extension-registry/design.md is excluded by !openspec/**
  • openspec/changes/proxy-extension-registry/proposal.md is excluded by !openspec/**
  • openspec/changes/proxy-extension-registry/specs/proxy-extension-authoring/spec.md is excluded by !openspec/**
  • openspec/changes/proxy-extension-registry/specs/proxy-extension-registry/spec.md is excluded by !openspec/**
  • openspec/changes/proxy-extension-registry/specs/proxy-l4-extension/spec.md is excluded by !openspec/**
  • openspec/changes/proxy-extension-registry/specs/proxy-vhost-extension-selection/spec.md is excluded by !openspec/**
  • openspec/changes/proxy-extension-registry/tasks.md is excluded by !openspec/**
📒 Files selected for processing (12)
  • .opencode/skills/modules/SKILL.md
  • docs/src/modules/nixos/server/proxy.md
  • hosts/server/nixio/proxy.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/extensions.nix
  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/kanidm.nix
  • modules/nixos/server/proxy/options.nix
💤 Files with no reviewable changes (2)
  • modules/nixos/server/proxy/kanidm.nix
  • modules/nixos/server/proxy/extensions.nix
📜 Review details
⏰ Context from checks skipped due to timeout. (9)
  • GitHub Check: Build homeConfigurations.racci.activationPackage on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixio.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixarr.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixmi.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixai.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixmon.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixserv.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixcloud.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixdev.config.system.build.toplevel on x86_64-linux
🧰 Additional context used
📓 Path-based instructions (11)
**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/code-style-nix)

**/*.nix: Follow Nix code style conventions and best practices
Use consistent indentation and formatting in Nix configuration files
Follow established patterns for module organization in home-manager configurations

**/*.nix: Format code and check syntax using nix fmt
Evaluate Nix expressions without building using nix eval with the target configuration path
Format specific Nix files or directories using nix fmt followed by the file or directory path
Use --show-trace flag with nix build or nix eval commands to diagnose evaluation errors
For infinite recursion errors in Nix builds, check for circular imports or conflicting option definitions

**/*.nix: Use builtins.trace to add trace statements and inspect values during Nix evaluation (format: builtins.trace "message: ${toString var}" var)
Use builtins.toJSON to convert complex Nix attribute sets to JSON for easier inspection during evaluation
Check for circular imports between modules and option definitions that depend on themselves to resolve infinite recursion errors
Verify attribute names are correct and imports are complete when debugging 'attribute not found' errors in Nix
Check option type definitions and ensure provided values match the expected type to resolve type mismatch errors
Read assertion messages and provide required configuration values when assertion failures occur in NixOS modules

**/*.nix: Store sensitive data in secrets.yaml encrypted with sops instead of hardcoding passwords, API keys, or tokens in plain text
Declare sops secrets with proper owner, group, and mode attributes; use restrictive modes like 0400 for secrets files
Set restartUnits or reloadUnits for sops secrets declarations so services that depend on secrets are restarted when secrets change
Use config.sops.placeholder in sops templates instead of directly interpolating secret paths in multi-secret templates
Do not pass secrets as environment variables in plain Nix; use environmentFile or...

Files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • hosts/server/nixio/proxy.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
modules/nixos/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Reusable NixOS module fragments should be placed in modules/nixos/

Create new NixOS modules as files under modules/nixos/<category>/<name>.nix.

Files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
modules/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

modules/**/*.nix: Use the standard Nix module structure: accept { config, lib, pkgs, ... }, define cfg from config.<namespace>.<name>, declare options under options, and gate configuration with config = lib.mkIf cfg.enable { ... } (or the equivalent mkIf/mkEnableOption pattern).
When modifying existing Nix modules, run nix fmt on the changed .nix files.
When extending a submodule declared in another Nix module, declare the same options.<path> again with the same outer wrapper (for example attrsOf (submodule ...)) so the inner options merge additively.
Do not build submodule imports dynamically from config inside the submodule type; that creates infinite recursion.
Use static submodule imports only when they do not depend on config, and use mkIf inside config for conditional behavior instead of conditioning the submodule type.
When adding options to an existing submodule, keep them always declared in the submodule type; do not gate the option declaration with enable.

Files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
hosts/server/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Server machine-specific NixOS configs should be placed in hosts/server/<machine>/

Files:

  • hosts/server/nixio/proxy.nix
.opencode/skills/**

⚙️ CodeRabbit configuration file

../../modules/home-manager/purpose/development/editors/ai/skills/code-style-nix

../../modules/home-manager/purpose/development/editors/ai/skills/conventional-commits

../../modules/home-manager/purpose/development/editors/ai/skills/jujutsu

../../modules/home-manager/purpose/development/editors/ai/skills/nushell

../../modules/home-manager/purpose/development/editors/ai/skills/systemd-hardening

../../modules/home-manager/purpose/development/editors/ai/skills/tmux

../../modules/home-manager/purpose/development/editors/ai/skills/vhs

Files:

  • .opencode/skills/modules/SKILL.md
.opencode/skills/modules/**

⚙️ CodeRabbit configuration file

.opencode/skills/modules/**: ---
name: modules
description: Create and modify NixOS and Home-Manager modules

Modules

Module Structure

Standard module pattern:

{
  config,
  lib,
  pkgs,
  ...
}:
let
  inherit (lib) mkEnableOption mkOption mkIf types;
  cfg = config.services.myService;
in
{
  options.services.myService = {
    enable = mkEnableOption "my service";

    port = mkOption {
      type = types.port;
      default = 8080;
      description = "Port to listen on.";
    };
  };

  config = mkIf cfg.enable {
    # Configuration applied when enabled
  };
}

Creating a NixOS Module

  1. Create file at modules/nixos/<category>/<name>.nix

  2. Define options and config:

    {
      config,
      lib,
      pkgs,
      ...
    }:
    let
      cfg = config.services.myService;
    in
    {
      options.services.myService = {
        enable = lib.mkEnableOption "my service";
      };
    
      config = lib.mkIf cfg.enable {
        systemd.services.my-service = {
          wantedBy = [ "multi-user.target" ];
          serviceConfig.ExecStart = "${pkgs.myPackage}/bin/my-service";
        };
      };
    }
  3. Register in parent default.nix:

    # modules/nixos/services/default.nix
    _: {
      imports = [
        ./existing-service.nix
        ./my-service.nix  # Add this
      ];
    }
  4. Enable in host config:

    # hosts/server/myhost/default.nix
    { services.myService.enable = true; }

Creating a Home-Manager Module

  1. Create file at modules/home-manager/<category>/<name>.nix

  2. Define with optional osConfig access:

    {
      osConfig ? null,
      config,
      lib,
      pkgs,
      ...
    }:
    let
      cfg = config.purpose.myFeature;
    in
    {
      options.purpose.myFeature = {
        enable = lib.mkEnableOption "my feature";
      };
    
      config = lib.mkIf cfg.enable {
        home.packages = [ pkgs.myPackage ];
      };
    }
  3. Register in parent default.nix

  4. Enable in user...

Files:

  • .opencode/skills/modules/SKILL.md
docs/**/*

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Project documentation should be placed in the docs/ directory

Files:

  • docs/src/modules/nixos/server/proxy.md
docs/src/**/*.md

📄 CodeRabbit inference engine (.opencode/skills/docs/SKILL.md)

docs/src/**/*.md: Use underscore filenames (e.g., my_new_feature.md) instead of hyphens for documentation files
Keep documentation prose focused on behavior, architecture, usage examples, and operational notes; let generated fragments provide exhaustive option reference

Files:

  • docs/src/modules/nixos/server/proxy.md
docs/src/modules/**/*.md

📄 CodeRabbit inference engine (.opencode/skills/docs/SKILL.md)

For documented modules, prefer build-time generated option fragments via {{#include}} from docs/src/generated/*.md instead of hand-maintained option tables

Files:

  • docs/src/modules/nixos/server/proxy.md
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Verify documentation accurately reflects new behavior in docs/ directory before proceeding to commit

Files:

  • docs/src/modules/nixos/server/proxy.md
modules/nixos/**/default.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

Register new NixOS modules in the parent default.nix via the imports list or top-level attribute-set export, depending on the directory layout.

Files:

  • modules/nixos/server/proxy/default.nix
🧠 Learnings (8)
📚 Learning: 2026-04-13T14:02:32.760Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: hosts/server/nixdev/default.nix:18-18
Timestamp: 2026-04-13T14:02:32.760Z
Learning: When configuring NixOS Docker via `virtualisation.docker.daemon.settings`, it is valid to set `storage-driver = "overlayfs"` (do not flag it as an invalid Docker storage-driver). Use `overlayfs` specifically for Docker Engine 29+ and/or when the containerd snapshotter integration is enabled (`virtualisation.docker.features.containerd-snapshotter = true`). Treat this as the containerd snapshotter name for OverlayFS, distinct from the legacy `overlay2` classic Docker storage driver.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • hosts/server/nixio/proxy.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
📚 Learning: 2026-05-01T10:02:55.261Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/sops.nix:49-53
Timestamp: 2026-05-01T10:02:55.261Z
Learning: In this nix-config repo, when declaring `sops.secrets` in Nix files, avoid explicitly setting `owner = "root"` and/or `group = "root"` if the intended ownership is root. `sops-nix` defaults `sops.secrets` to `root:root`, so adding these fields explicitly is redundant boilerplate.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • hosts/server/nixio/proxy.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
📚 Learning: 2026-05-01T14:14:49.691Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:119-119
Timestamp: 2026-05-01T14:14:49.691Z
Learning: When configuring the NixOS `wivrn` module option `services.wivrn.config.json.application`, pass the raw package/derivation (e.g., `pkgs.wayvr`) rather than converting it to a string executable path (e.g., `lib.getExe pkgs.wayvr`). The upstream module expects a list of derivations/packages (it internally `toList`s the value, asserts the first element is a derivation, and then resolves the executable internally). Code review should not recommend changing `pkgs.wayvr` to `lib.getExe pkgs.wayvr` for this option.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • hosts/server/nixio/proxy.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
📚 Learning: 2026-05-20T13:12:46.610Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: docs/site.nix:127-127
Timestamp: 2026-05-20T13:12:46.610Z
Learning: In DaRacci/nix-config, treating `passthru.discovery = false` as a known repo-wide convention to exclude a derivation from automated flake discovery/package CI. Do not require or flag an inline explanatory comment specifically for the absence of a comment when `passthru.discovery = false` is set.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • hosts/server/nixio/proxy.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
📚 Learning: 2026-05-01T09:11:22.009Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:65-65
Timestamp: 2026-05-01T09:11:22.009Z
Learning: In Nix code, do not flag shell-variable literals like "$XDG_RUNTIME_DIR" used inside Steam’s `extraEnv` (e.g., `pkgs.steam.override { extraEnv = { ... }; }`, including `modules/nixos/core/gaming.nix`). The Steam wrapper script expands these shell variables at runtime, so they should be treated as intended unexpanded literals rather than an interpolation/quoting mistake.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
📚 Learning: 2026-05-01T14:35:32.037Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/remote.nix:153-179
Timestamp: 2026-05-01T14:35:32.037Z
Learning: In this repo’s NixOS module code (e.g., shell scripts produced via `writeShellApplication` inside `modules/nixos/**`), do not treat missing `XDG_STATE_HOME` fallbacks (like `${XDG_STATE_HOME:-$HOME/.local/state}`) as an error in the embedded shell script. On NixOS user sessions, `XDG_STATE_HOME` is reliably set via PAM/systemd, so flagging its absence as potentially unset is overly defensive for these generated scripts.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
📚 Learning: 2026-06-20T14:33:25.328Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 590
File: modules/nixos/server/monitoring/collector/tempo.nix:71-72
Timestamp: 2026-06-20T14:33:25.328Z
Learning: When reviewing DaRacci/nix-config NixOS modules that use sops-nix, do not flag `sops.secrets` entries as missing `owner`, `group`, `mode`, or `restartUnits` if the secret declarations are only placeholder sources for `sops.templates`:
- The secret value is referenced exclusively via `config.sops.placeholder.<NAME>` inside a `sops.templates` definition (i.e., no other code reads the decrypted secret from the raw secret path).
- The rendered `sops.templates` output is what is used by systemd via a `systemd.services.*.serviceConfig.EnvironmentFile` (the template is the effective boundary).
In this pattern, the template’s own `restartUnits` are the relevant access-control/restart boundary; the raw `sops.secrets` files are only decrypted in-memory by sops-nix (run as root) to render the template. Therefore, empty-attrset `sops.secrets.<NAME> = { };` declarations should not be treated as missing permissions/restart hooks when they are only feeding a `sops.templates` placeholder.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
📚 Learning: 2026-05-01T09:57:09.578Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/services/ai-agent.nix:15-15
Timestamp: 2026-05-01T09:57:09.578Z
Learning: In this repo’s Nix modules, `inputs.services-zeroclaw` is a flake input that resolves to an attrset containing a `_file` attribute, and Nix coerces that attrset to a file path via `_file`. When importing/using it as a path in `imports` (e.g., `modules/nixos/services/ai-agent.nix`), use the string interpolation form "${inputs.services-zeroclaw}". Do not change it to `inputs.services-zeroclaw` (raw attrset form) in `imports`, because it will not work correctly.

Applied to files:

  • modules/nixos/server/proxy/extensions/cloudflared.nix
  • modules/nixos/server/proxy/extensions/dashboard.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/default.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/options.nix
🪛 LanguageTool
docs/src/modules/nixos/server/proxy.md

[typographical] ~141-~141: If specifying a range, consider using an en dash instead of a hyphen.
Context: ...onfig placement. Ranges: 0-49 reserved, 50-99 auth, 100-199 general, 200+ post-proces...

(HYPHEN_TO_EN)

🔇 Additional comments (11)
docs/src/modules/nixos/server/proxy.md (1)

49-50: LGTM!

Also applies to: 123-235

.opencode/skills/modules/SKILL.md (1)

169-251: LGTM!

hosts/server/nixio/proxy.nix (1)

48-52: LGTM!

modules/nixos/server/proxy/extensions/dashboard.nix (1)

1-33: LGTM!

modules/nixos/server/proxy/extensions/cloudflared.nix (1)

1-72: LGTM!

modules/nixos/server/proxy/options.nix (1)

25-26: LGTM!

Also applies to: 37-78, 94-111

modules/nixos/server/proxy/default.nix (1)

10-10: LGTM!

Also applies to: 94-122, 131-142

modules/nixos/server/proxy/config.nix (1)

26-32: LGTM!

Also applies to: 53-75, 145-146, 171-192

modules/nixos/server/proxy/extensions/kanidm.nix (3)

1-41: LGTM!

Also applies to: 110-147, 180-220, 270-270


235-240: 🩺 Stability & Availability

Consider sanitising : in bypass matcher names too. Vhost names can include ports, and this matcher name only replaces - and ., so keys like app.example.com:8443 will produce @bypass_auth_app_example_com:8443.


52-58: 🩺 Stability & Availability

Keep the Kanidm env-file wiring on services.caddy. The generated config still resolves {env.OAUTH_${envPrefix}_CLIENT_SECRET} and {env.${envPrefix}_SHARED_KEY} at runtime, so the Caddy service still needs the template or EnvironmentFile that exports those values.

Comment thread modules/nixos/server/proxy/config.nix Outdated
Comment thread modules/nixos/server/proxy/config.nix
Comment thread modules/nixos/server/proxy/extensions/kanidm.nix Outdated
Comment thread modules/nixos/server/proxy/extensions/kanidm.nix
Comment thread modules/nixos/server/proxy/extensions/kanidm.nix
Comment thread modules/nixos/server/proxy/extensions/l4.nix
Comment thread modules/nixos/server/proxy/extensions/l4.nix

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/nixos/server/proxy/config.nix`:
- Around line 70-74: The current validation only checks for vhosts that
configure kanidm without listing the kanidm extension, but it misses the case
where server.proxy.extensions.kanidm.enable is false and a vhost still has
vh.kanidm set. Update the proxy config validation in config.nix so the same
rejection path also catches Kanidm-protected vhosts whenever the Kanidm
extension is disabled, using the existing virtualHosts filtering logic and the
getExtensionsForVhost-related checks to ensure these vhosts are rejected before
rendering.

In `@modules/nixos/server/proxy/extensions/kanidm.nix`:
- Around line 284-285: The secret rotation hook is restarting the wrong unit, so
rotated OAuth2 secrets won’t be reloaded by the Kanidm server/provision path.
Update the `restartUnits` entry in the `basicSecretFile` block in `kanidm.nix`
to target `kanidm.service` instead of `kanidm-unixd.service`, since
`services.kanidm.provision.systems.oauth2` is consumed by the server unit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9dad0ef-21de-481a-81b8-d22ae35b830d

📥 Commits

Reviewing files that changed from the base of the PR and between 12907fc and dcdfb90.

📒 Files selected for processing (5)
  • hosts/server/nixai/voice.nix
  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • modules/nixos/server/proxy/config.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/extensions/l4.nix
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Build nixosConfigurations.nixcloud.config.system.build.toplevel on x86_64-linux
  • GitHub Check: Build nixosConfigurations.nixai.config.system.build.toplevel on x86_64-linux
🧰 Additional context used
📓 Path-based instructions (4)
**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/code-style-nix)

**/*.nix: Follow Nix code style conventions and best practices
Use consistent indentation and formatting in Nix configuration files
Follow established patterns for module organization in home-manager configurations

**/*.nix: Format code and check syntax using nix fmt
Evaluate Nix expressions without building using nix eval with the target configuration path
Format specific Nix files or directories using nix fmt followed by the file or directory path
Use --show-trace flag with nix build or nix eval commands to diagnose evaluation errors
For infinite recursion errors in Nix builds, check for circular imports or conflicting option definitions

**/*.nix: Use builtins.trace to add trace statements and inspect values during Nix evaluation (format: builtins.trace "message: ${toString var}" var)
Use builtins.toJSON to convert complex Nix attribute sets to JSON for easier inspection during evaluation
Check for circular imports between modules and option definitions that depend on themselves to resolve infinite recursion errors
Verify attribute names are correct and imports are complete when debugging 'attribute not found' errors in Nix
Check option type definitions and ensure provided values match the expected type to resolve type mismatch errors
Read assertion messages and provide required configuration values when assertion failures occur in NixOS modules

**/*.nix: Store sensitive data in secrets.yaml encrypted with sops instead of hardcoding passwords, API keys, or tokens in plain text
Declare sops secrets with proper owner, group, and mode attributes; use restrictive modes like 0400 for secrets files
Set restartUnits or reloadUnits for sops secrets declarations so services that depend on secrets are restarted when secrets change
Use config.sops.placeholder in sops templates instead of directly interpolating secret paths in multi-secret templates
Do not pass secrets as environment variables in plain Nix; use environmentFile or...

Files:

  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
hosts/server/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Server machine-specific NixOS configs should be placed in hosts/server/<machine>/

Files:

  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/voice.nix
modules/nixos/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/project-structure/SKILL.md)

Reusable NixOS module fragments should be placed in modules/nixos/

Use the standard NixOS module structure: destructure { config, lib, pkgs, ... }, bind cfg from config.<namespace>.<name>, define options with mkEnableOption/mkOption, and gate runtime config with mkIf cfg.enable.

Files:

  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
modules/**/*.nix

📄 CodeRabbit inference engine (.opencode/skills/modules/SKILL.md)

modules/**/*.nix: When extending submodules declared in another module, declare the same options.<path> using a compatible attrsOf (submodule ...) wrapper so the inner options sets merge additively.
Do not build submodule imports from config values; dynamic imports inside a submodule cause infinite recursion.
Static submodule imports are allowed when they do not read from config.
Use mkIf inside the submodule config for conditional behavior; keep submodule option declarations unconditional.

Files:

  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
🧠 Learnings (8)
📚 Learning: 2026-04-13T14:02:32.760Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: hosts/server/nixdev/default.nix:18-18
Timestamp: 2026-04-13T14:02:32.760Z
Learning: When configuring NixOS Docker via `virtualisation.docker.daemon.settings`, it is valid to set `storage-driver = "overlayfs"` (do not flag it as an invalid Docker storage-driver). Use `overlayfs` specifically for Docker Engine 29+ and/or when the containerd snapshotter integration is enabled (`virtualisation.docker.features.containerd-snapshotter = true`). Treat this as the containerd snapshotter name for OverlayFS, distinct from the legacy `overlay2` classic Docker storage driver.

Applied to files:

  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
📚 Learning: 2026-05-01T10:02:55.261Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/sops.nix:49-53
Timestamp: 2026-05-01T10:02:55.261Z
Learning: In this nix-config repo, when declaring `sops.secrets` in Nix files, avoid explicitly setting `owner = "root"` and/or `group = "root"` if the intended ownership is root. `sops-nix` defaults `sops.secrets` to `root:root`, so adding these fields explicitly is redundant boilerplate.

Applied to files:

  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
📚 Learning: 2026-05-01T14:14:49.691Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:119-119
Timestamp: 2026-05-01T14:14:49.691Z
Learning: When configuring the NixOS `wivrn` module option `services.wivrn.config.json.application`, pass the raw package/derivation (e.g., `pkgs.wayvr`) rather than converting it to a string executable path (e.g., `lib.getExe pkgs.wayvr`). The upstream module expects a list of derivations/packages (it internally `toList`s the value, asserts the first element is a derivation, and then resolves the executable internally). Code review should not recommend changing `pkgs.wayvr` to `lib.getExe pkgs.wayvr` for this option.

Applied to files:

  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
📚 Learning: 2026-05-20T13:12:46.610Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 546
File: docs/site.nix:127-127
Timestamp: 2026-05-20T13:12:46.610Z
Learning: In DaRacci/nix-config, treating `passthru.discovery = false` as a known repo-wide convention to exclude a derivation from automated flake discovery/package CI. Do not require or flag an inline explanatory comment specifically for the absence of a comment when `passthru.discovery = false` is set.

Applied to files:

  • hosts/server/nixcloud/home-assistant/connectivity.nix
  • hosts/server/nixai/voice.nix
  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
📚 Learning: 2026-05-01T09:11:22.009Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/gaming.nix:65-65
Timestamp: 2026-05-01T09:11:22.009Z
Learning: In Nix code, do not flag shell-variable literals like "$XDG_RUNTIME_DIR" used inside Steam’s `extraEnv` (e.g., `pkgs.steam.override { extraEnv = { ... }; }`, including `modules/nixos/core/gaming.nix`). The Steam wrapper script expands these shell variables at runtime, so they should be treated as intended unexpanded literals rather than an interpolation/quoting mistake.

Applied to files:

  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
📚 Learning: 2026-05-01T14:35:32.037Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/core/remote.nix:153-179
Timestamp: 2026-05-01T14:35:32.037Z
Learning: In this repo’s NixOS module code (e.g., shell scripts produced via `writeShellApplication` inside `modules/nixos/**`), do not treat missing `XDG_STATE_HOME` fallbacks (like `${XDG_STATE_HOME:-$HOME/.local/state}`) as an error in the embedded shell script. On NixOS user sessions, `XDG_STATE_HOME` is reliably set via PAM/systemd, so flagging its absence as potentially unset is overly defensive for these generated scripts.

Applied to files:

  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
📚 Learning: 2026-06-20T14:33:25.328Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 590
File: modules/nixos/server/monitoring/collector/tempo.nix:71-72
Timestamp: 2026-06-20T14:33:25.328Z
Learning: When reviewing DaRacci/nix-config NixOS modules that use sops-nix, do not flag `sops.secrets` entries as missing `owner`, `group`, `mode`, or `restartUnits` if the secret declarations are only placeholder sources for `sops.templates`:
- The secret value is referenced exclusively via `config.sops.placeholder.<NAME>` inside a `sops.templates` definition (i.e., no other code reads the decrypted secret from the raw secret path).
- The rendered `sops.templates` output is what is used by systemd via a `systemd.services.*.serviceConfig.EnvironmentFile` (the template is the effective boundary).
In this pattern, the template’s own `restartUnits` are the relevant access-control/restart boundary; the raw `sops.secrets` files are only decrypted in-memory by sops-nix (run as root) to render the template. Therefore, empty-attrset `sops.secrets.<NAME> = { };` declarations should not be treated as missing permissions/restart hooks when they are only feeding a `sops.templates` placeholder.

Applied to files:

  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
📚 Learning: 2026-05-01T09:57:09.578Z
Learnt from: DaRacci
Repo: DaRacci/nix-config PR: 544
File: modules/nixos/services/ai-agent.nix:15-15
Timestamp: 2026-05-01T09:57:09.578Z
Learning: In this repo’s Nix modules, `inputs.services-zeroclaw` is a flake input that resolves to an attrset containing a `_file` attribute, and Nix coerces that attrset to a file path via `_file`. When importing/using it as a path in `imports` (e.g., `modules/nixos/services/ai-agent.nix`), use the string interpolation form "${inputs.services-zeroclaw}". Do not change it to `inputs.services-zeroclaw` (raw attrset form) in `imports`, because it will not work correctly.

Applied to files:

  • modules/nixos/server/proxy/extensions/l4.nix
  • modules/nixos/server/proxy/extensions/kanidm.nix
  • modules/nixos/server/proxy/config.nix
🔇 Additional comments (5)
modules/nixos/server/proxy/extensions/l4.nix (1)

45-52: LGTM!

Also applies to: 80-93, 143-160

hosts/server/nixai/voice.nix (1)

29-29: LGTM!

Also applies to: 42-42

hosts/server/nixcloud/home-assistant/connectivity.nix (1)

146-146: LGTM!

modules/nixos/server/proxy/extensions/kanidm.nix (1)

176-177: LGTM!

modules/nixos/server/proxy/config.nix (1)

45-68: LGTM!

Also applies to: 85-92

Comment thread modules/nixos/server/proxy/config.nix
Comment thread modules/nixos/server/proxy/extensions/kanidm.nix Outdated
@DaRacci DaRacci enabled auto-merge (rebase) June 24, 2026 13:31
@DaRacci DaRacci merged commit 0f323db into master Jun 24, 2026
5 of 8 checks passed
@DaRacci DaRacci deleted the push-kkyupknwnwrn branch June 24, 2026 13:32
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.

2 participants