feat: add User module (closes #46) #47

Merged
yorunikakeru merged 14 commits from feature/issue-46-users into main 2026-06-22 21:08:37 +02:00
Owner

What

Adds User module so configs can declare system users:

User.user "alice" $ do
    User.isNormalUser True
    User.description "primary user"
    User.extraGroups ["networkmanager", "wheel", "docker"]
    User.packages ["steam", "wine"]

Changes

IR (frogos-ir — pushed to main, flake.lock updated):

  • IRDocument gains irUsers :: [UserConfig]; JSON key "users" (omitted when empty)
  • Schema version bumped to 7

DSL (this branch):

  • User module: UserBuilder, user, isNormalUser, description, extraGroups, packages
  • Builder.Config: addUserConfig, csUsers in ConfigState, wired into configuration
  • Validate.Types: DuplicateUserName Text constructor in ValidationError
  • Validate.Users: duplicateUserError — rejects configs with duplicate usernames
  • 9 new tests (143 total, all passing)

Verification

  • stan — clean
  • cabal test — 143/143 pass
  • nix flake check — all checks pass

Closes #46

## What Adds `User` module so configs can declare system users: ```haskell User.user "alice" $ do User.isNormalUser True User.description "primary user" User.extraGroups ["networkmanager", "wheel", "docker"] User.packages ["steam", "wine"] ``` ## Changes **IR** (`frogos-ir` — pushed to main, flake.lock updated): - `IRDocument` gains `irUsers :: [UserConfig]`; JSON key `"users"` (omitted when empty) - Schema version bumped to 7 **DSL** (this branch): - `User` module: `UserBuilder`, `user`, `isNormalUser`, `description`, `extraGroups`, `packages` - `Builder.Config`: `addUserConfig`, `csUsers` in `ConfigState`, wired into `configuration` - `Validate.Types`: `DuplicateUserName Text` constructor in `ValidationError` - `Validate.Users`: `duplicateUserError` — rejects configs with duplicate usernames - 9 new tests (143 total, all passing) ## Verification - `stan` — clean - `cabal test` — 143/143 pass - `nix flake check` — all checks pass Closes #46
style: formatted
All checks were successful
CI / linux (pull_request) Successful in 1m9s
9c8eaf8fa8
refactor(builder): unify policy accumulation via PolicyAccum
Some checks failed
CI / linux (pull_request) Failing after 1m8s
061c841fef
Each module builder was calling policiesFromPortSpecs per port,
producing duplicate allow_ports policies instead of one merged set.
PolicyAccum collects PortSpecs (for dedup) and raw Policies, then
finalizes both once at build time.
style: formetted
All checks were successful
CI / linux (pull_request) Successful in 1m6s
17034e4599
refactor(builder): drop PolicyAccum, use IR types directly in builders
All checks were successful
CI / linux (pull_request) Successful in 1m9s
d1c5590429
NginxVHostState duplicated NginxVirtualHost — removed in favour of
StateT NginxVirtualHost. Forgejo and PostgreSQL builders already used
their IR configs directly; pattern is now uniform across all modules.

Policy deduplication was dropped: each port call appends its own
allow_ports entry. No runtime exists yet to require merged policies.
feat(network): separate allow_ports from module policies, add global irNetwork
Some checks failed
CI / linux (pull_request) Failing after 1m58s
966ffe5b49
- Network.allowPorts: now ConfigBuilder (), writes to IRDocument.irNetwork
  (global, document-level) instead of profilePolicies
- Network.Policy: remove AllowPorts branch from policiesFromPortSpecs;
  only Fallback policies remain (generated by withFallback in module builders)
- Builder.Types.ConfigState: add csNetwork :: NetworkConfig
- Builder.Config: propagate csNetwork to IRDocument.irNetwork
- flake.lock: update frogos-ir to IR v8 (NetworkConfig, no AllowPorts)
- Tests and golden fixtures updated accordingly
feat: state-mutating actions carry priority
Some checks failed
CI / linux (pull_request) Failing after 1m59s
1d69b35073
RestartModule and SetPowerProfile now carry an Int priority, matching
the EnableModule/DisableModule pattern. Plain DSL forms (restart,
setPowerProfile) default to 100; withPriority variants allow explicit
control.

Conflict detection extended: restart vs disable on the same module is
now an intra- and inter-profile conflict (restart implies running,
disable implies not). Two SetPowerProfile actions in the same profile
or across profiles at equal priority are also validation errors.

IR bumped to version 9; all golden fixtures updated.
style: formatted
All checks were successful
CI / linux (pull_request) Successful in 1m6s
5292baa702
choire: flake update
All checks were successful
CI / linux (pull_request) Successful in 2m1s
aa72e4cba1
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
FrogOS/DSL!47
No description provided.