diff options
Diffstat (limited to 'openspec')
6 files changed, 127 insertions, 0 deletions
diff --git a/openspec/changes/archive/2026-09-24-add-automatic-timezone/.openspec.yaml b/openspec/changes/archive/2026-09-24-add-automatic-timezone/.openspec.yaml new file mode 100644 index 0000000..75289e4 --- /dev/null +++ b/openspec/changes/archive/2026-09-24-add-automatic-timezone/.openspec.yaml | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | schema: spec-driven | ||
| 2 | created: 2026-09-24 | ||
diff --git a/openspec/changes/archive/2026-09-24-add-automatic-timezone/design.md b/openspec/changes/archive/2026-09-24-add-automatic-timezone/design.md new file mode 100644 index 0000000..0037bd5 --- /dev/null +++ b/openspec/changes/archive/2026-09-24-add-automatic-timezone/design.md | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | ## Context | ||
| 2 | |||
| 3 | See `proposal.md` - Why. Current state: `modules/nixos/common.nix` sets `time.timeZone = lib.mkDefault "Etc/UTC";` and nothing ever updates it. Relevant constraints discovered while investigating the pinned `nixos-unstable` nixpkgs (`nixos/modules/services/system/automatic-timezoned.nix`, `nixos/modules/services/desktops/geoclue2.nix`, `nixos/modules/services/desktop-managers/plasma6.nix`, and `systemd`'s shipped `org.freedesktop.timedate1.policy`): | ||
| 4 | |||
| 5 | - `systemd`'s own default polkit policy requires `auth_admin` for `org.freedesktop.timedate1.set-timezone` for any subject, active or not. Nothing in nixpkgs relaxes that for GNOME. | ||
| 6 | - The KDE Plasma 6 module (`plasma6.nix`) adds its own polkit rule allowing an *active* session to call `set-timezone` without a prompt, backing Plasma's own automatic-timezone UI toggle. | ||
| 7 | - nixpkgs' GNOME module (`nixos/modules/services/desktops/gnome`) adds no equivalent rule. GNOME Settings' own "Automatic Time Zone" toggle (backed by `gnome-settings-daemon`'s datetime plugin) would therefore hit the default `auth_admin` prompt on this flake's NixOS hosts today - it isn't wired to a passwordless mechanism the way Plasma's is. | ||
| 8 | - `services.automatic-timezoned` (a small dedicated daemon) is nixpkgs' own DE-agnostic answer to this gap: when enabled it sets `time.timeZone = null;` itself, turns on `services.geoclue2` with its own `appConfig` entry, and ships a polkit rule scoped to its own dedicated `automatic-timezoned` system user - so it runs unattended regardless of desktop environment or which user is logged in. | ||
| 9 | |||
| 10 | ## Goals / Non-Goals | ||
| 11 | |||
| 12 | **Goals:** | ||
| 13 | - Every NixOS host's `time.timeZone` reflects actual physical location shortly after boot, with no manual step and no interactive authentication. | ||
| 14 | - The mechanism works the same regardless of which user (if any) is logged into the GNOME session, since it's a system service, not a per-session one. | ||
| 15 | |||
| 16 | **Non-Goals:** | ||
| 17 | - Making GNOME Settings' own "Automatic Time Zone" toggle functional. It's a separate, unwired mechanism on NixOS (see Context) and fixing that is out of scope - `automatic-timezoned` achieves the actual user-visible goal (correct system timezone, which GNOME's clock/calendar read directly from `time.timeZone`/`/etc/localtime`) without it. | ||
| 18 | - Manual/static location configuration (`services.geoclue2.enableStatic` + `location.latitude`/`longitude`). Network-based geolocation is sufficient for a desktop machine that's expected to have network access shortly after boot. | ||
| 19 | - Any change to `homeConfigurations` (standalone home-manager, no NixOS layer) - they have no `time.timeZone` to manage. | ||
| 20 | |||
| 21 | ## Decisions | ||
| 22 | |||
| 23 | **Use `services.automatic-timezoned.enable = true;` in `modules/nixos/common.nix`, rather than trying to make GNOME's own toggle work.** | ||
| 24 | |||
| 25 | Alternatives considered: | ||
| 26 | 1. **Add a NixOS polkit rule scoped to active GNOME sessions**, mirroring `plasma6.nix`'s `subject.active` rule, then rely on GNOME's own `gsd-datetime` plugin (toggled on via a `dconf` default, the same pattern already used for dark mode in `common.nix`). Rejected: this reverse-engineers and depends on `gsd-datetime`'s internal behavior, which isn't a stable, documented NixOS integration point the way `automatic-timezoned` is: it's exactly the gap `automatic-timezoned` exists to fill for GNOME. It would also only run while a graphical session is active, whereas `automatic-timezoned` is a system service independent of any login. | ||
| 27 | 2. **`services.automatic-timezoned.enable = true;`** (chosen): purpose-built for this exact scenario, self-contained (enables and configures its own `geoclue2` + polkit rule, no manual wiring), maintained in nixpkgs itself, and already proven for the same problem this repo solved for Docker (`container-runtime`) - prefer an existing, documented NixOS module over recreating its internals. | ||
| 28 | |||
| 29 | **Leave `time.timeZone = lib.mkDefault "Etc/UTC";` in place rather than removing it.** | ||
| 30 | |||
| 31 | `automatic-timezoned`'s module sets `time.timeZone = null;` at normal priority when enabled, which unconditionally overrides the existing `mkDefault`. Leaving the line in place costs nothing and keeps `Etc/UTC` as the documented, explicit fallback if `automatic-timezoned` is ever disabled again on a specific host, without needing to touch `common.nix` a second time. | ||
| 32 | |||
| 33 | ## Risks / Trade-offs | ||
| 34 | |||
| 35 | - **[Risk]** A host with no network access at boot (or geoclue2's beacondb.net lookup failing) never gets a timezone update, and stays on whatever was last applied (or `Etc/UTC` on first boot). → **Mitigation**: none needed for this repo's target hardware (desktops/laptops expected to have network shortly after boot); already called out as a known limitation in `proposal.md`. | ||
| 36 | - **[Risk]** GNOME's own "Automatic Time Zone" toggle in Settings remains visually present but functionally disconnected from what's actually keeping the timezone correct, which could read as broken/confusing if a user flips it expecting it to be the mechanism. → **Mitigation**: documented as a known limitation in `proposal.md`; the actual observable goal (correct time shown everywhere) is met regardless of that toggle's state, and no further UI work is planned here. | ||
| 37 | - **[Risk]** A future host that legitimately needs a fixed, non-default timezone must remember to set it at higher-than-default priority (`lib.mkForce` or a plain assignment beats `automatic-timezoned`'s normal-priority `null`, but a naive `lib.mkDefault` override would silently lose to it). → **Mitigation**: called out explicitly in `proposal.md`'s BREAKING/Impact notes; the module's own evaluation-time error (if a plain/default-priority conflicting value is set) makes a silent miss unlikely. | ||
| 38 | |||
| 39 | ## Migration Plan | ||
| 40 | |||
| 41 | Additive, single-file change (`modules/nixos/common.nix`) applied to every NixOS host on next `nixos-rebuild switch` (or equivalent activation). No data migration. Rollback is reverting the one-line addition and rebuilding; `time.timeZone` immediately falls back to the existing `Etc/UTC` default with no other state to clean up (the `automatic-timezoned`/`geoclue` system user and services are removed by NixOS's normal generation switch). | ||
diff --git a/openspec/changes/archive/2026-09-24-add-automatic-timezone/proposal.md b/openspec/changes/archive/2026-09-24-add-automatic-timezone/proposal.md new file mode 100644 index 0000000..6c2c77c --- /dev/null +++ b/openspec/changes/archive/2026-09-24-add-automatic-timezone/proposal.md | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | ## Why | ||
| 2 | |||
| 3 | Every NixOS host built from this flake currently defaults to `Etc/UTC` (`modules/nixos/common.nix`) and nothing ever changes that, so a freshly booted or freshly relocated machine shows the wrong local time/date everywhere (GNOME's clock, calendar, screenshots, log timestamps) until someone manually runs `timedatectl set-timezone`. Tom wants the timezone detected automatically instead. | ||
| 4 | |||
| 5 | ## What Changes | ||
| 6 | |||
| 7 | - Enable `services.automatic-timezoned` unconditionally on every NixOS host, in `modules/nixos/common.nix`, alongside the other unconditional host-level services (GNOME, SSH, printing). This is the NixOS-native daemon for this purpose: it uses `geoclue2` (which it enables and configures itself) to determine location and `systemd-timedated` to actually apply the timezone, and it ships its own polkit rule so the update happens automatically with no interactive auth prompt. | ||
| 8 | - The existing `time.timeZone = lib.mkDefault "Etc/UTC";` in `modules/nixos/common.nix` is left as-is: `automatic-timezoned` overrides it internally (`time.timeZone = null;`, at normal priority) whenever it's enabled, so `Etc/UTC` only remains as the boot-time value until the daemon determines and applies the real one shortly after boot (network permitting). No host in this repo (checked `hosts/test-vm`, the only real host, and `hosts/template`) sets `time.timeZone` explicitly, so there's no conflict with the module's requirement that an explicit timezone be set with a priority lower than default. | ||
| 9 | - **Not** relying on GNOME's own Settings → Date & Time → "Automatic Time Zone" toggle: NixOS's `systemd` package ships `org.freedesktop.timedate1.set-timezone` requiring `auth_admin` by default, and unlike the KDE Plasma module (`nixos/modules/services/desktop-managers/plasma6.nix`), nixpkgs' GNOME module adds no polkit rule to relax that for GNOME's own timezone daemon. `automatic-timezoned` ships and enables exactly that rule for its own dedicated service user, so it works without depending on GNOME-side authorization plumbing that isn't wired up on NixOS today. See `design.md` for the alternatives considered here. | ||
| 10 | - **BREAKING**: none — additive only. A host that later needs a fixed non-`Etc/UTC` timezone can still set `time.timeZone` at a priority higher than default (`lib.mkForce` or a plain assignment) in its own `configuration.nix`; doing so alongside this change without adjusting priority would now raise the same explicit "you set a timezone with `automatic-timezoned` enabled" evaluation error the upstream module already raises by design, which is the intended, deliberate-override behavior — not a silent conflict. | ||
| 11 | |||
| 12 | ## Capabilities | ||
| 13 | |||
| 14 | ### New Capabilities | ||
| 15 | - `automatic-timezone`: every NixOS host built from this flake keeps its system timezone (and therefore the desktop's clock/calendar) in sync with the host's actual location automatically, without manual `timedatectl` intervention or an interactive authorization prompt. | ||
| 16 | |||
| 17 | ### Modified Capabilities | ||
| 18 | (none) | ||
| 19 | |||
| 20 | ## Impact | ||
| 21 | |||
| 22 | - **Affected code**: `modules/nixos/common.nix` (add `services.automatic-timezoned.enable = true;`). | ||
| 23 | - **Not affected**: `modules/home/*` (home-manager-only `homeConfigurations` have no NixOS-level timezone service and are unaffected — they already inherit whatever timezone the host OS provides), `hosts/*/configuration.nix` (no host currently overrides `time.timeZone`), `lib/unfree-allowlist.nix` (`automatic-timezoned` is GPL-3.0, free). | ||
| 24 | - **Dependencies**: nixpkgs' `automatic-timezoned` and `geoclue2` packages, both already present in the pinned `nixos-unstable` input; no new flake inputs. `geoclue2`'s default network-based location source (`api.beacondb.net`) requires outbound internet access, which this repo's firewall config (inbound-only restrictions) doesn't block. | ||
| 25 | - **Platforms**: NixOS hosts only (`modules/nixos/common.nix`), via any host built by `lib/mkNixos.nix`. No effect on `homeConfigurations` (`tom@linux`, `tom@darwin`). | ||
| 26 | - **Known limitation, out of scope**: GNOME's own "Automatic Time Zone" toggle in Settings → Date & Time is not wired to this mechanism and may still prompt for authentication if the user flips it manually; the actual timezone is kept correct by the independent `automatic-timezoned` service regardless of that toggle's state. No reverse-geocoding/location-display UI is added — this only keeps `time.timeZone` current. Timezone detection is network-dependent (Wi-Fi/IP-based geolocation via `geoclue2`); a host with no network at boot keeps whatever timezone was last applied (or `Etc/UTC` on first boot) until connectivity returns. | ||
diff --git a/openspec/changes/archive/2026-09-24-add-automatic-timezone/specs/automatic-timezone/spec.md b/openspec/changes/archive/2026-09-24-add-automatic-timezone/specs/automatic-timezone/spec.md new file mode 100644 index 0000000..c9c50bf --- /dev/null +++ b/openspec/changes/archive/2026-09-24-add-automatic-timezone/specs/automatic-timezone/spec.md | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | ## Purpose | ||
| 2 | |||
| 3 | Keeps every NixOS host's system timezone in sync with its actual physical location automatically, so the system clock, GNOME's clock/calendar, and log timestamps reflect local time without any manual `timedatectl` step. | ||
| 4 | |||
| 5 | ## ADDED Requirements | ||
| 6 | |||
| 7 | ### Requirement: NixOS hosts detect and apply their timezone automatically | ||
| 8 | Every NixOS host built from this flake's shared system module SHALL determine its current timezone based on location and apply it to the system, without requiring the user to run a manual command or interactively authenticate the change. | ||
| 9 | |||
| 10 | #### Scenario: Timezone is applied after boot with network access | ||
| 11 | - **WHEN** a NixOS host built from this flake's shared system module boots with network connectivity available | ||
| 12 | - **THEN** the system's active timezone is set to the timezone matching the host's current location, without any interactive prompt | ||
| 13 | |||
| 14 | #### Scenario: No per-host opt-in required | ||
| 15 | - **WHEN** a NixOS host is built from this flake's shared system module and its own `hosts/<name>/configuration.nix` does not configure timezone detection itself | ||
| 16 | - **THEN** automatic timezone detection is still active, exactly as if it had been configured directly | ||
| 17 | |||
| 18 | ### Requirement: A host can still pin an explicit fixed timezone | ||
| 19 | A NixOS host built from this flake SHALL be able to override automatic detection with a fixed, explicitly configured timezone when that host's own configuration requires one. | ||
| 20 | |||
| 21 | #### Scenario: Host-level override takes effect | ||
| 22 | - **WHEN** a host's own `hosts/<name>/configuration.nix` sets an explicit timezone at a priority higher than the shared default | ||
| 23 | - **THEN** that host uses the explicitly configured timezone instead of an automatically detected one | ||
diff --git a/openspec/changes/archive/2026-09-24-add-automatic-timezone/tasks.md b/openspec/changes/archive/2026-09-24-add-automatic-timezone/tasks.md new file mode 100644 index 0000000..e139bbd --- /dev/null +++ b/openspec/changes/archive/2026-09-24-add-automatic-timezone/tasks.md | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | ## 1. Enable automatic timezone detection | ||
| 2 | |||
| 3 | - [x] 1.1 Add `services.automatic-timezoned.enable = true;` to `modules/nixos/common.nix`, alongside the other unconditional host-level services | ||
| 4 | - [x] 1.2 Verify `nix eval '.#nixosConfigurations.test-vm.config.services.automatic-timezoned.enable'` (or the appropriate real host output) evaluates to `true`, and that `.config.services.geoclue2.enable` and `.config.time.timeZone` evaluate to `true` and `null` respectively (confirming `automatic-timezoned` took over from the `Etc/UTC` default as expected) — this repo has no host tracked in git today (`hosts/test-vm` is a local-only scratch VM excluded via `.git/info/exclude`, so it's invisible to the flake's git-tree evaluation and `nixosConfigurations` is currently empty); verified instead via a synthetic `nixpkgs.lib.nixosSystem` built directly from `modules/nixos/common.nix`, confirming `services.automatic-timezoned.enable = true`, `services.geoclue2.enable = true`, and `time.timeZone = null` | ||
| 5 | |||
| 6 | ## 2. Verification | ||
| 7 | |||
| 8 | - [x] 2.1 Run `nix flake check` and confirm it passes | ||
| 9 | - [x] 2.2 Run `nix build '.#nixosConfigurations.test-vm.config.system.build.toplevel'` (or the appropriate real host output) and confirm it succeeds — same test-vm caveat as 1.2; built the synthetic `nixosSystem`'s `config.system.build.toplevel` instead, which succeeded natively (this machine is aarch64-linux) and produced a closure including the `automatic-timezoned`, `automatic-timezoned-geoclue-agent`, `geoclue`, and `systemd-timedated` units | ||
| 10 | - [x] 2.3 Run `nix fmt` and confirm `modules/nixos/common.nix` is formatted with no diff | ||
diff --git a/openspec/specs/automatic-timezone/spec.md b/openspec/specs/automatic-timezone/spec.md new file mode 100644 index 0000000..a14ef6a --- /dev/null +++ b/openspec/specs/automatic-timezone/spec.md | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | # automatic-timezone Specification | ||
| 2 | |||
| 3 | ## Purpose | ||
| 4 | |||
| 5 | Keeps every NixOS host's system timezone in sync with its actual physical location automatically, so the system clock, GNOME's clock/calendar, and log timestamps reflect local time without any manual `timedatectl` step. | ||
| 6 | |||
| 7 | ## Requirements | ||
| 8 | |||
| 9 | ### Requirement: NixOS hosts detect and apply their timezone automatically | ||
| 10 | Every NixOS host built from this flake's shared system module SHALL determine its current timezone based on location and apply it to the system, without requiring the user to run a manual command or interactively authenticate the change. | ||
| 11 | |||
| 12 | #### Scenario: Timezone is applied after boot with network access | ||
| 13 | - **WHEN** a NixOS host built from this flake's shared system module boots with network connectivity available | ||
| 14 | - **THEN** the system's active timezone is set to the timezone matching the host's current location, without any interactive prompt | ||
| 15 | |||
| 16 | #### Scenario: No per-host opt-in required | ||
| 17 | - **WHEN** a NixOS host is built from this flake's shared system module and its own `hosts/<name>/configuration.nix` does not configure timezone detection itself | ||
| 18 | - **THEN** automatic timezone detection is still active, exactly as if it had been configured directly | ||
| 19 | |||
| 20 | ### Requirement: A host can still pin an explicit fixed timezone | ||
| 21 | A NixOS host built from this flake SHALL be able to override automatic detection with a fixed, explicitly configured timezone when that host's own configuration requires one. | ||
| 22 | |||
| 23 | #### Scenario: Host-level override takes effect | ||
| 24 | - **WHEN** a host's own `hosts/<name>/configuration.nix` sets an explicit timezone at a priority higher than the shared default | ||
| 25 | - **THEN** that host uses the explicitly configured timezone instead of an automatically detected one | ||
