diff --git a/README.md b/README.md index 49f131b..eff42ea 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The compatible application versions are selected through these variables: | Variable | Default | | --- | --- | | `dnd_pipeline_audita_version` | `v0.9.1` | -| `dnd_pipeline_narratio_version` | `v2.0.0` | +| `dnd_pipeline_narratio_version` | `v2.1.0` | | `dnd_pipeline_notarius_version` | `v0.7.0` | | `dnd_pipeline_seriatim_version` | `v1.5.0` | | `dnd_pipeline_scriptorium_version` | `v0.13.0` | @@ -97,7 +97,7 @@ chosen policy value when their deployment requires it. | `dnd_pipeline_audita_pipeline_modules` | `glossary`, `homophones`, `glossary`, `spoken_word`, `grammar` | | `dnd_pipeline_audita_output_schema` | `audita-v1` | | `dnd_pipeline_audita_llm_proposal_*` | `https://inference.ai.rakestrawhome.com/v1`, `google/gemma-4-31b-it`, `AUDITA_LLM_API_KEY`, `900s`, `3` | -| `dnd_pipeline_audita_llm_validation_*` | `https://inference.ai.rakestrawhome.com/v1`, `google/gemma-4-31b-it`, `AUDITA_VALIDATION_LLM_API_KEY`, `900s`, `3` | +| `dnd_pipeline_audita_llm_validation_*` | `https://inference.ai.rakestrawhome.com/v1`, `google/gemma-4-31b-it`, `AUDITA_LLM_API_KEY`, `900s`, `3` | | `dnd_pipeline_audita_concurrency_*` | total, proposal, and validation concurrency of `4` | | `dnd_pipeline_audita_chunking_*` | `8` target sections, `6144` maximum and `2048` minimum section tokens | | `dnd_pipeline_audita_normalization_*` | `3s` maximum and ellipsis gaps, `240s` maximum duration, `2048` maximum tokens | @@ -105,10 +105,11 @@ chosen policy value when their deployment requires it. | `dnd_pipeline_audita_context_description` | D&D-game transcript context, including possible pre- and post-session banter | | `dnd_pipeline_audita_diagnostics_*` | `/tmp/audita`, retained automatically | -The API-key values themselves are never managed by this role. The two -environment-variable names above are configuration only. Audita owns its -endpoint, model, tuning, and diagnostics configuration; Narratio receives its -managed Audita configuration path and supplies the run-specific output path. +Audita's proposal and validation settings independently remain overrideable, +but both default to the one typed `AUDITA_LLM_API_KEY` reference Narratio can +forward. Audita owns its endpoint, model, tuning, and diagnostics configuration; +Narratio receives its managed Audita configuration path and supplies the +run-specific output path. | Variable | Default | | --- | --- | @@ -188,6 +189,8 @@ The Notarius root configuration imports the fixed | `dnd_pipeline_notarius_cache_chunk_plans_mode` | `auto` | | `dnd_pipeline_notarius_cache_checkpoints_enabled` | `true` | | `dnd_pipeline_narratio_notarius_pipeline_id` | `dnd-session` | +| `dnd_pipeline_narratio_notarius_llm_api_key` | `OPENROUTER_API_KEY` | +| `dnd_pipeline_narratio_notarius_resume` | `true` | | `dnd_pipeline_narratio_notarius_references` | `party`, `players`, and `glossary` prepared sources | | `dnd_pipeline_narratio_notarius_outputs` | Complete native map of ten accepted D&D lanes | @@ -203,7 +206,10 @@ that input. The accepted sources are `scene_descriptions`, `item_occurrences`, `spells`, `combat_turns`, `npc_occurrences`, `location_occurrences`, and `enemy_events`. -Chunk plans use `auto` caching and checkpoints are recorded but not resumed. +Narratio forwards the typed `OPENROUTER_API_KEY` reference to the selected +Notarius profile and ordinary extraction requests checkpoint reuse with +`resume: true`. Chunk plans use Notarius's root-owned `auto` policy; the +pipeline deliberately leaves Narratio's optional `chunk_cache` override unset. The `chunk-plans` and `checkpoints` paths derive from the cache root and are created by Notarius during use. Base and `testing` configurations select the same `dnd-extraction` profile and Notarius pipeline; the testing overlay changes @@ -232,9 +238,8 @@ inspection shows enabled sources, inferred dependencies, and generated family members; the diff shows the overlay's profile selections without modifying managed files. -API keys, storage and publishing, operator selection and -group-membership management, scheduling, and end-to-end external execution -remain deferred. +Storage and publishing, operator selection and group-membership management, +scheduling, and end-to-end external execution remain deferred. ### Shared execution filesystem @@ -258,9 +263,32 @@ play can manage its selected operator separately: ``` Configuration, transcripts, caches, generated artifacts, campaign data, -prompts, and logs are non-secret D&D content. API keys and other credentials -remain deferred to a future restricted `secrets/` subtree; this role does not -create or populate that subtree. +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. + +### Managed credentials + +`dnd_pipeline_secrets` defaults to `{}`. Its keys must be valid environment +variable names, and each value is either a nonempty string to manage as the +exact named credential file or `null` to remove that exact file. Omitted names +are unmanaged: the role neither mirrors nor purges the directory. Narratio +loads this conventional sibling directory before configuration resolution; an +already-set process environment value takes precedence. The role adds no +wrapper, service, or parallel credential loader. + +Keep values in encrypted inventory, for example with Ansible Vault; Vault is a +consumer workflow, not role functionality: + +```yaml +dnd_pipeline_secrets: + AUDITA_LLM_API_KEY: "{{ vault_dnd_audita_llm_api_key }}" + OPENROUTER_API_KEY: "{{ vault_dnd_openrouter_api_key }}" + RETIRED_PROVIDER_KEY: null +``` ## Validation diff --git a/tests/integration b/tests/integration index f7cc9de..3a5652f 100755 --- a/tests/integration +++ b/tests/integration @@ -123,6 +123,10 @@ grep -Fq 'lane_id: item-registry' "$narratio_effective_config" /usr/bin/sudo -u "$operator_user" /usr/local/bin/notarius config validate \ --config /usr/local/etc/notarius/config.yml --pipeline dnd-session /usr/bin/sudo -u nobody /bin/cat /usr/local/etc/narratio/pipeline.yml >/dev/null +if /usr/bin/sudo -u nobody /usr/local/bin/narratio config validate \ + --config /usr/local/etc/narratio/pipeline.yml --campaign centaurs; then + exit 1 +fi /usr/bin/sudo -u narratio /bin/sh -c \ "umask 077; mkdir '$shared_fixture_root'; printf '%s\\n' service-created > '$service_fixture_file'" /usr/bin/sudo -u "$operator_user" /bin/sh -c \ @@ -155,6 +159,40 @@ baseline_repeat_log="$test_tmp/baseline-repeat.log" run_converge "$baseline_repeat_log" "${baseline_args[@]}" require_clean_recap "$baseline_repeat_log" +invalid_key_log="$test_tmp/invalid-key.log" +if run_converge "$invalid_key_log" "${baseline_args[@]}" \ + -e '{"dnd_pipeline_secrets":{"INVALID-KEY":"invalid-key-synthetic-value"}}'; then + exit 1 +fi +invalid_value_log="$test_tmp/invalid-value.log" +if run_converge "$invalid_value_log" "${baseline_args[@]}" \ + -e '{"dnd_pipeline_secrets":{"EMPTY_VALUE_KEY":""}}'; then + exit 1 +fi + +removal_key=NARRATIO_TEST_REMOVAL_KEY +removal_value=removal-synthetic-value +removal_present_config="{\"dnd_pipeline_secrets\":{\"AUDITA_LLM_API_KEY\":\"$synthetic_audita_api_key\",\"OPENROUTER_API_KEY\":\"$synthetic_notarius_api_key\",\"$removal_key\":\"$removal_value\"},\"dnd_pipeline_narratio_notarius_llm_api_key\":\"$removal_key\"}" +removal_present_log="$test_tmp/removal-present.log" +run_converge "$removal_present_log" "${baseline_args[@]}" -e "$removal_present_config" +removal_present_validation_log="$test_tmp/removal-present-validation.log" +/usr/bin/sudo -u narratio /usr/local/bin/narratio config validate \ + --config /usr/local/etc/narratio/pipeline.yml --campaign centaurs | tee "$removal_present_validation_log" +removal_absent_config="{\"dnd_pipeline_secrets\":{\"AUDITA_LLM_API_KEY\":\"$synthetic_audita_api_key\",\"OPENROUTER_API_KEY\":\"$synthetic_notarius_api_key\",\"$removal_key\":null},\"dnd_pipeline_narratio_notarius_llm_api_key\":\"$removal_key\"}" +removal_absent_log="$test_tmp/removal-absent.log" +run_converge "$removal_absent_log" "${baseline_args[@]}" -e "$removal_absent_config" +removal_absent_validation_log="$test_tmp/removal-absent-validation.log" +if /usr/bin/sudo -u narratio /usr/local/bin/narratio config validate \ + --config /usr/local/etc/narratio/pipeline.yml --campaign centaurs | tee "$removal_absent_validation_log"; then + exit 1 +fi +removal_absent_repeat_log="$test_tmp/removal-absent-repeat.log" +run_converge "$removal_absent_repeat_log" "${baseline_args[@]}" -e "$removal_absent_config" +require_clean_recap "$removal_absent_repeat_log" +! grep -Fq "$synthetic_audita_api_key" "$baseline_log" "$removal_present_log" "$removal_absent_log" "$removal_present_validation_log" "$removal_absent_validation_log" +! grep -Fq "$synthetic_notarius_api_key" "$baseline_log" "$removal_present_log" "$removal_absent_log" "$removal_present_validation_log" "$removal_absent_validation_log" +! grep -Fq "$removal_value" "$removal_present_log" "$removal_absent_log" "$removal_present_validation_log" "$removal_absent_validation_log" + testing_profile_log="$test_tmp/testing-profile.log" run_converge "$testing_profile_log" "${baseline_args[@]}" \ -e 'dnd_pipeline_narratio_testing_scriptorium_profile=endpoint-profile'