enjoin¶
| Field | Value |
|---|---|
| Purpose | System state configuration — applies users, services, cron, network, firewall, certificates, SELinux, and more |
| Repo | AmadlaOrg/enjoin |
Overview¶
enjoin applies system state configuration. It is distinct from lay (installation) and weaver (template/config file generation). Where lay installs packages and applications, enjoin handles everything else that requires imperative system commands — creating users, enabling services, setting firewall rules, mounting filesystems, etc.
Each concern is handled by a fat plugin (enjoin-*) with multiple OS-aware backends built in. Backend selection is driven by the OS/Preference entity, with runtime detection as fallback.
Commands¶
| Command | Description |
|---|---|
enjoin apply --from <plugin> -f <data> |
Apply system state configuration via a plugin |
enjoin validate --from <plugin> -f <data> |
Dry-run validation — shows what would change without applying |
enjoin plugins |
List discovered enjoin plugins on PATH |
Dependencies¶
| Library | Purpose |
|---|---|
| LibraryEnjoinFramework | Enjoin plugin loading and communication |
Entity Types¶
| Entity | Plugin | What enjoin Does |
|---|---|---|
| User | enjoin-user | Creates/manages system users and groups |
| Service | enjoin-service | Manages systemd services |
| Security/Firewall | enjoin-firewall | Configures firewall rules |
| Cron | enjoin-cron | Manages scheduled tasks |
| System/Network | enjoin-network | Configures network interfaces and routes |
| System/Filesystem | enjoin-filesystem | Manages mounts and fstab entries |
| Security/Certificate | enjoin-certificate | Manages TLS certificates |
| Security/SELinux | enjoin-selinux | Manages SELinux policies |
| Security/AppArmor | enjoin-apparmor | Manages AppArmor profiles |
Pipeline Position¶
enjoin sits between lay (installation) and weaver (config file generation):
# Apply user configuration
enjoin apply --from user -f users.yaml
# Dry-run firewall changes
enjoin validate --from firewall -f firewall.yaml
# Pipeline: pipe entity from hery
hery entity get "amadla.org/entity/user@v1.0.0" | enjoin apply --from user
# List available plugins
enjoin plugins
How It Works¶
Entity (YAML/JSON) → enjoin apply --from <plugin> → enjoin-<plugin> apply -f <data>
│
OS-aware backend
(useradd, systemctl, ufw, etc.)
│
JSON result (stdout)
Exit 0=success, 1=failure
Plugin Selection Flow¶
Each enjoin plugin is a fat plugin — it contains multiple backends internally and selects the right one at runtime:
- Read OS/Preference entity (e.g.,
firewall: firewalld) enjoin-firewallreceives this and uses its firewalld backend- No OS entity? Runtime detect (probe for ufw, firewalld, iptables, nft)
- Entity says firewalld but system has ufw? Warn/error (reality doesn't match IaC)
Enjoin Plugins¶
| Plugin | Manages | Backends | Entity |
|---|---|---|---|
enjoin-user |
Users, groups, sudoers | useradd, groupadd | User |
enjoin-service |
System services | systemctl, init.d, rc-service | Service |
enjoin-firewall |
Firewall rules | ufw, iptables, nftables, firewalld | Security/Firewall |
enjoin-cron |
Scheduled tasks | crontab, systemd timers | Cron |
enjoin-network |
Network config | ip, nmcli, netplan, ifupdown | System/Network |
enjoin-filesystem |
Mounts, fstab | mount, fstab, tmpfs | System/Filesystem |
enjoin-certificate |
TLS certificates | certbot, openssl, mkcert | Security/Certificate |
enjoin-selinux |
SELinux policies | semanage, setsebool, restorecon | — |
enjoin-apparmor |
AppArmor profiles | aa-enforce, aa-complain | — |
enjoin-sysctl |
Kernel parameters | sysctl.conf | — |
Plugins are discovered via PATH (enjoin-* naming convention). Each plugin declares supported entity types via its info subcommand.
File Writing¶
enjoin plugins can write simple declarative files directly (cron entry, sudoers line, fstab mount) — these are direct expressions of the entity with no templating needed. If templating with entity data interpolation is required, pipe through weaver instead.
Security/Network vs System/Network¶
- Security/Network (firewall) = default posture: deny-all baseline, allowed protocols, rate limits
- System/Network = connectivity: interfaces, ports, DNS, routes
- System/Network
_requiresSecurity/Network — security baseline applied first - Declared ports in System/Network become implicit allow-list against Security/Network's deny-all