Commit Graph
29 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5 fc0881ff33 fix(env): point python at the OS trust store
The package-cache frontend terminates TLS for package traffic and signs
with its own CA: probed from inside the test container, pypi.org arrives
as subject CN=pypi.org issued by CN=Infinito Package-Cache Frontend CA.
package-frontend-ca.sh installs that CA into the OS store, which is why
apt, pip, curl and urllib work — but requests reads certifi, which has
never heard of it, so test-external failed its reachability precondition
with CERTIFICATE_VERIFY_FAILED. Upgrading certifi does not help; the
issuer is not a public root.

load.sh is where the runner puts the venv on PATH, so it is also where the
interpreter carrying the pip certifi is chosen; pointing REQUESTS_CA_BUNDLE
and SSL_CERT_FILE at the store the stack deliberately fills keeps one trust
decision instead of two. A caller-set value still wins.

The bundle location was about to become a fourth copy: dev-nix and the
network diagnose CLI each carried their own candidate list, and the two had
already drifted apart in their fourth entry. All of them now read
group_vars CA_BUNDLE_CANDIDATES — Ansible directly, the shell through a
generated env key, python through read_group_paths.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 18:55:58 +02:00
kevinveenbirkenbachandClaude Opus 5 575a5a87ac refactor(layout): sort shipped scripts by language and split the unit suite
Every script a role ships now lives under `files/<language>/`, and the unit
suite is split the same way: `tests/unit/python/` beside new sibling trees for
the other languages. `tests/lint/filesystem/test_role_files_layout.py` keeps it
that way; directories whose shape is dictated from outside carry a `.nocheck`
naming the constraint (Docker build contexts, WordPress mu-plugins, the Joomla
extension, Odoo addons, Playwright suites, the `files/test/test.sh` harness
that `test-e2e-cli` resolves generically).

This cannot be applied in halves. Moving a file and repointing what names it
are the same change: 14 references resolve only at deploy time, so the tree is
green either before or after, never between.

Those 14 were found by static resolution over every reference class, not by the
test suite -- a full `make quality-high` was green while all of them were
broken:

  * 7 `src:` values built from a role variable holding a bare filename
    (svc-bkp-remote-2-local, decidim, espocrm, friendica, joomla, pixelfed x2).
    The variable doubles as the destination name inside the container, so the
    language segment belongs at the call site, not in the variable.
  * `sys-service/tasks/04_base.yml` resolved every consumer's systemd script
    through `first_found(..., errors='strict')` over `files/script.{sh,py}`.
    18 roles ship exactly that and have no template fallback: the play would
    have died on each.
  * `sys-front-inj-javascript` fell back to `<role>/files/javascript.js`; the
    interface now reads `files/javascript/javascript.js`.
  * `sys-front-inj-logout/templates/head_sub.j2` built the cache-busting mtime
    path through `path_absolute(... 'files', ...)`.
  * 4 `ansible.builtin.script:` invocations naming a bare command
    (pull.py, prune.sh, set_postgres_superuser_password.sh, ganesha-serve.sh).
  * `dev-python/files/shell/install.sh` pointed at a sibling role's script.

Depth-dependent paths inside the moved trees were bumped accordingly: 59
`parents[N]` computations, 12 relative climbs, and the per-role recover CLI,
whose path `cli/administration/recover/recoverers.py` still assembled from the
pre-move location.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 01:31:09 +02:00
kevinveenbirkenbachandClaude Opus 5 93b47a5bee refactor(packages): install every package through the registry
Replaces the raw package modules at 76 call sites with package_install, moves
each role's distribution mapping into its own meta/packages.yml, and turns the
inventory PACKAGES variable from source-keyed literal names into a list of
declared package ids. The lint that forbids the raw modules is enabled here,
because the migration burns it down from 76 offenders to zero.

Removes sys-aur, sys-aur-install and sys-package. The AUR build user, the
passwordless pacman rule and the inventory-driven install are part of the plan
the action plugin executes, so the roles no longer carry them.

Declaring the mappings surfaced breakage the raw modules had hidden: on Debian
the `which` binary comes from debianutils, jrnl is in no Debian or Ubuntu
suite, chromium-browser is absent from Debian stable, JDK 11 is unobtainable on
RedHat, wireguard had no RedHat branch at all, qbittorrent was built from the
AUR although Arch ships it in extra, and desk-docker installed a Docker variant
that conflicts with the one sys-svc-container installs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 23:25:50 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4039313266 refactor(tasks): enforce and apply a single task-file numbering scheme
Add tests/lint/repository/test_task_file_numbering.py: numbered task
files use exactly two leading digits, a numbered *_core.yml must be
00_core.yml, per directory the numbers are unique/consecutive and start
at 01 (00 with a core file), numbered includes appear in ascending
order, and shared helpers live in tasks/utils/ instead of the numbered
chain.

Apply it across every role: rename NN_core.yml to 00_core.yml with a
consecutive down-shift of the siblings, move letter-suffix children into
a subdirectory named after their parent task, relocate helpers included
from more than one place into tasks/utils/, and update every reference
(include_tasks, path_absolute, .ansible-lint-ignore, requirement docs).
Legacy narration comments in the touched files are deleted; the upstream
xwiki.properties reference block opts out via nocheck. The unused
MAILU_IP6_PUBLIC var (only ever named in now-removed comments) is dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 20:01:31 +02:00
kevinveenbirkenbachandClaude Opus 4.8 96aa7784b6 feat(sys-svc-compose): scale all task timeouts via TIMEOUT_FACTOR lookup
Add a 'timeout' lookup plugin that returns round(base * TIMEOUT_FACTOR)
(group_vars default 1, so value-identical to the old literals). One knob
in group_vars stretches every wait in the stack for a slow uplink:
TIMEOUT_FACTOR: 2 doubles them all.

- plugins/lookup/timeout.py + unit tests (identity, factor scaling,
  string coercion, error paths).
- group_vars/all/17_resource.yml: TIMEOUT_FACTOR: 1.
- Convert all 34 literal 'timeout:' task keywords / module args across 25
  task+handler files to "{{ lookup('timeout', <base>) | int }}".
- tests/lint/repository/yaml/test_timeout_uses_lookup.py enforces the
  lookup in every task/handler timeout (opt-out: # nocheck: timeout-lookup).
- swarm.yml pre-deploy build handler: add the missing timeout (same
  network-build hang vector as compose.yml's Build compose).
- Drop 13 pre-existing narration comments in the touched files (comment
  lint enforces whole-file on any edited file).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 13:57:30 +02:00
kevinveenbirkenbachandClaude Opus 4.8 cddb0dc59b feat(lint): require emoji-prefixed task/step/job names + convert existing
Add tests/lint/repository/test_name_emoji_and_length.py: every Ansible task
name and GitHub Actions workflow/job/step name must start with an emoji (first
char not 0-9/A-Za-z) and be <= 80 chars.

- emit emoji names at the source: cli/build/include generator now writes
  "🔧 setup <app>" / "🚿 flush handlers after <app>" so generated
  tasks/groups/*-roles.yml satisfy the convention too
- convert existing task/step/job/workflow names to emoji-prefixed, choosing a
  task-fitting icon per action (📦 install, ✅ ensure, 🔍 probe, 🥾 bootstrap,
  🚀 deploy, 🧩 service-module load, ⬇️ checkout, 📂 include-routines, ...)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 22:45:06 +02:00
kevinveenbirkenbachandClaude Opus 4.7 ae81df392b style(dev-nix): autoformat collapse double-space before inline nocheck directive
`make autoformat` (mbake) rewrites multi-whitespace gaps in YAML
inline comments to a single space. Pure formatting touch on the
`# nocheck: stack-host-template` marker, no functional change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 19:02:58 +02:00
kevinveenbirkenbachandClaude Opus 4.7 05f6a97bd8 refactor(stack_host_template): generalise IS_STACK_HOST template wrapper across the codebase
Renames the local action plugin from `conf_template` to
`stack_host_template` so the name carries the actual semantics
(IS_STACK_HOST gate, not nginx config), broadens the lint guard to
every bare `template:` task, and migrates every consumer found in the
audit.

Plugin / tests / lint:
  * plugins/action/conf_template.py -> plugins/action/stack_host_template.py
    (drop nginx-specific docstring; trust_as_template gate unchanged)
  * test_conf_template.py            -> test_stack_host_template.py
  * test_conf_template_migration.py  -> test_stack_host_template_migration.py
    Scope expanded from `.conf.j2` to every `template:` task; marker
    renamed to `nocheck: stack-host-template`.

Migrations (~50 tasks now using stack_host_template:):
  * sys-svc-compose/04_files.yml: compose.yml, .env, Dockerfile,
    compose.override (every per-app compose-tree file)
  * web-app-keycloak: sso_proxy upstream-config (fixes the friendica
    CI failure that prompted this refactor) + realm-import
  * web-app-taiga, web-app-matrix, web-app-opentalk, web-app-pgadmin,
    web-app-moodle, web-app-listmonk, web-app-littlejs, web-app-fediwall,
    web-app-wordpress, web-app-discourse, web-app-bigbluebutton,
    web-app-jenkins, web-app-jitsi, web-app-mobilizon, web-app-suitecrm,
    web-app-decidim, web-app-dashboard, web-app-nextcloud, web-app-xwiki,
    web-app-mailu, web-app-magento, web-app-odoo, web-app-prometheus,
    web-app-matrix, web-app-peertube, web-app-mailu (+ existing `conf_template:`
    callers updated to the new name)
  * sys-front-tls, svc-db-openldap, sys-svc-webserver-core,
    sys-svc-rdbms (dedicated DB env + initdb), sys-front-inj-css,
    sys-front-inj-dashboard, sys-front-inj-all, sys-stk-front-proxy,
    web-svc-cdn-css, web-svc-xmpp, web-svc-legal, web-svc-simpleicons,
    web-opt-rdr-domains

Nochecks (per-host or already-structurally-stack-host):
  * sys-svc-mail-smtp/postfix, sys-svc-sshd, sys-svc-container/daemon.json
  * sys-timer, sys-service, sys-svc-mail-msmtp, sys-svc-journalctl,
    sys-daemon, sys-svc-compose/utils/_render_one_template (delegate_to
    stack host with peer slurp dance)
  * dev-locales, dev-nix, desk-*, user, user-backup, user-workstation
  * svc-storage-nfs-server/exports, test-e2e-playwright stage dirs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 15:45:38 +02:00
kevinveenbirkenbachandClaude Opus 4.7 2921ab6f03 feat(ansible): conf_template action plugin enforces IS_STACK_HOST gate
Adds plugins/action/conf_template.py, a drop-in `template:` replacement
that returns `skipped: true` whenever IS_STACK_HOST evaluates to false.
Routes the rendered Jinja through ansible.module_utils.parsing.convert_bool
so both Python bool and string "True"/"False" templar outputs resolve
correctly. Inherits every standard template module argument.

Migrates seven nginx-tree consumers that previously aborted on workers
with "Destination directory does not exist": sys-front-tls,
svc-db-openldap, sys-svc-webserver-core (nginx.conf + default_server.conf),
web-app-matrix (synapse vhost), web-app-peertube (per-domain vhost),
web-opt-rdr-domains (redirect vhost), and web-app-prometheus.

Tags twelve legitimate bare `template:` callers with
`# nocheck: conf-template`: per-host system configs (locale, nix, systemd
manager defaults, journald, msmtprc) and per-app compose-dir configs
(magento x2, mailu x2, moodle, odoo, taiga) that intentionally bypass the
project's nginx tree.

Adds tests/lint/ansible/modules/test_conf_template_migration.py as the
drift guard: any future `template:` task whose `src:` ends in `.conf.j2`
must adopt conf_template or carry the nocheck marker. Adds seven unit
tests for the plugin covering skip semantics, dispatch, mode defaults,
mode overrides, full-arg passthrough, and the string-bool templar path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 22:25:13 +02:00
kevinveenbirkenbach a7fbca5b09 Merge branch 'main' into feature/web-app-jitsi 2026-06-01 15:33:30 +02:00
kevinveenbirkenbachandClaude Opus 4.7 033495d42f fix(dev-nix): guard nixbld set_fact against getent fail_key: false None values
Cherry-pick of bdc5945bc from feature/web-app-zammad, retargeted at
roles/dev-nix/tasks/02a_nix_install_only.yml (the include_tasks
companion file that 201670975 introduced on this branch).

Same root cause + fix as on the zammad branch:

  TASK [dev-nix : Set build group override for Nix installer when nixbld exists]
  Error while resolving value for 'dev_nix_installer_build_group_id':
  object of type 'NoneType' has no attribute 1

`getent` with `fail_key: false` inserts the key with a `None` value
when the entry is missing, so the membership test `'nixbld' in
ansible_facts.getent_group` evaluates True but `getent_group.nixbld[1]`
crashes on None. The guard now explicitly checks the value with
`is not none` for both `nixbld` (group) and `nixbld1` (passwd).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:51:13 +02:00
kevinveenbirkenbachandClaude Opus 4.7 f27e6337ee fix(dev-nix): guard nixbld set_fact against getent fail_key: false None values
CI run 26643336674 (feature/web-app-zammad) failed at:

  TASK [dev-nix : Set build group override for Nix installer when nixbld exists]
  Error while resolving value for 'dev_nix_installer_build_group_id':
  object of type 'NoneType' has no attribute 1

Root cause: `getent` with `fail_key: false` does NOT drop the key when
the entry is missing — it inserts the key with a `None` value. The
existing `when:` guard `'nixbld' in ansible_facts.getent_group`
therefore evaluates True (the membership test only checks the key, not
the value), and `getent_group.nixbld[1]` then crashes when the value
is None.

Fix: replace the membership check with an explicit `is not none`
assertion for both `nixbld` (group entry) and `nixbld1` (passwd entry).
A short comment above each `when:` block names the trap so the next
reader does not re-introduce the membership-only check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:43:25 +02:00
kevinveenbirkenbachandClaude Opus 4.7 201670975d refactor(dev-nix): factor Nix install steps into include_tasks to satisfy when-block lints
Two pre-existing lint failures on main (introduced in 45eea2892) blocked
`make test` from going green:

- test_excessive_repeated_when_in_tasks_files flagged the four
  `when: dev_nix_binary_path_before | length == 0` repeats across
  Purge / getent group / getent passwd / Run-installer tasks.
- test_blocks_with_when_and_sections_have_max_three_tasks rejects any
  `block:` carrying a block-level `when:` and more than 3 tasks per
  section, because the block-level `when:` does NOT skip parse-time
  resolution of inner tasks.

Final shape: the six install tasks live in
`02a_nix_install_only.yml` and are pulled in via a single
`include_tasks` guarded by the original `when:`. When the binary is
already present, Ansible never opens the included file at all.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:54:45 +02:00
kevinveenbirkenbachandClaude Opus 4.7 a52d2e626f refactor(dev-nix): extract official-installer branch to 03_install_official.yml
Adding the purge task pushed dev-nix/tasks/02_non_arch_installer.yml
to 4 tasks gated by `when: dev_nix_binary_path_before | length == 0`,
tripping tests.integration.roles.when.test_duplication.

A `block:` would satisfy that lint but exceeds the project convention
of max 3 entries per block. Move the six install-branch tasks (purge,
nixbld group+uid probes, override set_facts, installer run) into a
dedicated tasks/03_install_official.yml and call it once via
include_tasks with the original guard `when:` on the include.

Behavior unchanged; inner tasks no longer re-evaluate the binary-path
condition each call.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:32:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 45eea2892f fix(dev-nix): purge stale nixbld users blocking Nix installer
The Nix 2.32.4 installer allocates build users ascending from
NIX_FIRST_BUILD_UID. The pkgmgr-centos:stable base image ships
nixbld1..nixbld32 with descending UIDs (RHEL `useradd -r` default:
nixbld1=997, nixbld2=996, ...) and no nix binary, so the role
detects no install, runs the installer, which then aborts on
"nixbld2 already exists, but with the UID '996'".

Add purge_stale_nixbld.sh, called via ansible.builtin.script
before the installer. Three guards must all hold to purge:
  1. No nix binary in candidate paths.
  2. nixbld2 UID < nixbld1 UID (broken descending layout).
  3. /nix/store does not exist (no live store to orphan).

Idempotent. Distro-agnostic at the script level: Debian/Ubuntu stay
[UNCHANGED] because guard 2 fails (nixbld users absent); Arch never
hits this code path. Production hosts with /nix/store present but
nixbld users get [FAIL] (rc=1) instead of silent destruction.

Fixes the 31/32 test-deploy-server / test-deploy-universal failures
observed in run 26634712613.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:09:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 951f6d36d2 chore(lint): unify autoformat/galaxy parallelism into one PARALLEL env var
* scripts/lint/autoformat.sh: rename AUTOFORMAT_PARALLEL to PARALLEL,
  declare it at file start with default `true`; still env-overridable.
  Reword the worker comment so the literal `# shellcheck` token no
  longer appears at start-of-line and trips SC1072/SC1073.
* scripts/lint/galaxy.sh: drop the GALAXY_FATAL / GALAXY_NAMESPACE /
  GALAXY_PARALLEL env vars (over-engineered for a single repo). Failure
  is always fatal. NAMESPACE is an internal constant. Add the same
  PARALLEL env var (default `true`, env-overridable); falsy demotes the
  xargs fan-out to one worker.
* docs/contributing/environment/variables.md: collapse the four
  AUTOFORMAT_*/GALAXY_* rows into one `PARALLEL` row covering both
  consumers.
* docs/contributing/tools/make.md: refer to `PARALLEL=0` everywhere;
  add the lint-galaxy parallelism note.

Plus working-tree drift across roles/, group_vars/, inventories/, and
tasks/ that accumulated from the make-test setup phase regenerating
generated artefacts during recent test runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 00:59:24 +02:00
kevinveenbirkenbachandClaude Opus 4.7 311bbfc809 refactor(lint): catch FQCN shell blocks + extract 4 violators
Inline-script-size lint regex previously matched only bare keys
(shell:/command:/script:/raw:/run:). Extended to also catch FQCN
forms (ansible.builtin.*, ansible.legacy.*, ansible.windows.win_shell)
which are interchangeable in Ansible and must be linted identically.

Four pre-existing violations exposed and fixed by extracting the
shell bodies to files/ and calling them via ansible.builtin.script:

  - sys-cleanup/main.yml (21 logical lines)
    -> files/cleanup_caches.sh
  - svc-db-openldap/06_migrate_005.yml (30 logical lines)
    -> files/migrate_005_purge_stale.sh (4 args, no_log preserved)
  - dev-nix/02_non_arch_installer.yml (24 logical lines)
    -> files/aggressive_prune_nix.sh (1 arg)
  - web-app-espocrm/01_patch_config.yml (13 logical lines)
    -> files/set_siteurl.sh (URL via env, fixes quote injection
       risk in original Jinja-into-PHP-single-quoted body)

Removed cargo-culted args.executable: /bin/bash from the four
script: tasks; the script: module ignores it (shebang controls
interpreter).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 09:26:33 +02:00
kevinveenbirkenbach de555f6bc3 add get_url_retry plugin and migrate get_url usages 2026-03-19 01:58:11 +01:00
kevinveenbirkenbach c6f5fdea15 refactor plugins layout and migrate uri calls to uri_retry 2026-03-19 01:41:07 +01:00
kevinveenbirkenbach fe55c5e85f fix(dev-nix): configure CA trust bundle for nix TLS 2026-02-22 20:57:59 +01:00
kevinveenbirkenbach 7a804fa083 Refactored to buildin snippet 2026-02-22 15:30:50 +01:00
kevinveenbirkenbach 63aa589d10 fix(dev-nix): harden nix detection and installer reuse handling 2026-02-22 13:39:36 +01:00
kevinveenbirkenbach 8a81630391 Added newline at file and POSIX compatible 2026-02-04 19:49:56 +01:00
kevinveenbirkenbach 456bc6f5f0 ci: add aggressive cleanup for docker, nix and system caches to prevent disk pressure
Introduce a new sys-cleanup role to perform cross-distro cleanup (apt, pacman,
dnf, yum, language caches, temp dirs and journald) for CI/container environments.

Add aggressive Docker prune handler (system + buildx + builder + log truncate)
to prevent GitHub Actions images from growing uncontrollably.

Integrate Nix garbage collection and store optimisation for CI runs.

Cleanup is guarded by MODE_CLEANUP and DOCKER_IN_CONTAINER to ensure it never
runs on real production hosts.

https://chatgpt.com/share/6967ad99-8e50-800f-b4e9-4cd8e45c29bc
2026-01-14 16:28:20 +01:00
kevinveenbirkenbach ca1809a25a feat(dev-nix): enable shell integration by default and finalize official installer flow
- Enable Nix shell snippet by default for reliable PATH setup
- Remove unused vendored installer file
- Ensure /usr/local/bin/nix symlink for systemd and non-login environments
- Always create /etc/nix and deploy nix.conf
- Clarify role description and promote lifecycle to beta

https://chatgpt.com/share/695e483c-1f68-800f-9f94-87d5295b871d
2026-01-07 14:12:28 +01:00
kevinveenbirkenbach 7359e88f88 fix(dev-nix): use official installer on non-Arch x86_64 and fix localhost become
- Restrict pacman-based Nix install to Arch Linux x86_64 only
- Use official Nix installer as fallback on ARM and other platforms
- Prevent sudo usage on localhost when fetching installer checksum
- Align README with actual online, verified installer behavior

https://chatgpt.com/share/695e483c-1f68-800f-9f94-87d5295b871d
2026-01-07 12:49:04 +01:00
kevinveenbirkenbach fd54faff65 refactor(ansible): replace pacman installs with package
Migrate most roles from community.general.pacman to the generic package module for better portability. Keep pacman where it is required (system upgrades and Arch-specific tasks). Split VirtualBox setup into an Arch-only task file and add a warning when skipped on non-Arch systems. Update integration test examples accordingly.

https://chatgpt.com/share/6947ce9f-3228-800f-8365-2253b5ed9451
2025-12-21 11:40:10 +01:00
kevinveenbirkenbach f143ce258c dev-nix: migrate to official installer with dynamic SHA256 verification,
split non-Arch logic, add template-based nix.conf, and integrate into pkgmgr

- Replace local installer mechanism with official upstream URLs:
  https://releases.nixos.org/nix/nix-<version>/install
  and dynamically fetch associated SHA256 checksum
- Add version-based URL construction via new defaults variables
- Implement clean OS-branching:
  * Arch-based systems: install Nix via pacman
  * Non-Arch systems: download installer + verify SHA256 + run in daemon mode
- Extract non-Arch installation logic into dedicated task file
  (02_non_arch_installer.yml)
- Introduce template-based /etc/nix/nix.conf with build-users-group
  and optional experimental-features block
- Remove obsolete install.yml
- Update pkgmgr dev stack to include dev-nix and adjust update command
- Add TODO.md for future security improvements

https://chatgpt.com/share/6939bbfe-5cb0-800f-8ea8-95628dc911f5
https://chatgpt.com/share/6939bbd9-4840-800f-b9d2-b2510ea0f105
2025-12-10 19:29:04 +01:00
kevinveenbirkenbach 486a98af3e Add new dev-nix role for secure offline Nix installation
This commit introduces the new 'dev-nix' Ansible role, which installs the
Nix package manager in a secure and reproducible way using a locally stored,
SHA256-verified installer script.

Key features:
- Local pinned installer (no network download during execution)
- SHA256 checksum validation to prevent execution of modified installers
- Multi-user (daemon) installation mode
- Optional shell integration via /etc/profile.d
- Fully idempotent, distro-agnostic design

This role matches the structure and conventions of existing dev-* roles
in the Infinito.Nexus ecosystem.

https://chatgpt.com/share/69387c73-bf3c-800f-abcd-c5e7d3717059
2025-12-09 20:46:15 +01:00