-
-
Notifications
You must be signed in to change notification settings - Fork 155
Description
Summary
secrets.providers in nix/generated/openclaw-config-options.nix uses t.oneOf with three t.submodule variants (discriminated by source). This fails nix flake check — Nix's types.oneOf cannot reliably discriminate between submodules that share overlapping option names.
As a result, it's impossible to declare secret providers declaratively (except with source = "env"):
programs.openclaw.instances.default.config.secrets.providers.my-secrets = {
source = "file";
path = "/run/secrets/openclaw_json";
mode = "json";
};Root Cause
The generated type for secrets.providers (around line 10149) is:
providers = lib.mkOption {
type = t.nullOr (t.attrsOf (t.oneOf [
(t.submodule { options = { source = lib.mkOption { type = t.enum [ "env" ]; }; ... }; })
(t.submodule { options = { source = lib.mkOption { type = t.enum [ "file" ]; }; ... }; })
(t.submodule { options = { source = lib.mkOption { type = t.enum [ "exec" ]; }; ... }; })
]));
default = null;
};types.oneOf checks each variant in sequence via its check function, but types.submodule's check is very permissive — it accepts any attrset. This means:
- Multiple variants match the input value.
- The
mergefunction then fails because the value doesn't satisfy all variants simultaneously. nix flake check(which evaluates all options strictly) surfaces the error, even when the value is perfectly valid for one specific variant.
This is a known limitation of types.oneOf with submodules in nixpkgs — it works for structurally distinct types (e.g., str vs submodule) but not for discriminated-union-style submodules that share keys like source.
Same issue was also flagged here on nixpkgs: NixOS/nixpkgs#337108
Suggested Fix
Instead of generating t.oneOf [ submoduleA submoduleB submoduleC ], the code generator should produce a single t.submodule where:
sourceremains the discriminator ast.enum [ "env" "file" "exec" ]- Each variant's fields are nested under a submodule named after the variant, eliminating any overlap between variants
For example:
providers = lib.mkOption {
type = t.nullOr (t.attrsOf (t.submodule { options = {
source = lib.mkOption { type = t.enum [ "env" "file" "exec" ]; };
env = lib.mkOption {
type = t.nullOr (t.submodule { options = {
allowlist = lib.mkOption { type = t.nullOr (t.listOf t.str); default = null; };
}; });
default = null;
};
file = lib.mkOption {
type = t.nullOr (t.submodule { options = {
path = lib.mkOption { type = t.str; };
mode = lib.mkOption { type = t.nullOr (t.enum [ "singleValue" "json" ]); default = null; };
maxBytes = lib.mkOption { type = t.nullOr t.int; default = null; };
timeoutMs = lib.mkOption { type = t.nullOr t.int; default = null; };
}; });
default = null;
};
exec = lib.mkOption {
type = t.nullOr (t.submodule { options = {
command = lib.mkOption { type = t.str; };
args = lib.mkOption { type = t.nullOr (t.listOf t.str); default = null; };
# ... remaining exec-only options
}; });
default = null;
};
}; }));
default = null;
};Usage would then look like:
secrets.providers.my-secrets = {
source = "file";
file = {
path = "/run/secrets/openclaw_json";
mode = "json";
};
};This keeps each variant's options cleanly separated with no field overlap, preserves full type safety (required fields like path and command stay non-nullable), and is idiomatic in the Nix module system.
The relevant place to fix this is likely in nix/scripts/generate-config-options.ts, in the oneOf handler — when all entries are submodules sharing a discriminator field, generate a single submodule with nested variant submodules instead of emitting t.oneOf.
Current Workaround
Patch the generated config JSON in a home.activation script after nix-openclaw writes it, using jq to inject secrets.providers outside of the Nix module system:
home.activation.openclawSecretsProviders =
lib.hm.dag.entryAfter [ "openclawConfigFiles" ] ''
config="$HOME/.openclaw/openclaw.json"
if [ -e "$config" ]; then
resolved="$(readlink -f "$config")"
${lib.getExe pkgs.jq} '
.secrets.providers["sops"] = {"source": "file", "path": "/run/secrets/openclaw_json", "mode": "json"}
' "$resolved" >| "$config.tmp"
run --quiet mv "$config.tmp" "$config"
fi
'';Related
- Generated config options broken: oneOf-of-consts should collapse to single enum #41 — similar codegen issue with
oneOf-of-consts (fixed), but this is the submodule variant of the same class of problem.
Environment
- nix-openclaw rev:
2b1e71bd01ee7984649ab18a4eaa76ada29d4575 - nixpkgs: NixOS 24.11
- Platform: x86_64-linux