From d292297b6ad179e4664c01ad07cddaefff12f769 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Fri, 18 Sep 2026 12:57:00 +0000 Subject: [PATCH] Squashed 'roles/pipeline/' changes from 78afffe..c13f726 c13f726 Add optional pipeline operator enrollment git-subtree-dir: roles/pipeline git-subtree-split: c13f726a0a846180a1aa95d110b8bbc801edaae5 --- README.md | 34 +++++++++++++++++++--------------- defaults/main.yml | 1 + meta/argument_specs.yml | 5 +++++ tasks/main.yml | 15 +++++++++++++++ tests/integration | 6 +++--- 5 files changed, 43 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f403f7f..53ed4c2 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ group before the remaining configuration-bearing dependencies run. | --- | --- | | `dnd_pipeline_runtime_user` | `narratio` | | `dnd_pipeline_runtime_group` | `narratio` | +| `dnd_pipeline_operator_users` | `[]` | | `dnd_pipeline_config_directory_mode` | `0755` | | `dnd_pipeline_config_file_mode` | `0644` | @@ -259,8 +260,8 @@ inspection shows enabled sources, inferred dependencies, and generated family members; the diff shows the overlay's profile selections without modifying managed files. -Storage and publishing, operator selection and group-membership management, -scheduling, and end-to-end external execution remain deferred. +Storage and publishing, scheduling, and end-to-end external execution remain +deferred. ### Shared execution filesystem @@ -269,27 +270,30 @@ scheduling, and end-to-end external execution remain deferred. `narratio:narratio` mode `2775` **setgid** directories. Their access and default ACLs retain owner and group write access plus world read/traverse access for newly created content. The pipeline may run as `narratio` or as a human -account already in the selected runtime group; the production role neither -selects people nor manages their group membership. For example, a consumer -play can manage its selected operator separately: +account in the selected runtime group. Consumers can enroll selected existing +human accounts through the role interface: ```yaml -- name: Add the selected operator to the pipeline group - become: true - ansible.builtin.user: - name: "{{ pipeline_operator }}" - groups: - - "{{ dnd_pipeline_runtime_group }}" - append: true +dnd_pipeline_operator_users: + - eric + - alice ``` +Every selected account must already exist; the role does not create human +accounts or manage their identity and login policy. Enrollment adds the +selected runtime group without replacing other supplementary groups. Removing +or omitting a name later does not revoke membership. A newly enrolled operator +must begin a new login session before the operating system exposes the added +supplementary group to that session. + Configuration, transcripts, caches, generated artifacts, campaign data, prompts, and logs are non-secret D&D content. Credentials use the restricted `/usr/local/etc/narratio/secrets` subtree, owned by the selected runtime user and group with mode `0750`; managed files use mode `0640`. Runtime-group -membership authorizes use of these shared credentials, while the subtree grants -no world access. Ordinary configuration remains world-readable and contains -only reference names. +membership, including enrollment through `dnd_pipeline_operator_users`, +authorizes use of these shared credentials, while the subtree grants no world +access. Ordinary configuration remains world-readable and contains only +reference names. ### Managed credentials diff --git a/defaults/main.yml b/defaults/main.yml index 4e9d9f4..8237cbe 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -9,6 +9,7 @@ dnd_pipeline_go_snap_channel: 1.26/stable dnd_pipeline_go_binary: /snap/bin/go dnd_pipeline_runtime_user: narratio dnd_pipeline_runtime_group: narratio +dnd_pipeline_operator_users: [] dnd_pipeline_secrets: {} dnd_pipeline_config_directory_mode: "0755" dnd_pipeline_config_file_mode: "0644" diff --git a/meta/argument_specs.yml b/meta/argument_specs.yml index 52f7506..b8bc6fc 100644 --- a/meta/argument_specs.yml +++ b/meta/argument_specs.yml @@ -43,6 +43,11 @@ argument_specs: type: str required: true description: Shared group for suite-managed configuration. + dnd_pipeline_operator_users: + type: list + elements: str + required: true + description: Existing human accounts enrolled in the shared runtime group. dnd_pipeline_secrets: type: dict required: true diff --git a/tasks/main.yml b/tasks/main.yml index 5cffe1c..08ef3b8 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,4 +1,19 @@ --- +- name: Validate selected pipeline operator accounts + ansible.builtin.getent: + database: passwd + key: "{{ item }}" + loop: "{{ dnd_pipeline_operator_users }}" + +- name: Enroll selected pipeline operators + become: true + ansible.builtin.user: + name: "{{ item }}" + groups: "{{ dnd_pipeline_runtime_group }}" + append: true + state: present + loop: "{{ dnd_pipeline_operator_users }}" + - name: Install ACL support become: true ansible.builtin.apt: diff --git a/tests/integration b/tests/integration index 6d6f7c4..cfd963e 100755 --- a/tests/integration +++ b/tests/integration @@ -31,6 +31,7 @@ baseline_args=( -e "dnd_pipeline_prompt_library_repository_url=file://$prompt_library_repository" -e "dnd_pipeline_prompt_library_revision=$prompt_library_revision" -e "dnd_pipeline_prompt_library_root=$prompt_library_root" + -e "{\"dnd_pipeline_operator_users\":[\"$operator_user\"]}" -e "{\"dnd_pipeline_secrets\":{\"AUDITA_LLM_API_KEY\":\"$synthetic_audita_api_key\",\"OPENROUTER_API_KEY\":\"$synthetic_notarius_api_key\"}}" ) @@ -38,8 +39,8 @@ cleanup() { exit_status=$? trap - EXIT /usr/bin/sudo /bin/rm -rf -- "$shared_fixture_root" || true - /usr/bin/sudo /usr/sbin/userdel --remove "$operator_user" 2>/dev/null || true "$ansible_playbook" -i "$inventory" "${baseline_args[@]}" "$converge" >/dev/null 2>&1 || true + /usr/bin/sudo /usr/sbin/userdel --remove "$operator_user" 2>/dev/null || true rm -rf -- "$test_tmp" exit "$exit_status" } @@ -70,6 +71,7 @@ printf '%s\n' \ -p "$test_tmp/roles" "$ansible_playbook" -i "$inventory" --syntax-check "$converge" "$workspace_venv/bin/ansible-lint" --offline --profile production "$converge" +/usr/bin/sudo /usr/sbin/useradd --create-home --shell /usr/sbin/nologin "$operator_user" baseline_log="$test_tmp/baseline.log" run_converge "$baseline_log" "${baseline_args[@]}" @@ -116,8 +118,6 @@ grep -Fq 'lane_id: item-registry' "$narratio_effective_config" /usr/bin/sudo -u narratio /usr/local/bin/narratio config diff default testing \ --config /usr/local/etc/narratio/pipeline.yml --campaign centaurs | \ awk -F '\t' '$1 != "changed" || $2 !~ /\.profile_id$/ { invalid = 1 } END { exit invalid || NR == 0 }' -/usr/bin/sudo /usr/sbin/useradd --create-home --groups narratio \ - --shell /usr/sbin/nologin "$operator_user" /usr/bin/sudo -u "$operator_user" /usr/local/bin/narratio config validate \ --config /usr/local/etc/narratio/pipeline.yml --campaign centaurs /usr/bin/sudo -u "$operator_user" /usr/local/bin/notarius config validate \