Files
ansible-workspace-dnd/docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md

267 lines
13 KiB
Markdown

# Feature 0009: Shared Pipeline Filesystem and Execution
Status: done
## Summary
Establish one coherent filesystem and invocation policy for the D&D suite.
Standalone application roles will expose sensible generic configuration
ownership and mode controls, while the pipeline role will use those controls
to make configuration service-owned and world-readable and to make writable
state safely shareable by the service account and existing human members of
its group.
## Problem or Opportunity
The current standalone roles hard-code their configuration ownership and
modes. Those defaults are reasonable in isolation, but the pipeline cannot
select its intended `narratio:narratio` ownership without adding a second
convergence pass that would fight the dependency roles and report changes on
every run.
Narratio's writable roots already use setgid mode `2775`, but directory mode
alone does not preserve group write access when different invocation identities
have different umasks. Notarius v0.7.0 has removed its application-enforced
private cache modes, so deployment provisioning can now establish a consistent
shared policy before Notarius integration begins.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the generic role
interfaces, direct module-driven convergence, and suite overrides.
- [The testing house style](../../testing.md) governs behavioral access tests
and clean repeated convergence.
- [The MVP roadmap](../mvp.md) assigns operator access and cross-application
policy to the pipeline role while keeping standalone roles independently
useful.
- [Decision 0001](../../decisions/0001-minimal-module-driven-ansible.md)
requires direct idempotent modules without preliminary state inspection.
- [Decision 0002](../../decisions/0002-shared-readable-pipeline-filesystem-policy.md)
defines the service ownership, shared writable state, world-readable content,
and restricted credential boundary implemented by this feature.
## Scope
- Add configuration owner, group, directory-mode, and file-mode variables to
the Audita, Notarius, Narratio, and Scriptorium roles.
- Preserve standalone defaults appropriate to each application rather than
embedding D&D suite policy in those roles.
- Add suite-level runtime identity and configuration-mode variables to the
pipeline role and pass them explicitly to all four configuration-bearing
dependencies.
- Run the Narratio dependency before the other application dependencies so it
creates the selected service account and group before they write
service-owned configuration.
- Converge suite application configuration as `narratio:narratio`, with
directory mode `0755` and file mode `0644` by default.
- Keep `/var/lib/narratio`, `/var/spool/narratio`, and
`/var/cache/narratio` as `narratio:narratio` mode `2775` shared writable
roots.
- Install the Ubuntu `acl` package, declare a pinned `ansible.posix`
collection dependency, and manage access and default ACL entries that retain
owner/group write and world read/traverse access beneath shared roots.
- Support invocation as either the service account or an existing human
member of the selected runtime group.
- Document the standalone defaults, pipeline overrides, expected group
membership, world-readable non-secret boundary, and reserved restricted
`secrets/` policy.
- Add focused integration coverage for public configuration-mode overrides,
cross-identity access, and immediate clean repeated convergence.
## Non-goals
- Upgrading Notarius, adding its ConfigKit import interface, deploying its
D&D pipeline, creating `/var/cache/notarius`, or enabling Narratio's
extraction stage; those belong to Feature 0010.
- Changing any application's native configuration fields or runtime behavior.
- Selecting human operators or changing their group membership.
- Creating or populating a `secrets/` directory, delivering credentials, or
defining secret injection.
- Making application configuration group-writable or supporting manual edits
to Ansible-managed configuration.
- Changing ownership of root-managed source checkouts, installed binaries,
campaign assets, or prompt assets.
- Recursively migrating pre-existing runtime content with incompatible modes
or ACLs.
- Running transcript processing, calling external services, or adding
scheduling and service management.
## Target End State
Each standalone role exposes the same four concepts using its application
prefix. Its defaults remain appropriate for an independent installation:
| Role | Configuration owner | Configuration group | Directory mode | File mode |
| --- | --- | --- | --- | --- |
| Audita | `root` | `root` | `0755` | `0644` |
| Notarius | `root` | `root` | `0755` | `0644` |
| Scriptorium | `root` | `root` | `0755` | `0644` |
| Narratio | `root` | `narratio` | `0750` | `0640` |
For example, the Notarius variables are
`notarius_config_owner`, `notarius_config_group`,
`notarius_config_directory_mode`, and `notarius_config_file_mode`; the other
roles use their corresponding prefixes. Each role uses these variables in the
ordinary directory and template tasks that already own its configuration. No
role adds a follow-up permission-repair task or preliminary inspection.
The pipeline role defines `dnd_pipeline_runtime_user` and
`dnd_pipeline_runtime_group`, both defaulting to `narratio`, plus
`dnd_pipeline_config_directory_mode: "0755"` and
`dnd_pipeline_config_file_mode: "0644"`. It passes those values as the four
roles' configuration owner, group, and mode inputs. Narratio executes first in
dependency order and creates the selected identity before another dependency
references it.
The resulting application configuration beneath
`/usr/local/etc/{audita,notarius,narratio,scriptorium}` is owned by
`narratio:narratio` and is world-readable. It remains under Ansible control;
neither the service account nor human operators are expected to edit managed
files in place.
The three existing Narratio writable roots are `narratio:narratio` mode
`2775`. Their access and default ACLs are equivalent to `u::rwx`, `g::rwx`,
`o::r-x`, and `m::rwx`. Inherited permissions remain subject to the mode
requested for each new file type, so ordinary files are non-executable while
remaining group-writable and world-readable. A later feature applies the same
policy when it introduces another shared root such as
`/var/cache/notarius`.
A human account already belonging to `narratio` can use the same configuration
and writable roots as the service account. This feature does not choose that
account. Credential files are absent; the reserved future
`/usr/local/etc/narratio/secrets` subtree uses the distinct `0750` directory
and `0640` file policy when a credential-delivery feature creates it.
## Repository Ownership
- `ansible-role-audita`, `ansible-role-notarius`, and
`ansible-role-scriptorium` own their generic configuration ownership and
mode variables, standalone defaults, documentation, and focused integration
coverage.
- `ansible-role-narratio` owns the equivalent generic controls while retaining
its existing standalone relationship to the service group it creates.
- `ansible-role-dnd-pipeline` owns dependency ordering, the suite runtime
identity and configuration-mode defaults, explicit dependency overrides,
the `acl` package and `ansible.posix` dependency, shared-root ACL
convergence, consumer documentation, and cross-identity integration
coverage.
- `ansible-workspace-dnd` owns this roadmap, Decision 0002, the later staged
implementation plan, and aggregate status.
- The five application source repositories are unchanged; their runtime
contracts are not needed to implement configuration-file ownership.
## Constraints and Settled Decisions
- Standalone application roles remain independently usable. Their defaults do
not assume that a `narratio` account exists unless the role itself creates
it.
- The pipeline role selects suite policy by passing public role variables; it
does not reapply ownership after dependencies have completed.
- Configuration owner and group variables are strings, while mode variables
use the quoted four-digit strings expected by Ansible file-management
modules.
- The pipeline's selected runtime user and group are the configuration owner
and group. Supporting different configuration and runtime identities would
require a concrete later use case.
- Application configuration is world-readable but not group-writable. Shared
writable roots and their ordinary content are group-writable and
world-readable.
- The role uses `ansible.builtin.apt` for the `acl` package and
`ansible.posix.acl` for access/default ACL state. The collection dependency
is pinned in the pipeline role's manifest and installed by its integration
driver.
- ACL management covers only the three existing writable roots and their
inheritance policy. It does not recursively rewrite existing descendants.
- A `secrets/` subtree is a documented future boundary, not state created by
this feature.
- Tests exercise the public operating contract and one representative
cross-identity workflow. They do not enumerate every path or restate every
module argument.
## Simplest Viable Implementation
1. Add four defaults, four argument-specification entries, and direct task
substitutions to each configuration-bearing standalone role; update its
README and focused integration inputs without adding new task flow.
2. Reorder the pipeline dependencies so Narratio creates the service identity
first, add four suite policy variables, and pass them directly to each
configuration-bearing role.
3. Add the pinned `ansible.posix` requirement, install `acl`, and apply the
selected access/default ACL entries to the three existing writable roots
with ordinary state-management modules.
4. Update pipeline consumer documentation and extend its integration driver
with one representative human group member, native configuration
inspection, shared-write behavior, and a clean repeat.
No task gathers preliminary filesystem or account state. Existing `file`,
`template`, `apt`, and `acl` modules own convergence and change reporting.
## Rationale and Alternatives
Public ownership and mode variables let each standalone role express its own
sensible installation while allowing a composing role to select different
policy through normal Ansible precedence. A corrective pipeline task would
fight the dependency templates and make every otherwise unchanged run report
changes.
Setgid alone preserves group identity but does not guarantee group-write bits
for files created under an arbitrary human user's umask. A managed default ACL
expresses the required inherited state directly. A wrapper command that sets a
umask would add another invocation path and would not protect direct use of the
installed applications.
Mode `2775`, rather than `2770`, is deliberate: D&D transcript content is not
treated as secret in this deployment. Only API keys and similar credentials
belong in the separately restricted future subtree.
## Acceptance Criteria
- Each configuration-bearing standalone role exposes and documents owner,
group, directory-mode, and file-mode variables with the standalone defaults
listed above.
- Each role applies those inputs through the tasks that already create its
configuration directory and file, without a second convergence pass.
- The pipeline role runs Narratio first and explicitly selects
`narratio:narratio`, `0755` directories, and `0644` files for all application
configuration.
- The deployed configuration for Audita, Notarius, Narratio, and Scriptorium
is owned by `narratio:narratio`, is readable by other local users, and
contains no credential values.
- The three existing Narratio writable roots are `narratio:narratio` mode
`2775` and have access/default ACLs that preserve group write and world
read/traverse access for new content.
- The pipeline role declares a pinned `ansible.posix` dependency and installs
the required Ubuntu `acl` package.
- The service account and a representative existing human member of the
`narratio` group can use the same configuration and exchange ordinary
writable-state content.
- The role does not create users other than the established service account,
alter human group membership, create a secrets directory, or migrate
existing descendants recursively.
- Syntax checking and production-profile lint pass in every changed role.
- Focused standalone-role integration checks and the complete pipeline
integration entry point pass.
- An immediate repeated application in every changed role reports no changes.
- Tests observe the shared operating contract without snapshotting defaults,
enumerating implementation steps, or testing trusted module behavior.
## Dependencies and Follow-up Work
Features 0001 through 0008 and the standalone-role test-suite simplification
are complete. Notarius v0.7.0's deployment-owned cache permissions remove the
application blocker that previously prevented this policy, but Feature 0009
does not otherwise depend on or modify the Notarius application.
Feature 0010 applies this policy to `/var/cache/notarius` while adding the D&D
extraction integration. Later work may add optional operator-selection and
group-membership variables or deliver credentials beneath the restricted
`secrets/` subtree.
## Potential Future Hardening
- Offer a non-world-readable deployment profile if a concrete environment
later treats campaign material as confidential.
- Select a recursive migration policy if supported upgrades must normalize
pre-existing descendants rather than only managed roots and new content.