401 lines
15 KiB
Markdown
401 lines
15 KiB
Markdown
# Code Quality Cleanup Roadmap
|
|
|
|
## Current Baseline
|
|
|
|
The codebase has completed the local, SSH/SFTP, S3, public bundle package,
|
|
manifest creation, JSON output, path mapping, link generation, and HTTP upload
|
|
work documented in the current user and internal docs.
|
|
|
|
The audit in `docs/roadmap/audit.md` found no major architectural risk. The
|
|
remaining cleanup work should be narrow, behavior-preserving, and focused on
|
|
reducing drift in upload staging, runtime config setup, run reporting, backend
|
|
config handling, output projection, path validation tests, and internal
|
|
coordination code.
|
|
|
|
One intentional behavior change is part of this cleanup roadmap: malformed
|
|
authenticated upload archives should be rejected before `202 Accepted`, rather
|
|
than accepted and later marked failed. Valid staged uploads should still run
|
|
asynchronously after admission.
|
|
|
|
## Cleanup Principles
|
|
|
|
- Preserve public CLI behavior, config schema, manifest schema, destination
|
|
state schema, backend behavior, and JSON envelopes unless a stage explicitly
|
|
says otherwise.
|
|
- Keep config parsing and validation in `internal/config`.
|
|
- Keep CLI parsing in `internal/cli`.
|
|
- Keep upload archive policy in `internal/ingest`; keep HTTP routing,
|
|
authentication, and status projection in `internal/app`.
|
|
- Keep backend-specific filesystem, SSH/SFTP, and S3 behavior in adapter
|
|
packages.
|
|
- Prefer small package-local helpers over broad abstractions.
|
|
- Add or strengthen tests before refactoring behavior that affects public
|
|
output, upload admission, path safety, or run reporting.
|
|
|
|
## Active Cleanup Stages
|
|
|
|
Implement these stages in order. Each stage should be small enough for one
|
|
implementation prompt and should leave the repository passing the listed focused
|
|
tests before moving to the next stage.
|
|
|
|
## Stage 1: HTTP Upload Staging Boundary
|
|
|
|
Goal:
|
|
|
|
Move archive validation and upload body staging fully behind `internal/ingest`,
|
|
stop app-layer full-body buffering, and reject malformed archives before
|
|
returning `202 Accepted`.
|
|
|
|
Implementation scope:
|
|
|
|
- Add an ingestion-owned content-type helper, such as
|
|
`ValidateContentType(contentType string) error`, and remove duplicated
|
|
content-type policy from the HTTP handler.
|
|
- Replace the current handler-side `readUploadBody` buffering with streaming
|
|
staging through `internal/ingest`.
|
|
- Introduce a two-step upload coordinator admission model:
|
|
- reserve a run id and queue slot before consuming the request body;
|
|
- stage and validate the archive using that reserved run id;
|
|
- enqueue only a successfully staged local bundle root for async execution.
|
|
- Keep queue-full rejection before reading the body.
|
|
- Preserve `401` for missing or invalid bearer tokens, `415` for unsupported
|
|
content type, `413` for oversized uploads, and `503` for a full queue.
|
|
- Return a pre-acceptance `400` for malformed tar/gzip content or invalid
|
|
staged bundles.
|
|
- Preserve async queued/running/succeeded/failed status after a valid staged
|
|
bundle is accepted.
|
|
- Do not add durable queues, idempotency keys, zstd, or new routes.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- Update `docs/cli.md`, `docs/config.md`, `docs/operations.md`,
|
|
`docs/troubleshooting.md`, `docs/internal/app.md`, and
|
|
`docs/internal/ingest.md` only as needed to describe the new
|
|
pre-acceptance failure boundary.
|
|
|
|
Tests:
|
|
|
|
- `go test ./internal/ingest ./internal/app ./internal/cli`
|
|
- Queue-full upload rejection does not read the request body.
|
|
- Unsupported content type is rejected through ingestion-owned policy.
|
|
- Oversized uploads return `413` and do not retain a staged run.
|
|
- Malformed tar/gzip content returns `400` before a run id is issued.
|
|
- Valid tar and tar.gz uploads return `202` after staging and still transition
|
|
through async status.
|
|
- HTTP responses and status records do not leak bearer tokens or secret values.
|
|
|
|
Completion criteria:
|
|
|
|
- `internal/app` no longer buffers the full upload body before staging.
|
|
- A valid accepted upload has a committed staged bundle root before the `202`
|
|
response is sent.
|
|
- Invalid archive content cannot create an accepted run id.
|
|
|
|
## Stage 2: Runtime Config And Secret Setup Helper
|
|
|
|
Goal:
|
|
|
|
Centralize runtime config path resolution, config loading, secret loading,
|
|
environment resolver creation, and secret-conflict warning projection in one
|
|
app-layer helper.
|
|
|
|
Implementation scope:
|
|
|
|
- Add a small `internal/app` runtime setup helper that:
|
|
- defaults an empty config path to `config.DefaultConfigPath`;
|
|
- calls `config.LoadFile`;
|
|
- calls `config.LoadSecretEnvironment`;
|
|
- exposes the loaded config, config path, `config.Environment`, and
|
|
`[]OutputWarning` for secret conflicts.
|
|
- Use the helper from `Run`, `RunPipeline`, `RunPipelineWithLocalSource`,
|
|
configured `Validate`/`Inspect`, and `Serve` where applicable.
|
|
- Keep `manifest create` outside runtime config loading.
|
|
- Keep YAML structs, defaults, validation, and secret-directory parsing in
|
|
`internal/config`.
|
|
- Preserve app test injection points for backend factories and upload handler
|
|
tests.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- Update `docs/internal/app.md` if helper boundaries or flow descriptions
|
|
change. User-facing docs should not change unless observable behavior changes.
|
|
|
|
Tests:
|
|
|
|
- `go test ./internal/config ./internal/app ./internal/cli`
|
|
- Default config path behavior remains unchanged.
|
|
- Secret conflict warnings still appear in text and JSON output for `run`,
|
|
configured `validate`, and configured `inspect`.
|
|
- `serve` still fails startup safely for missing, empty, or duplicate upload
|
|
tokens without leaking values.
|
|
- Explicit S3 credential references still resolve through the config-owned
|
|
environment resolver.
|
|
|
|
Completion criteria:
|
|
|
|
- Runtime commands no longer repeat config path defaulting and secret loading.
|
|
- Config policy remains owned by `internal/config`.
|
|
|
|
## Stage 3: Run Destination Processing Extraction
|
|
|
|
Goal:
|
|
|
|
Reduce complexity in the main run loop while preserving run report behavior,
|
|
warning ordering, action ordering, failure aggregation, and text/JSON output.
|
|
|
|
Implementation scope:
|
|
|
|
- Extract narrow helpers from `internal/app/run.go` for destination-scoped
|
|
processing.
|
|
- Centralize destination-scoped failure recording so one helper updates
|
|
`runFailures`, `runSummary`, `RunReport.Actions`, and pipeline events.
|
|
- Centralize normalization of partial `publish.Plan` identity fields before
|
|
converting plans to run action records.
|
|
- Keep app orchestration explicit; do not introduce a generic workflow engine,
|
|
stage framework, or broad runner abstraction.
|
|
- Preserve independent destination fan-out and partial-result behavior.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- Update `docs/internal/app.md` only if helper names or package layout
|
|
descriptions materially change.
|
|
|
|
Tests:
|
|
|
|
- `go test ./internal/app ./internal/publish ./internal/state`
|
|
- Destination open failures for multiple selected bundles keep action records,
|
|
output errors, summary counters, and pipeline events aligned.
|
|
- JSON partial-result output remains unchanged when destination planning or
|
|
execution fails after a report exists.
|
|
- Fixed-path dry-run warnings appear in the same order as before.
|
|
- Existing run text output assertions continue to pass.
|
|
|
|
Completion criteria:
|
|
|
|
- `run.go` delegates destination-scoped record/failure bookkeeping to helpers.
|
|
- No public output shape or ordering changes.
|
|
|
|
## Stage 4: Backend Config Normalized View
|
|
|
|
Goal:
|
|
|
|
Reduce source/destination backend config drift while preserving the current YAML
|
|
schema and public config behavior.
|
|
|
|
Implementation scope:
|
|
|
|
- Add package-local normalized backend view helpers in `internal/config` for
|
|
source and destination backend fields.
|
|
- Use the normalized view to reduce duplication in backend defaulting and
|
|
validation where it remains clearer than the current paired code.
|
|
- Keep `config.Backend` and `config.Destination` YAML structs and tags
|
|
unchanged.
|
|
- Preserve destination-only policy fields on `Destination`.
|
|
- Preserve `http_upload` as source-only and invalid for destinations.
|
|
- Update app backend opening only if the normalized view provides clearer
|
|
handoff without leaking config internals.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- None expected unless internal docs mention the old paired implementation
|
|
shape in a way that becomes misleading.
|
|
|
|
Tests:
|
|
|
|
- `go test ./internal/config ./internal/app`
|
|
- Equivalent local, SSH, and S3 source/destination validation remains
|
|
consistent.
|
|
- Defaults for SSH port/host key policy, S3 region/prefix/force-path-style, and
|
|
HTTP upload staging fields remain unchanged.
|
|
- `http_upload` remains valid only for sources.
|
|
|
|
Completion criteria:
|
|
|
|
- Adding a future backend field has one obvious defaulting/validation path.
|
|
- Public config files and examples continue to load unchanged.
|
|
|
|
## Stage 5: Command Output Projection Cleanup
|
|
|
|
Goal:
|
|
|
|
Reduce drift in bundle and file metadata projection for app command JSON
|
|
results.
|
|
|
|
Implementation scope:
|
|
|
|
- Add small app-local projection helpers for bundle summaries and manifest file
|
|
records used by `validate`, `inspect`, and `manifest create`.
|
|
- Use `time.RFC3339` consistently instead of equivalent literal layouts.
|
|
- Preserve existing JSON envelope fields, command names, command-specific result
|
|
field names, text output, and fatal error behavior.
|
|
- Do not redesign CLI JSON output or HTTP JSON responses.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- None expected unless tests reveal current docs are stale.
|
|
|
|
Tests:
|
|
|
|
- `go test ./internal/app ./internal/cli`
|
|
- JSON output for `validate`, `inspect`, and `manifest create` remains
|
|
structurally stable.
|
|
- RFC3339 timestamps remain unchanged, including offset-preserving source
|
|
timestamps where current behavior preserves them.
|
|
- Text output remains unchanged.
|
|
|
|
Completion criteria:
|
|
|
|
- Bundle/file projection logic is shared where semantics match.
|
|
- Command-specific result structs remain easy to read.
|
|
|
|
## Stage 6: Archive And Source Path Validation Alignment
|
|
|
|
Goal:
|
|
|
|
Protect path safety by aligning archive path tests with source and storage path
|
|
policy, without blurring archive-specific rules.
|
|
|
|
Implementation scope:
|
|
|
|
- Add mirrored path-safety table tests around `internal/ingest`, `pkg/bundle`,
|
|
`internal/bundle`, and `internal/storage` where useful.
|
|
- Keep archive-specific directory handling, root-level manifest rules, duplicate
|
|
file rejection, symlink rejection, hardlink rejection, and special-entry
|
|
rejection in `internal/ingest`.
|
|
- Centralize code only if the helper can preserve clear archive semantics and
|
|
current error behavior.
|
|
- Do not add new public `pkg/bundle` APIs unless the existing public API cannot
|
|
safely support the needed shared behavior.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- None expected unless implementation changes error boundaries or internal
|
|
package descriptions.
|
|
|
|
Tests:
|
|
|
|
- `go test ./pkg/bundle ./internal/bundle ./internal/ingest ./internal/storage`
|
|
- Absolute paths, traversal, backslashes, empty paths, dot segments, nested
|
|
manifests, `.distributor.json` handling, symlinks, hardlinks, devices, and
|
|
sockets remain covered.
|
|
- Archive directories remain accepted where safe.
|
|
|
|
Completion criteria:
|
|
|
|
- Path safety policy has regression coverage across archive staging, source
|
|
bundle validation, and storage logical path validation.
|
|
- Any code sharing is smaller and clearer than the duplicated logic it replaces.
|
|
|
|
## Stage 7: Pipeline Run Coordinator Removal
|
|
|
|
Goal:
|
|
|
|
Remove the currently unused internal `PipelineRunCoordinator` to avoid
|
|
maintaining two similar coordination concepts.
|
|
|
|
Implementation scope:
|
|
|
|
- Delete `PipelineRunCoordinator`, `PipelineRunRecord`,
|
|
`DuplicatePipelineRunError`, related helpers, and their tests.
|
|
- Remove or rewrite `docs/internal/app.md` sections that describe the removed
|
|
coordinator.
|
|
- Keep `UploadCoordinator`; do not merge upload queueing with the removed
|
|
duplicate-run coordinator.
|
|
- Before deletion, confirm with `rg` that production code does not reference
|
|
`NewPipelineRunCoordinator`, `PipelineRunCoordinator`, or
|
|
`DuplicatePipelineRunError`.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- Update `docs/internal/app.md` because it currently documents the coordinator
|
|
as an internal implemented component.
|
|
|
|
Tests:
|
|
|
|
- `go test ./internal/app ./internal/cli`
|
|
- `rg -n "PipelineRunCoordinator|NewPipelineRunCoordinator|DuplicatePipelineRunError" internal docs`
|
|
should show no stale references after removal.
|
|
|
|
Completion criteria:
|
|
|
|
- No production, test, or internal documentation references remain for the
|
|
removed coordinator.
|
|
- Upload coordination behavior is unchanged.
|
|
|
|
## Stage 8: Narrow CLI And Test Helper Cleanup
|
|
|
|
Goal:
|
|
|
|
Apply only low-risk CLI setup and test fixture cleanup that remains useful after
|
|
the earlier stages.
|
|
|
|
Implementation scope:
|
|
|
|
- Add tiny CLI helpers for repeated `flag.FlagSet` setup or output-format
|
|
parsing only where command behavior remains obvious.
|
|
- Keep the standard-library CLI; do not introduce a CLI framework.
|
|
- Keep `manifest create` interspersed positional parsing local unless another
|
|
command now needs the same parsing behavior.
|
|
- Expand `internal/testutil` only for repeated setup touched by earlier stages.
|
|
- Do not rewrite tests wholesale just to use shared helpers.
|
|
|
|
Current-behavior documentation updates:
|
|
|
|
- None expected unless CLI help or syntax changes. This stage should avoid such
|
|
changes.
|
|
|
|
Tests:
|
|
|
|
- `go test ./internal/cli ./internal/app`
|
|
- CLI usage-error tests remain stable.
|
|
- `manifest create <path> --id x`, `manifest create --id x <path>`, missing
|
|
flag values, invalid `--format`, and help output remain covered.
|
|
|
|
Completion criteria:
|
|
|
|
- Remaining CLI/test cleanup is small, readable, and behavior-preserving.
|
|
- No public CLI syntax or output changes.
|
|
|
|
## Refactors To Avoid
|
|
|
|
- Do not introduce a generic workflow engine or stage framework.
|
|
- Do not add a CLI framework.
|
|
- Do not merge local, SSH, S3, and fake backend adapter implementations.
|
|
- Do not collapse `pkg/bundle` and `internal/bundle`.
|
|
- Do not move destination state comparison into `internal/publish` or
|
|
`internal/app`.
|
|
- Do not redesign CLI JSON envelopes.
|
|
- Do not change HTTP JSON response shapes except where Stage 1 requires
|
|
pre-acceptance error behavior.
|
|
- Do not add durable upload queues, retry workers, zstd support, in-app TLS,
|
|
idempotency keys, browser UI, or other feature work.
|
|
- Do not rewrite tests wholesale to use new fixture helpers.
|
|
|
|
## Validation
|
|
|
|
After each implementation stage, run the stage-specific tests listed above.
|
|
|
|
After all cleanup stages:
|
|
|
|
```sh
|
|
go test ./...
|
|
```
|
|
|
|
Recommended consistency checks:
|
|
|
|
```sh
|
|
rg -n "LoadFile\\(|LoadSecretEnvironment\\(|DefaultConfigPath" internal/app internal/cli
|
|
rg -n "application/x-tar|application/gzip|application/x-gzip" internal docs
|
|
rg -n "2006-01-02T15:04:05Z07:00" internal pkg
|
|
rg -n "PipelineRunCoordinator|NewPipelineRunCoordinator|DuplicatePipelineRunError" internal docs
|
|
```
|
|
|
|
The cleanup is complete when:
|
|
|
|
- all staged tests and `go test ./...` pass;
|
|
- current-behavior docs describe the implemented Stage 1 upload failure
|
|
boundary;
|
|
- `docs/roadmap/audit.md` findings have either been addressed or consciously
|
|
left in place as noted in this cleanup roadmap;
|
|
- no completed cleanup behavior is documented only as future work.
|