Files
narratio/docs/roadmap/implementation.md

22 KiB
Raw Blame History

Audit Remediation Implementation Plan

Purpose and status

This document is the executable roadmap for remediating the confirmed findings in audit-findings.md and the concrete gaps found during the post-implementation code review. It is written for a gpt-5.6-terra coding agent that will implement exactly one pending stage per prompt, in order.

The audit is an immutable requirements and evidence ledger. Do not edit audit-findings.md or reinterpret its accepted findings. Stages 132 completed the original audit-remediation plan and are summarized below instead of retaining their now-obsolete implementation instructions. The repository history and audit remain the detailed evidence for that work.

Stages 3335 address follow-up review findings in the completed implementation. They are implementation gaps in the original remediation rather than new entries in the immutable audit ledger. They do not require the implementing agent to read the full audit or any audit line range.

Stage status and completed summaries

Stage Outcome or pending work Source Status
1 Aligned architecture policy and filesystem modes with collaborative, group-owned workspaces while preserving private API-key handling. RSK-004 Completed
2 Enforced portable safe-segment identifiers and added path/source fuzz coverage. COR-002, TST-013 Completed
3 Consolidated crash-durable atomic file replacement behind shared file-operation primitives. RSK-002, DUP-001, DUP-005 Completed
4 Added confined, no-follow destination and download/install operations. COR-003, DUP-003, TST-003 Completed
5 Confined recursive cleanup and replaced existence-based sentinel locks with OS-held locks. RSK-003 Completed
6 Made API-key acquisition private, bounded, regular-file-only, and no-follow. RSK-010 Completed
7 Bounded and verified externally produced adapter and stage result files. RSK-013, TST-007 Completed
8 Added owned subprocess-tree cancellation, timeout, and forced termination. RSK-011 Completed
9 Added streaming secret redaction and bounded subprocess diagnostic capture. RSK-012 Completed
10 Confined publish archive reads to validated workspace sources. COR-005 Completed
11 Established singular manifest and run identity ownership. COR-001, TST-006 Completed
12 Centralized handled terminal-failure persistence and removed competing failure paths. RSK-001, TST-002, SIM-001, COM-001 Completed
13 Introduced immutable remote commit manifests, a final current pointer, and an isolated removable legacy reader. ARC-003 Completed
14 Switched publishing to immutable commits, deterministic mappings, and a final pointer update. COR-004, COR-011, DUP-002, TST-004 Completed
15 Made remote locks generation-safe and rejected non-progressing storage pagination. RSK-005, RSK-014 Completed
16 Persisted retryable post-commit cleanup obligations. COR-006, COR-007 Completed
17 Bound restore and status to one verified committed snapshot and rejected conflicting state. COR-008, COR-009, TST-005 Completed
18 Serialized restore transitions, persisted interrupted-restore state, and made restored paths portable. RSK-006, RSK-008 Completed
19 Bound reusable audio cache entries to remote object identity. RSK-007 Completed
20 Unified previous-source readiness and eliminated duplicate transfers. COR-010, EFF-001 Completed
21 Tightened configuration parsing, validation, value domains, and test expectations. COR-012COR-015, TST-011, TST-014 Completed
22 Made product configuration truthful and assigned lifecycle ownership for downloaded temporary files. COR-024, RSK-009, ARC-004 Completed
23 Streamed WhisperX uploads and made its transport bounded, retry-correct, and race-safe. COR-016, EFF-002, TST-001 Completed
24 Corrected prepare/transcribe transition, retry, and optional-output semantics. COR-017COR-019, TST-008 Completed
25 Enforced authoritative output paths and shared singleton resolution. ARC-006, DUP-006 Completed
26 Centralized typed extraction-bundle evidence. DUP-007 Completed
27 Bound extraction reuse to direct transcript identity and explicit freshness evidence. COR-020, TST-009 Completed
28 Established one effective artifact set and deterministic catalog bootstrap behavior. COR-022, ARC-007, DUP-008 Completed
29 Made analyze input resolution typed, optional, actionable, and deterministic. COR-021, COR-023, RSK-015, SIM-003, TST-010 Completed
30 Removed misleading contracts and placed static Audita policy in adapter construction. ARC-001, ARC-005, SIM-004, COM-003, COM-006 Completed
31 Enforced repository-wide CI/release validation and streamlined redundant test matrices. TST-012, TST-015 Completed
32 Reconciled lifecycle/analyze documentation and closed the original audit traceability inventory. COM-002, COM-005 Completed
33 Confine diagnostic log destinations and eliminate pathname-based tail reads. Follow-up review Completed
34 Dispose of owned subprocess descendants after natural leader exit. Follow-up review Completed
35 Bound remote current-state and lock control-plane reads. Follow-up review Completed

Completed stages must not be reimplemented wholesale. A pending stage may adjust their code only where its stated remediation requires it.

Governing decisions

The following decisions are settled requirements, not questions for the implementing agent:

  1. Ordinary Narratio and Notarius campaign/session data is deliberately shareable, not private or sensitive. Group-owned, group-writable workspaces are an operational requirement. API keys are the only sensitive data handled by these applications and must remain private.
  2. On POSIX systems, Narratio-managed ordinary workspace directories and files should converge on setgid 02775 and 0664 respectively, inheriting the workspace's existing group. API-key directories and files must be 0700 and 0600. Do not add ownership-changing behavior or assume Narratio may chown. Windows behavior must preserve the same collaboration/security intent using the platform's available guarantees and explicit operational guidance.
  3. Remote current-state publication uses an immutable run-scoped commit manifest selected by one final pointer update. Readers may accept coherent legacy state, but all compatibility code must remain isolated behind a clearly named boundary, covered by dedicated tests, and carry an in-code removal comment. New writers must never produce the legacy format.
  4. Explicit notification no-op is supported. Configured notification backends or recipients are rejected until a real provider exists.
  5. External-data limits are runaway safeguards, not normal operating limits. Each limit must be a named, centrally discoverable constant in the package that owns the contract and at least an order of magnitude above expected ordinary data. Every limit error must identify the enforcing adapter or contract, the configured byte limit, and what exceeded it. Hard whole-disk protection remains an operations concern implemented with filesystem, service, container, or volume quotas rather than output-root polling.
  6. Narratio owns the complete process group or job created for every external command. Leader completion does not transfer ownership of surviving descendants. Run must not return while an owned descendant can continue running, including when the leader exits successfully or closes its streams.
  7. Diagnostic tails are derived only from content that passed through the streaming redactor. Diagnostic files use the same confined, no-follow mutation guarantees as other workspace destinations; a pathname must not be reopened to obtain an error tail after execution.
  8. Remote current pointers, commit manifests, selected session manifests, and lock documents are bounded while being read. Object metadata may reject an oversized value early but cannot replace enforcement against the actual byte stream. Limits for these small control-plane contracts are separate from limits for intentionally large artifact payloads.
  9. Retain every accepted-risk disposition in the audit. In particular, do not turn abrupt process-death detection into a distributed liveness system, add rollback of arbitrary external side effects, or introduce generic speculative abstractions rejected by the audit.
  10. CI must run ordinary tests, the full race suite, vet, build, and example/docs checks on every change and release path; shuffled tests run on a schedule. Add native macOS/Windows jobs only when authoritative Woodpecker runner labels and usable runners are available. Do not invent labels. Cross-compilation is useful but does not count as native filesystem or process evidence.

Instructions for every pending stage

For each implementation prompt, the coding agent must:

  1. Read docs/development.md, then the current-behavior documents and source files named by that stage. Follow the task-specific reading guide in docs/development.md. Stages 3335 do not require reading audit-findings.md; do not reread or modify the immutable audit ledger.

  2. Inspect the current tree before editing. Earlier stages may have changed names and ownership boundaries. Use the repository knowledge graph first for code discovery and call tracing, then text search for documentation, string literals, configuration, and evidence the graph cannot supply.

  3. Confirm the worktree state and preserve unrelated user changes. Do not rewrite or amend earlier commits unless explicitly instructed.

  4. Implement the stage completely, including production code, focused regression tests, platform-specific implementations where applicable, current-behavior documentation, and removal of code made obsolete by the stage. Do not leave a second competing path or defer required tests to a later stage unless this plan explicitly says so.

  5. Prefer typed, owner-specific contracts and existing package ownership. Keep policy at the owner and reusable mechanism in internal/fileops, storage, or the relevant adapter package. Do not create a generic abstraction solely because two call sites look similar.

  6. Treat path, race, process-lifecycle, and size checks as production behavior. Validation followed by an unsafe pathname operation or unbounded read is not a completed fix. Unsupported safe behavior must fail closed with an actionable error.

  7. Run focused tests while developing, then run at minimum:

    go test ./...
    go test -race ./...
    go vet ./...
    go build ./...
    go test ./internal/doccheck
    go test ./internal/config -run '^TestExamplesLoadAndValidate$'
    

    Run the platform build/test checks named by the stage. Do not require live cloud or third-party services.

  8. Compare the final diff with the stage goal and exit criteria. Update only that stage's row in the status table from Pending to Completed, adding the implementing commit hash if the workflow supplies one. Do not mark a stage complete while a required check is failing or required behavior is missing.

Stage 33 — Confine diagnostic log destinations and eliminate pathname-based tail reads

Read first: docs/policy/architecture.md, docs/policy/testing.md, docs/internal/adapters.md, docs/internal/workspace.md, and the current subprocess diagnostic and confined file-operation implementations and tests.

Depends on: Completed Stages 3, 4, and 9.

Goal: Prevent diagnostic log setup from following a replaceable leaf symlink or mutating a file outside the intended workspace, and ensure error diagnostics cannot be redirected to read unrelated or secret content after a command runs.

Work:

  • Replace direct diagnostic os.Create use with the established confined, no-follow destination mechanism. Validate the leaf as part of the mutation, reject symlink and non-regular destinations, preserve group-workspace modes, and retain the platform-specific safety guarantees established by Stage 4. A prior ancestor check followed by an ordinary pathname create is not sufficient.
  • Remove pathname reopening from diagnostic-tail construction. Retain a small, bounded per-stream tail from bytes that have already passed through streaming redaction, preferably in the diagnostic writer itself, and obtain failure diagnostics from that retained state after redaction has been flushed. Do not read the log path again in the error path.
  • Preserve stdout/stderr file behavior, shared-path behavior, byte caps, split- chunk secret redaction, capture-limit signaling, and group collaboration modes. Do not create an unbounded in-memory copy of either stream.
  • Keep API-key values out of persisted logs and every returned error even if a workspace peer renames or replaces a diagnostic pathname while the process is running.
  • Remove obsolete pathname-tail helpers and update current-behavior documentation only if the existing documentation describes the replaced mechanism.

Tests and exit criteria: Add adversarial tests proving that an existing log leaf symlink is rejected without truncating its target; a non-regular leaf is rejected; pathname replacement after the log is opened cannot inject foreign content into a returned error; and a known credential remains absent from files and errors across split writes. Cover separate and shared stdout/stderr paths, exact diagnostic caps, and cap-plus-one behavior. Run focused subprocess and file-operation tests under -race, plus Linux, macOS, and Windows cross-builds for affected packages. Native platform tests remain conditional on available runners.

Status: Completed.

Stage 34 — Dispose of owned subprocess descendants after natural leader exit

Read first: docs/policy/architecture.md, docs/policy/testing.md, docs/internal/adapters.md, the subprocess run/process-tree implementations for Unix and Windows, and all process-tree test helpers.

Depends on: Completed Stage 8 and Stage 33.

Goal: Close the lifecycle gap in which cmd.Wait can complete before a descendant in Narratio's process group or Windows job exits, allowing that descendant to outlive Run after either a successful or failed leader exit.

Work:

  • Route the normal cmd.Wait completion branch through bounded owned-tree disposal before Run returns. Apply the ownership rule for successful exits, non-zero exits, and exec.ErrWaitDelay, not only cancellation, timeout, or diagnostic-cap paths.
  • On Unix, detect and gracefully terminate any remaining process-group members, wait only for the existing bounded grace period, then forcefully terminate survivors. Treat an already-empty group as success and avoid imposing the grace delay on ordinary commands with no descendants.
  • On Windows, preserve job-object kill-on-close semantics and ensure natural leader completion closes/disposes the job before return. Keep handles and goroutines bounded on every exit path.
  • Consolidate terminal cleanup so races among context cancellation, capture-limit signaling, and leader completion cannot skip disposal or produce unsafe double ownership. Preserve timeout/cancellation classification and join actionable cleanup failures without hiding the original command result.
  • Treat a descendant that deliberately leaves the owned process group or job as outside this stage; do not build a system-wide process discovery mechanism.

Tests and exit criteria: Extend the real subprocess helper with cases where a leader exits zero while a descendant (a) retains inherited streams and (b) redirects or closes them, plus a non-zero leader case. Prove Run completes within bounded time and no descendant reaches a delayed sentinel after return. Retain cancellation, timeout, and capture-limit coverage and run the subprocess suite repeatedly, shuffled, and under -race. Cross-build the affected packages for Linux, macOS, and Windows; run native platform tests only where runners are actually available.

Status: Completed.

Stage 35 — Bound remote current-state and lock control-plane reads

Read first: docs/policy/architecture.md, docs/policy/testing.md, docs/internal/storage.md, docs/internal/artifacts.md, docs/internal/command-restore.md, the current-state commit reader, remote lock loader, object-store contract and implementations, and their stateful fakes and tests.

Depends on: Completed Stages 1317.

Goal: Prevent corrupt, misconfigured, or hostile object storage from forcing unbounded temporary-disk or memory consumption before small remote control-plane objects can be parsed or verified.

Work:

  • Inventory the new-protocol read paths for the mutable current pointer, immutable commit manifest, selected session manifest, and remote lock document. Include the isolated legacy current-state reader only where it accepts equivalent small control objects. Do not apply these limits to intentionally large published artifact payloads.
  • Define generous, documented, centrally discoverable constants in the packages that own each control-plane contract. Use separate policy constants where the credible sizes differ; do not embed numeric limits at call sites or replace the owner policies with one unexplained global limit.
  • Stream each object through an enforcing limit+1 read before parsing or retaining it. Reject oversized metadata before transfer when available, but still enforce the limit against actual bytes because metadata can be missing, stale, or inaccurate. Avoid downloading these small objects unboundedly to a temporary file and then calling os.ReadFile or io.ReadAll.
  • Preserve immutable commit checksum, declared-size, generation/ETag, identity, and pointer-selection validation. Ensure the metadata used for validation belongs to the opened object version; do not weaken coherence while removing the temporary download path.
  • Every over-limit error must identify the responsible control-plane contract, object category, key or safe storage context, and configured byte limit without including credentials. Maintain cancellation and reader-close behavior on all exits.
  • Factor a bounded storage-read mechanism only if it has a clear storage-layer invariant; retain the owner-specific constants and errors in the artifact and remote-lock owners.

Tests and exit criteria: Add exact-limit and limit-plus-one cases for each object category, including inaccurate/absent size metadata, short reads, cancellation, malformed JSON/YAML, checksum or generation mismatch, and readers that verify they are closed. Prove oversized current-state downloads do not create unbounded temporary files and oversized lock documents are rejected without unbounded allocation. Retain coherent legacy-reader tests and stateful S3/fake ordering and conditional-write tests. Run focused storage, artifacts, app, restore, and publish tests under -race, followed by the complete repository validation.

Status: Completed.

Finding traceability inventory

This inventory remains the closed traceability record for Stages 132. A pending follow-up stage may strengthen the implementation of an original stage, but does not change the immutable finding disposition or create a second audit finding.

Finding(s) Primary stage
COR-001 11
COR-002 2
COR-003 4
COR-004 14
COR-005 10
COR-006, COR-007 16
COR-008, COR-009 17
COR-010 20
COR-011 14
COR-012, COR-013, COR-014, COR-015 21
COR-016 23
COR-017, COR-018, COR-019 24
COR-020 27
COR-021, COR-023 29
COR-022 28
COR-024 22
RSK-001 12
RSK-002 3
RSK-003 5
RSK-004 1
RSK-005 15
RSK-006, RSK-008 18
RSK-007 19
RSK-009 22
RSK-010 6
RSK-011 8
RSK-012 9
RSK-013 7
RSK-014 15
RSK-015 29
EFF-001 20
EFF-002 23
ARC-001 30
ARC-003 13
ARC-004 22
ARC-005 30
ARC-006 25
ARC-007 28
TST-001 23
TST-002 12
TST-003 4
TST-004 14
TST-005 17
TST-006 11
TST-007 7
TST-008 24
TST-009 27
TST-010 28
TST-011, TST-014 21
TST-012, TST-015 31
TST-013 2
DUP-001, DUP-005 3
DUP-002 14
DUP-003 4
DUP-006 25
DUP-007 26
DUP-008 28
SIM-001 12
SIM-003 29
SIM-004 30
COM-001 12
COM-002, COM-005 32
COM-003, COM-006 30

The remaining confirmed IDs have non-independent dispositions and must not receive separate implementation work: ARC-002 and COM-004 are merged into COM-002; SIM-002 is merged into DUP-007; DUP-004 is rejected. Their audit rationale remains authoritative.

Follow-up review traceability

Review finding Remediation stage Source
Diagnostic leaf symlinks and pathname-reopened tails bypass confinement/redaction guarantees 33 Post-implementation review
Unix descendants survive natural leader exit 34 Post-implementation review
Remote current-state and lock control objects are read without acquisition limits 35 Post-implementation review

Open Questions

None. The remediation behavior and ownership decisions are specified above. Native macOS/Windows runtime validation remains contingent on external runner availability, but cross-build requirements and the rule against inventing runner labels make implementation decision-complete.