579 lines
34 KiB
Markdown
579 lines
34 KiB
Markdown
# Audit remediation implementation plan
|
||
|
||
## Objective and baseline
|
||
|
||
Implement the accepted target in [audit.md](audit.md) from baseline `b5b3f09`.
|
||
The eleven [audit reports](audit/) supply evidence and reproduction details;
|
||
the target document owns the accepted outcomes and policy choices. This plan
|
||
owns execution order, concrete implementation choices, and completion evidence.
|
||
|
||
All stages are pending. Follow Stage 1 through Stage 19 in order as one
|
||
end-to-end sprint. Stages separate work into units suitable for a Luna coding
|
||
agent. Intermediate stages may leave related code or tests uncompilable;
|
||
complete the dependencies before evaluating the final implementation. Run
|
||
focused checks when the affected packages are ready, and reserve the complete
|
||
verification pass for Stage 19. Proceed through the sprint without intermediate
|
||
external actions, pilot integrations, releases, or human review gates.
|
||
|
||
This sprint implements the selected repairs and internal maintenance. A11 and
|
||
A17 deliver local assessment evidence while their production changes remain
|
||
deferred. New JSON limits, exclusion indexing, public configuration, broader
|
||
concurrent-use contracts, and alternative approaches are future decisions.
|
||
The public module path, Go minimum, facade types, receipt schema, and source
|
||
publication completion point keep their current contracts.
|
||
|
||
Read [development.md](../development.md) and the applicable policies before
|
||
working. Preserve unrelated changes. Use existing fixture helpers, local Git
|
||
remotes, and local HTTP servers. Keep synthetic module-proxy tests in test-owned
|
||
module caches. All default tests remain offline and credential-independent.
|
||
|
||
## Completion tracking
|
||
|
||
Update this table with the completed work and relevant check results as the
|
||
sprint proceeds. A completed assessment in Stage 18 leaves the corresponding
|
||
production change explicitly deferred. Commit completed nonempty units under
|
||
the agent policy; an intermediate compilation dependency is recorded accurately.
|
||
|
||
| Stage | Work items | Status |
|
||
| --- | --- | --- |
|
||
| 1 | A01; publication assertion portion of A19 | Pending |
|
||
| 2 | A02, A12: common Git mechanics | Pending |
|
||
| 3 | A02: source identity regression evidence | Pending |
|
||
| 4 | A03: buffered command teardown | Pending |
|
||
| 5 | A03, A18: piped lifetime and queued cancellation | Pending |
|
||
| 6 | A04 | Pending |
|
||
| 7 | A05 | Pending |
|
||
| 8 | A06, A14 | Pending |
|
||
| 9 | A16 | Pending |
|
||
| 10 | A07: allocation and temporary metadata | Pending |
|
||
| 11 | A07: build and delivery outcomes | Pending |
|
||
| 12 | A08 | Pending |
|
||
| 13 | A09 | Pending |
|
||
| 14 | A10 | Pending |
|
||
| 15 | A13 | Pending |
|
||
| 16 | A15 | Pending |
|
||
| 17 | Remaining A19, A20 | Pending |
|
||
| 18 | A11, A17: assessment only | Pending |
|
||
| 19 | Integrated verification and current documentation | Pending |
|
||
|
||
## Stage 1: Correct the owned tag push
|
||
|
||
Owners: [internal/git/tag.go](../../internal/git/tag.go) and
|
||
[publication tests](../../publish_test.go). Target: A01 and the publication
|
||
assertion portion of A19.
|
||
|
||
1. Add `--recurse-submodules=no` to `Endpoint.PushTag`. Retain its captured
|
||
object-to-exact-tag refspec, `--no-follow-tags`, scoped endpoint, and
|
||
non-forcing push behavior.
|
||
2. Extend the real local-bare-remote publication fixture with
|
||
`push.recurseSubmodules=only`. Set it after fixture setup has published
|
||
`main`. A successful public `Publish` must leave the captured annotated
|
||
object at the exact remote ref, with the intended peeled commit and note.
|
||
3. Remove the ordinary success test's assertion of exactly three queries.
|
||
Keep its exact remote object/message and unrelated-ref assertions. Retain
|
||
the documented single authoritative reconciliation after a failed push.
|
||
|
||
Evidence: the new regression fails on the baseline and passes with the push
|
||
option. Existing rejected-push, conflict, and unknown-result cases retain their
|
||
outcomes. This stage adds no successful-push read-back operation.
|
||
|
||
## Stage 2: Establish shared original-object Git observations
|
||
|
||
Owners: [internal/git](../../internal/git/source.go),
|
||
[candidate](../../internal/candidate/check.go),
|
||
[build](../../internal/build/build.go), and
|
||
[committed identity](../../internal/releaseidentity/identity.go).
|
||
Targets: the mechanics of A02 and A12.
|
||
|
||
1. Make ReleaseKit-owned Git subprocesses use `GIT_NO_REPLACE_OBJECTS=1`
|
||
through per-command environment overlays. Cover the Git command runner,
|
||
local-object reader, batch-reader startup, discovery/preparation commands,
|
||
and remaining direct candidate Git commands. Preserve local-only object
|
||
reads' lazy-fetch/transport controls and network-capable preparation.
|
||
Apply the override to owned Git children; preserve the existing environments
|
||
of application Go tests, product checks, and unrelated caller operations.
|
||
2. Reuse `git.CaptureHead` and add a small repository-wide worktree-status
|
||
observation in `internal/git`. Have candidate state inspection, build
|
||
eligibility inspection, and tagged-source inspection use these primitives.
|
||
Keep branch and tag observations explicit at their current owners.
|
||
3. Remove build's independent `gitCommit` and `cleanSource` execution paths.
|
||
Preserve its initial/final observation timing, captured commit, dirty-build
|
||
success behavior, `SourceVerified` calculation, and contextual causes.
|
||
4. Keep candidate checks requiring clean `main`, and delivery requiring the
|
||
selected tag and clean checkout. Shared observation helpers return facts;
|
||
they do not impose those caller policies or combine the observations into
|
||
a new release-state framework.
|
||
5. Leave the unused `InspectLocalTag` helper unused for removal in Stage 17.
|
||
Preserve the live candidate guard's exact captured-object/type checks.
|
||
|
||
Evidence: existing dirty-source, changed-HEAD, sparse-checkout, nested-module,
|
||
Git failure, and source-cancellation cases still express their distinct
|
||
contracts. Stage 3 supplies the replacement-object regressions before A02 is
|
||
marked complete.
|
||
|
||
## Stage 3: Prove validated and published source identity
|
||
|
||
Owners: public publication/build/delivery tests and existing Git/tree fixtures.
|
||
Target: A02, including the missing regression coverage in testing audit §1.
|
||
|
||
1. Use a real candidate and bare authoritative remote at original commit A.
|
||
Create a local replacement B with different source and note bytes. Include
|
||
a case where A fails compilation while B compiles. Materialize the replaced
|
||
checkout using ordinary fixture Git, then invoke the public release path.
|
||
2. Assert that a replacement-derived worktree cannot pass candidate validation
|
||
and publish A as validated source. Compare actual bytes or the contextual
|
||
rejection, rather than only commit IDs. Also verify that a worktree matching
|
||
original objects can release normally with unrelated replacement refs.
|
||
3. Cover original committed reads for commit, tree, and blob replacements at
|
||
the Git/identity/tree boundary. Reuse one public fixture to show this behavior
|
||
reaches publication and one existing tagged-delivery fixture to prove the
|
||
committed note remains the original note. Avoid a module/layout cross-product.
|
||
4. Retain dirty working-tree `Build` support: replacement-derived dirty bytes
|
||
may compile, but their result is ineligible as clean binary delivery source.
|
||
Keep ordinary partial build facts and inspection causes.
|
||
|
||
Evidence: original committed identity/note reads and the publication outcome
|
||
agree. Do not alter refs, disable unrelated caller configuration globally, or
|
||
add a repository-wide prohibition on replacement refs.
|
||
|
||
## Stage 4: Bound buffered subprocess I/O teardown
|
||
|
||
Owners: [internal/process/process.go](../../internal/process/process.go),
|
||
[native version execution](../../internal/build/build.go), and process tests.
|
||
Target: the buffered-command part of A03.
|
||
|
||
1. Set an internal `exec.Cmd.WaitDelay` of one second in the common command
|
||
construction path. This is an I/O teardown grace after cancellation or
|
||
observed child exit, not a runtime deadline for healthy commands. It bounds
|
||
drainage of pipes inherited by a surviving descendant while using the
|
||
standard library's child waiting and error behavior.
|
||
2. Preserve `errors.Is` cancellation/deadline identity when the governing
|
||
context is done. Preserve ordinary `*exec.ExitError` and `exec.ErrWaitDelay`
|
||
when appropriate. Retain the existing 30-second recovery context; its
|
||
cancellation may be followed by bounded teardown, rather than an unbounded
|
||
inherited-descriptor wait. Introduce no new public timing SLA or setting.
|
||
3. Route build's native version command through `process.Run`, capturing stdout
|
||
and stderr together. Preserve its current working-directory behavior,
|
||
literal `version` argument, exact expected output, and contextual failures.
|
||
Stage 2 has already moved build's Git commands to the shared boundary.
|
||
4. Add ready-child/ready-descendant fixtures for cancellation and normal child
|
||
exit with inherited descriptors. Check bounded return and error identity;
|
||
clean up the fixture's descendants explicitly in test cleanup. Keep a
|
||
generous test watchdog separate from the internal teardown grace.
|
||
|
||
Evidence: buffered Go/Git preparation can return after cancellation, healthy
|
||
long-running commands continue until their caller cancels or they finish, and
|
||
the existing source-publication recovery classifications remain unchanged.
|
||
|
||
## Stage 5: Complete piped ownership and queued-read cancellation
|
||
|
||
Owners: `PipedProcess` in [internal/process](../../internal/process/process.go)
|
||
and [BlobReader](../../internal/git/blob_reader.go). Targets: A03 and A18.
|
||
|
||
1. Keep serialized batch exchanges and the existing `sync.Once` wait ownership.
|
||
After a piped command starts, register an operation-context cancellation
|
||
callback that closes its owned stdin/stdout pipes so an exchange or normal
|
||
shutdown drain can unblock even if a descendant holds a descriptor.
|
||
2. Retain the callback's stop function and a completion signal. During `Wait`,
|
||
join the child and stop or join that callback before returning and before
|
||
reading captured stderr. On healthy completion, stop the callback before
|
||
releasing the derived context. Startup failures close acquired pipes and
|
||
release the context. Explicit `Cancel` continues leaving the parent context
|
||
unchanged.
|
||
3. Retain `BlobReader.Read`'s per-read cancellation hook and its completion
|
||
join; it may delegate pipe interruption to the piped-process owner. Keep
|
||
aborted sessions terminal, and preserve ordinary missing-object reuse.
|
||
Ensure `Close` uses the same cancellation/pipe lifetime and reaps the child.
|
||
Healthy exchanges still consume stdout before the normal wait; the one-second
|
||
grace does not become a lifetime limit on a healthy batch reader.
|
||
4. Recheck `ctx.Err()` immediately after acquiring `reader.mu`, before session
|
||
access or callback registration. A canceled queued request returns its own
|
||
context error without aborting the healthy session. Retain the mutex;
|
||
prompt cancellation while waiting for it remains outside this sprint.
|
||
5. Add controlled regressions for inherited-descriptor shutdown, cancellation
|
||
during a body read, and a canceled queued request between a successful first
|
||
read and a successful later read. Preserve double-close and parent-context
|
||
behavior. Use readiness signals and joined cleanup, not timing alone.
|
||
|
||
Evidence: process and reader lifecycle tests pass under the race detector.
|
||
Use one public preparation cancellation case to confirm caller-visible return;
|
||
the test owns any descendant left running after the direct child is reaped.
|
||
|
||
## Stage 6: Sanitize Git endpoint diagnostics
|
||
|
||
Owners: [internal/git/remote.go](../../internal/git/remote.go),
|
||
[tag operations](../../internal/git/tag.go),
|
||
[publication](../../internal/publish/publish.go), and the CLI. Target: A04.
|
||
|
||
1. Add narrow internal Git URL display helpers. Mask the entire HTTP(S)
|
||
userinfo component, covering password- and username-carried credentials.
|
||
Retain useful scheme/host/path context. Keep non-HTTP Git forms unchanged.
|
||
2. Use the helper for expected/resolved endpoints, endpoint changes, queries,
|
||
pushes, and reconciliation messages. Sanitize credential-bearing HTTP(S)
|
||
URL spans in captured Git error diagnostics before embedding them. If a
|
||
detected userinfo URL cannot be parsed safely for display, replace that span
|
||
with a redacted-URL marker. Preserve wrapped causes and error classification.
|
||
Where the cause's own text contains credentials, use a private error wrapper
|
||
whose `Error` renders sanitized text and whose `Unwrap` retains the cause;
|
||
embedding the raw cause with `%w` would expose its text again.
|
||
This addresses URL credentials in owned diagnostics, not arbitrary secrets
|
||
emitted by application checks or unrelated transport programs.
|
||
3. Render the CLI's `endpoint=` field through the same display logic. Keep
|
||
`PublicationResult.Endpoint`, captured transport URLs, URL rewrites, and
|
||
`ExpectedPushURL` comparisons raw and exact. Clarify the public field's
|
||
sensitivity in GoDoc without adding a new public accessor or field.
|
||
4. Cover password and username tokens, encoded userinfo, embedded Git diagnostic
|
||
URLs, malformed display inputs, and ordinary SSH destinations. A public
|
||
mismatch fixture must preserve exact mismatch detection while both the
|
||
library error and CLI output hide placeholder credentials. Also exercise
|
||
a later query/push failure and preserve the original cause.
|
||
|
||
Evidence: owned diagnostics are safe to display, while endpoint identity and
|
||
transport behavior retain their selected contracts. Use placeholder credentials
|
||
and local fixtures; live Git or forge credentials are unnecessary.
|
||
|
||
## Stage 7: Preserve partial local tag evidence
|
||
|
||
Owners: [CreateAnnotatedTag](../../internal/git/tag.go),
|
||
[publish.Publish](../../internal/publish/publish.go), and publication tests.
|
||
Target: A05.
|
||
|
||
1. Retain the annotated tag object ID once its existing inspections establish
|
||
that evidence. Return it with a later verification error rather than
|
||
returning an empty string on every error.
|
||
2. Assign any returned tag object to the publication result before handling the
|
||
error. Keep phase `tag_creation` and state `not_published` for these failures.
|
||
3. After successful tag creation followed by failed inspection, identify
|
||
`refs/tags/<tag>` in the error and explain that the local tag may remain.
|
||
When no ID was obtainable, retain the ref-level evidence and empty object
|
||
field. Preserve the original cause and failed verification; perform no
|
||
automatic local ref deletion, retagging, independent retry, or push.
|
||
4. Add public regressions using real repositories and a command wrapper that
|
||
fails the first post-creation type inspection and a later inspection after
|
||
the ID is known. Inspect the actual local ref independently and confirm
|
||
retained evidence, original error, and absence of a remote push.
|
||
|
||
Evidence: the caller can distinguish possible retained local work from a
|
||
verified tag object without a new public progress type. Update the relevant
|
||
public comment and recovery guidance to reflect unavailable evidence accurately.
|
||
|
||
## Stage 8: Normalize internal build results and completed artifacts
|
||
|
||
Owners: [internal/build/build.go](../../internal/build/build.go),
|
||
[facade conversion](../../build.go), and public build/CLI tests.
|
||
Targets: A06 and A14.
|
||
|
||
1. Remove internal `Result.MainPackage`, `BinaryName`, and `Targets`; use
|
||
normalized `Result.Settings` throughout compilation, native smoke selection,
|
||
and conversions. Keep public `BuildResult` fields and receipt fields intact.
|
||
Preserve early-failure normalization and result copying.
|
||
2. Build and hash each artifact in a local value before appending it to the
|
||
completed artifact list. A hash failure names that path, preserves its cause,
|
||
retains earlier completed artifacts, and leaves generated files in place.
|
||
Later smoke or source-inspection failures still return all already completed
|
||
artifacts. Introduce no compiled-but-unverified public result state.
|
||
3. Extend the public post-compilation read-failure fixture to include an earlier
|
||
successful target. Assert complete digests on the retained prefix, absence
|
||
of an incomplete entry, accurate CLI presentation, and preserved source/
|
||
settings facts. Retain no-target, dirty-build, duplicate-target normalization,
|
||
partial-target-failure, and version-injection coverage.
|
||
|
||
Evidence: public artifacts satisfy the documented digest contract, and prebuilt
|
||
delivery still accepts the same normalized public results.
|
||
|
||
## Stage 9: Share pure artifact declaration matching
|
||
|
||
Owners: [internal/artifact](../../internal/artifact/artifact.go),
|
||
[receipt validation](../../cmd/releasekit/internal/cli/receipt.go), and
|
||
[delivery declarations](../../internal/delivery/assets.go). Target: A16.
|
||
|
||
1. Introduce a pure helper accepting selected targets, expected-name inputs,
|
||
and recorded target/filename metadata in artifact-owned internal types.
|
||
Reuse `ExpectedBuild` and existing component rules to check counts, target
|
||
uniqueness, one artifact per selected target, and expected names.
|
||
2. Adapt both callers through explicit conversions. Keep receipt schema,
|
||
absolute-path, identity, digest-syntax, and nonempty-target rules in the CLI.
|
||
Keep delivery's empty/source-only behavior, file stats, manifest generation,
|
||
and byte verification in their current owners and ordering.
|
||
3. Preserve current acceptance rules; add no Go target allowlist or content
|
||
access during receipt loading. Keep `internal/artifact` independent of build,
|
||
CLI, delivery, and forge packages.
|
||
4. Retain independent concrete expected filenames in receipt, delivery, and
|
||
public receipt-to-delivery tests. Reuse mismatch cases rather than computing
|
||
every expected value with the helper under test.
|
||
|
||
Evidence: schema and content validation remain distinct, with one owner for
|
||
their shared declaration rule and unchanged source-only behavior.
|
||
|
||
## Stage 10: Preserve allocation paths and temporary metadata cleanup
|
||
|
||
Owners: [internal/tempdir](../../internal/tempdir/tempdir.go),
|
||
[tag message files](../../internal/git/tag.go), and
|
||
[receipt files](../../cmd/releasekit/internal/cli/receipt.go). Target: A07 part 1.
|
||
|
||
1. In both `Outside` allocation branches, keep the original `MkdirTemp` path
|
||
until `Abs`/`EvalSymlinks` succeed. Use that original path for error-path
|
||
removal. Retain the resolution error and report any failed removal with
|
||
its path. Preserve outside-worktree selection and fallback behavior.
|
||
2. Capture deferred removal errors for owned tag-message and receipt temporary
|
||
files and join them with primary errors. A temporary path absent after a
|
||
successful rename is normal; ignore `os.ErrNotExist` for that removal.
|
||
Keep successful receipt installation and caller output paths intact.
|
||
3. Preserve any verified local tag ID through a later metadata cleanup error,
|
||
as established in Stage 7. Cleanup failure before the push remains a local
|
||
publication failure; no extra remote action follows it.
|
||
4. Use a narrow private, per-operation removal/resolution test seam where real
|
||
filesystem failures are otherwise nondeterministic. Keep the seam behind
|
||
internal wrappers, with standard functions in production and no mutable
|
||
global hooks or public filesystem abstraction. Test path retention and joined
|
||
causes, including the renamed-receipt absent-path case.
|
||
|
||
Evidence: failed resolution never loses the owned cleanup path, and routine
|
||
successful receipt writes do not acquire a spurious cleanup error.
|
||
|
||
## Stage 11: Report managed build cleanup with accurate outcomes
|
||
|
||
Owners: [candidate build callback](../../internal/build/candidate.go),
|
||
[native smoke build](../../internal/build/build.go),
|
||
[managed delivery](../../internal/delivery/delivery.go), and CLI delivery output.
|
||
Target: A07 part 2.
|
||
|
||
1. Use named returns or equivalent explicit finalization to join failed owned
|
||
directory removal with a primary build/delivery error. Include the cleanup
|
||
path and preserve completed artifacts, source facts, and remote observations.
|
||
2. If remote delivery completed, return its `Complete` state and asset lists
|
||
together with the cleanup error. The public facade forwards both. The CLI
|
||
returns operational status 1, explicitly reports remote completion plus local
|
||
cleanup failure, and gives no instruction to redo completed hosted delivery.
|
||
Earlier partial/conflict/unknown outcomes retain their original classification.
|
||
3. Keep managed temporary output outside the checkout. Caller-owned prebuilt
|
||
artifacts and normal caller-selected build directories are not removed by
|
||
this finalizer. Candidate build cleanup occurs before tagging as today.
|
||
4. Test success-plus-cleanup-failure, primary-error-plus-cleanup-failure,
|
||
cancellation, and confirmed hosted completion with cleanup failure. Use a
|
||
private per-operation remover parameter at the internal operation boundary
|
||
where needed for deterministic failures; keep production entry points using
|
||
`os.RemoveAll`. Test the outcome, not only a standalone join helper.
|
||
|
||
Evidence: errors identify leaked paths without misreporting remote state or
|
||
discarding existing causes. Update delivery/CLI guidance for `Complete` plus
|
||
a local operational error and preserve ordinary cleanup success cases.
|
||
|
||
## Stage 12: Bound manual asset redirects
|
||
|
||
Owners: [internal/gitea/assets.go](../../internal/gitea/assets.go) and adapter/
|
||
delivery tests. Target: A08.
|
||
|
||
1. Count followed redirect hops in `openAsset`. Allow ten hops: the initial
|
||
request plus at most ten follow-up requests. After ten followed redirects,
|
||
a further redirect response is closed and rejected before requesting its
|
||
target. A successful response after the tenth hop remains accepted.
|
||
2. Keep fragment normalization, exact-cycle handling, invalid-userinfo rejection,
|
||
and per-origin token checks. Close every intermediate/rejected body. Return
|
||
the existing unverifiable-content failure classification with useful context.
|
||
Add no public override or automatic operation timeout.
|
||
3. Test zero hops, exactly ten, and an eleventh attempted hop with distinct
|
||
URLs. Retain same-origin, cross-origin, return-to-origin, and exact-cycle
|
||
checks. Use local servers and request counters to verify the boundary.
|
||
4. Preserve shared outcome mapping: read-only verification failure leaves
|
||
`NotAttempted`, or `Partial` when this invocation created the page; ambiguity
|
||
after an attempted asset write still follows existing reconciliation rules.
|
||
|
||
Evidence: the selected hop count is unambiguous and authorization never follows
|
||
the token to another origin. Document the limit in the Gitea integration owner.
|
||
|
||
## Stage 13: Bound remote content comparison by the declaration
|
||
|
||
Owners: [internal/delivery/remote_assets.go](../../internal/delivery/remote_assets.go)
|
||
and delivery/artifact fixtures. Target: A09.
|
||
|
||
1. Pass expected local size into the digest comparison. Read at most that size
|
||
through a limited reader, then probe one additional byte. Keep the extra-byte
|
||
fact separate from an `int64` total so `MaxInt64 + 1` never overflows.
|
||
2. Distinguish definite size mismatch from inspection failure. Short or excess
|
||
content becomes `AssetConflicting`; equal-length content still requires
|
||
digest equality. A non-EOF read error, close error, or context error remains
|
||
unverifiable with its cause retained. Close the stream on every path.
|
||
3. Apply the same verification during upload reconciliation. A mismatch there
|
||
conflicts; an unresolved read after a possibly successful write remains
|
||
unknown under the existing policy. Keep local hashing before hosted writes,
|
||
additive uploads, and asset observation categories unchanged.
|
||
4. Test empty, shorter, equal/matching, equal/different, and oversized streams,
|
||
plus a read returning data with an error, close failure, and cancellation.
|
||
Count bytes in a controlled stream to prove the declaration-derived bound.
|
||
Include a public prebuilt-delivery case and retain manifest comparison.
|
||
|
||
Evidence: remote metadata size/content length is not used as proof of matching
|
||
bytes, and legitimate artifact size has no new global cap.
|
||
|
||
## Stage 14: Bound retained status-only Go diagnostics
|
||
|
||
Owners: [internal/gotool/gotool.go](../../internal/gotool/gotool.go), its tests,
|
||
and [output benchmarks](../../internal/gotool/performance_test.go). Target: A10.
|
||
|
||
1. Give combined capture an explicit full-output mode and a status-diagnostics
|
||
mode. Full mode retains `Tool.Output` bytes and the existing ownership
|
||
transfer. Status mode retains the last 1,048,576 bytes and whether earlier
|
||
bytes were omitted. Use a lazy bounded circular tail so repeated small writes
|
||
copy in proportion to incoming data rather than shifting a 1 MiB buffer on
|
||
every write. Keep synchronization around capture and forwarding.
|
||
2. Use status mode for `Tool.Run` and dependency preparation. Preserve complete
|
||
forwarding to existing optional writers, short-write/error handling, quiet
|
||
behavior without a writer, and the separate preparation Go environment.
|
||
Keep configuration-discovery JSON and `Tool.Output` complete. Add no public
|
||
output field or diagnostic-retention setting.
|
||
3. On failed status commands, include a clear truncation notice only when
|
||
needed, followed by the retained tail, while wrapping original process and
|
||
forwarding errors. Successful status calls release retained diagnostics.
|
||
4. Adapt existing output tests and benchmarks to exercise both modes. Test
|
||
below/exact/above budget, a single oversized write, wrapped small writes,
|
||
concurrent stdout/stderr, forwarded bytes, and error identity. Benchmark
|
||
modest output and 8 MiB/32 KiB-chunk output with allocated bytes reported.
|
||
|
||
Evidence: the retained status tail is bounded, full-output consumers keep all
|
||
bytes, and forwarded output remains complete. Update the internal Go-output
|
||
guide and its benchmark description to the implemented modes.
|
||
|
||
## Stage 15: Separate validation sequence and tree lifetime
|
||
|
||
Owners: [internal/validation/validation.go](../../internal/validation/validation.go)
|
||
and validation lifecycle/diagnostic tests. Target: A13.
|
||
|
||
1. Extract private Go-command and committed-tree execution functions. Keep the
|
||
visible order: tests, selected full vet, selected compilation, forbidden
|
||
files, formatting, workspace files, local replacements, file size, Markdown.
|
||
Shared-file selection alone still validates explicit file presence.
|
||
2. Let the committed-tree sequence own its close and the last content-reading
|
||
check. Preserve tree-load failure precedence, first check failure, and the
|
||
rule that reader-close failure replaces success only after a content read.
|
||
Keep context and underlying diagnostic causes through the public facade.
|
||
3. Preserve nil versus empty shared files and optional check selections,
|
||
operation-local Go settings reuse, and single execution of additional checks
|
||
and build callbacks by their existing owners. Use private functions and
|
||
explicit check blocks; retain current package and public interfaces.
|
||
|
||
Evidence: existing combined-check order, scope, Markdown, and lifecycle tests
|
||
remain meaningful. Add a focused case only if existing tests leave one of the
|
||
preserved precedence or metadata-only close behaviors unprotected.
|
||
|
||
## Stage 16: Extract private CLI workflows
|
||
|
||
Owners: [cmd/releasekit/main.go](../../cmd/releasekit/main.go) and CLI tests.
|
||
Target: A15.
|
||
|
||
1. Extract named private handlers for check/publication and for build. Keep
|
||
argument parsing, containing-repository resolution, version dispatch, and
|
||
command routing in `run`. Existing delivery handlers remain the local model.
|
||
2. Preserve profile loading, captured-candidate environment, expected module
|
||
and endpoint mapping, receipt invalidation before build-error reporting,
|
||
receipt verification, partial-artifact output, and all exit classifications.
|
||
Carry Stage 6's safe endpoint display and Stage 11's cleanup reporting into
|
||
the handlers without adding command flags or public interfaces.
|
||
3. Keep the CLI calling the public facade for release operations. Existing
|
||
internal path/configuration helpers retain their current role. Reuse the
|
||
command tests for profile errors, successful operations, known failures,
|
||
and unknown publication/delivery outcomes.
|
||
|
||
Evidence: the dispatcher is small while command behavior and failure evidence
|
||
match the selected contracts. No new CLI framework is needed.
|
||
|
||
## Stage 17: Remove incidental assertions and unused helpers
|
||
|
||
Owners: Markdown and Linux delivery-read tests, public publication tests,
|
||
[release identity](../../internal/releaseidentity/identity.go), and
|
||
[local tag helpers](../../internal/git/tag.go). Targets: A19 and A20.
|
||
|
||
1. Remove Markdown cache pointer-identity assertions; retain unique parsing
|
||
checks and identical-blob source-relative link behavior. Existing behavioral
|
||
tests remain the protection for correctness.
|
||
2. Remove `TestDeliverReadsLocalBinaryOnceForVerificationAndOnceForUpload`
|
||
as an exact inotify-open-count contract. Retain independent tampering,
|
||
pre-write verification, and uploaded-byte checks. Use the existing delivery
|
||
benchmark to observe read/verification cost; no replacement exact-open
|
||
assertion is required. Stage 1 handled successful-path query counts.
|
||
3. Remove only the unused `FromCommittedSelection` wrapper, keeping the private
|
||
implementation and live `FromCommitted`/`ResolveCommittedSelection` paths.
|
||
4. Remove unused `InspectLocalTag` and its direct test call, preserving the
|
||
test's other full-tag/source assertions and the live candidate guard.
|
||
Retain tree accessors and constructors used meaningfully by tests/benchmarks.
|
||
|
||
Evidence: source references show no remaining use of removed symbols; caller
|
||
behavior and public exports remain covered. Avoid tests that merely mirror
|
||
the deleted helpers or assert a new incidental call count.
|
||
|
||
## Stage 18: Record the deferred resource assessments
|
||
|
||
Targets: A11 and A17. Deliver evidence in their status notes here; accepted
|
||
production behavior remains as defined in [audit.md](audit.md).
|
||
|
||
1. For A11, inventory local repository/release/attachment JSON fixtures and
|
||
checked-in release-note sizes. Record measured byte sizes, the kinds of
|
||
responses represented, and missing evidence about deployment/protocol maxima.
|
||
Local fixtures establish observed sizes, not a supported maximum. Record
|
||
that JSON size/time caps and new configuration remain deferred; preserve
|
||
current cancellation and ambiguous-write handling. Live service queries
|
||
or an external sizing decision are not prerequisites to finish this sprint.
|
||
2. For A17, add `BenchmarkFileSizeExclusions` in a validation benchmark file.
|
||
Compare the current scan with a benchmark-only normalized set/ancestor
|
||
prototype for 1,000 and 10,000 paths; 1, 10, 100, and 1,000 exclusions; and
|
||
representative shallow/deep paths with early matches and nonmatches.
|
||
Count one index construction per simulated operation, report allocations,
|
||
and prepare unrelated fixture strings outside timing. Preserve literal
|
||
semantics in the comparison; do not add the prototype to production code.
|
||
3. Run the benchmark with a bounded measurement interval, for example:
|
||
|
||
```sh
|
||
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go test ./internal/validation \
|
||
-run '^$' -bench '^BenchmarkFileSizeExclusions$' -benchtime=100ms -count=3
|
||
```
|
||
|
||
4. Record toolchain/platform, command, timings/allocations, and representative
|
||
common/large-list tradeoffs. Keep production exclusion matching unchanged
|
||
in this sprint; the assessment supplies evidence for a later adoption
|
||
decision. Mark both items as assessment completed / production change
|
||
deferred, rather than claiming either resource policy is implemented.
|
||
|
||
Evidence: both deferred items have a concrete disposition and useful evidence
|
||
without inventing unapproved protocol limits or performance thresholds.
|
||
|
||
## Stage 19: Verify the complete target and update current documentation
|
||
|
||
1. Inspect the combined implementation against all A01–A20 outcomes and the
|
||
stage table. Confirm the fixes interact correctly: original-object reads
|
||
use the shared canceled-process boundary; partial tag evidence survives
|
||
cleanup errors; completed artifacts feed shared declarations; content limits
|
||
preserve preflight/write order and reconciliation outcomes; CLI output
|
||
presents causes and reached state accurately.
|
||
2. Complete canonical documentation updates in GoDoc, `docs/cli.md`, consumer
|
||
publication/build/delivery guides, `docs/integrations/gitea.md`, and relevant
|
||
internal guides. Document the accepted redirect and diagnostic policies,
|
||
raw endpoint sensitivity, and completed hosted state with cleanup error.
|
||
Keep implementation mechanics out of user flows. Preserve public facade
|
||
shape, receipt schema, source-only release behavior, and the Go baseline.
|
||
3. Format changed Go files and run from the repository root:
|
||
|
||
```sh
|
||
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go test ./...
|
||
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go test -race ./...
|
||
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go run ./internal/apicheck
|
||
```
|
||
|
||
Run focused regressions first as needed while completing their owners.
|
||
Reuse successful checks for unchanged content. Full-suite green results
|
||
complement, rather than replace, the targeted failure evidence above.
|
||
4. Check local documentation links/fragments and Markdown whitespace. Review
|
||
the diff for accidental public exports, stronger target/path restrictions,
|
||
new global deadlines, secret values, unrelated changes, and altered caller
|
||
ownership. Resolve failures within the selected scope before finishing.
|
||
5. Update this plan's stage statuses and record final verification. Keep A11
|
||
caps and A17 indexing explicitly deferred, with Stage 18 evidence. Retain
|
||
the source audit reports for review and traceability. Commit completed
|
||
nonempty work with plain English messages and report the result, remaining
|
||
deferrals, and any actual limitations. Release preparation remains governed
|
||
by the maintainer runbook.
|
||
|
||
Completion means the selected repairs and maintenance are implemented, their
|
||
behavioral evidence passes, current contracts are documented, and the two
|
||
accepted deferrals have assessment records. Intermediate stages introduce no
|
||
extra compilation, review, or deployment gates.
|