392 lines
22 KiB
Markdown
392 lines
22 KiB
Markdown
# Audit Remediation Implementation Plan
|
||
|
||
## Purpose and status
|
||
|
||
This document is the executable roadmap for remediating the confirmed findings in
|
||
[`audit-findings.md`](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 1–32 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 33–35 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-012–COR-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-017–COR-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 | Pending |
|
||
|
||
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 33–35 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:
|
||
|
||
```sh
|
||
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 13–17.
|
||
|
||
**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 1–32. 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.
|