Compare commits

..

4 Commits

Author SHA1 Message Date
c0b0ebd13e Import pipeline operator enrollment 2026-09-18 12:57:00 +00:00
d292297b6a Squashed 'roles/pipeline/' changes from 78afffe..c13f726
c13f726 Add optional pipeline operator enrollment

git-subtree-dir: roles/pipeline
git-subtree-split: c13f726a0a846180a1aa95d110b8bbc801edaae5
2026-09-18 12:57:00 +00:00
5e695f38d0 Import pipeline documentation correction 2026-09-17 23:51:51 +00:00
f62445ad1e Squashed 'roles/pipeline/' changes from 7c2bad8..78afffe
78afffe Clarify the pipeline snapshot workflow

git-subtree-dir: roles/pipeline
git-subtree-split: 78afffe8e5fdedbd274e256dfa0e0721cfbf9a5c
2026-09-17 23:51:51 +00:00
5 changed files with 46 additions and 20 deletions

View File

@@ -49,8 +49,9 @@ The collection source exposes a reviewed snapshot of this role as
Collection consumers should follow the unified bootstrap instructions in the
[`rakestraw.dnd` collection repository](https://gitea.maximumdirect.net/eric/ansible-collection-dnd).
This standalone repository remains authoritative for role changes; collection
maintainers import a reviewed release as a snapshot. Collection releases are
published independently and are listed in the collection repository.
maintainers import a reviewed, pushed commit or immutable tag as a snapshot.
Collection releases are published independently and are listed in the
collection repository.
## Variables
@@ -89,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` |
@@ -258,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
@@ -268,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

View File

@@ -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"

View File

@@ -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

View File

@@ -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:

View File

@@ -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 \