cli: replay command to rebuild from historical CloudTrail logs - #56
Conversation
f4adc6b to
1b0cd31
Compare
|
Reworked to the corrected v1 after review. All four P1s and both P2s that touched replay are addressed:
Simplifications also applied: streamed listing with no whole-range buffer, sort, or cross-prefix dedup (the CLI only emits ordered single-account/region prefixes); help documents the no-overlap requirement. The design doc's overlap claim (#54, finding P1 #3) is corrected there: the ingestor marker is a sequential-redelivery guard, not general idempotency, so overlap with live delivery is an explicit non-goal pending an atomic claim. Now stacked on #55 (both previously inserted at the same |
b487a9f to
c9c5139
Compare
Adds `trailtool replay`, which lists historical CloudTrail objects in S3 and invokes the ingestor Lambda once per object with a synthetic S3 event, reusing the live ingestion path so replayed and live data are identical. Selection is by explicit --prefix or by --from/--to (with --account and --region) expanded to per-day CloudTrail key prefixes. Listing is ascending, hence chronological, so windowed sessions and cross-file attribution behave as they did live. Objects are filtered to gzipped event logs (Digest/Insight/Aggregated skipped, matching the Lambda). Invocations run with bounded --concurrency. Failures are recorded, not fatal, and reported for targeted re-runs. A local resume cursor advances only past a contiguous run of successes, so an interrupted replay resumes without stranding a failed object below the cursor. --dry-run lists and counts without invoking. The core/replay package holds the driver behind Lister/Invoker/Cursor interfaces; the AWS-backed S3 lister and Lambda invoker are separated from the pure loop so it is tested with fakes (ordering, resume, contiguous high-water, dedup, dry-run) under -race. Part of #49 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks replay to the correct offline-rebuild v1: - Sequential invocation only. Removes the concurrency pool and --concurrency; cross-file attribution is order-sensitive and never repaired, so objects must reach the ingestor in chronological order. - Removes the persistent resume cursor (FileCursor and all wiring). It survived a reset (a rebuild would skip everything and leave the projection empty) yet did not survive a kill (saved only after the whole run). Replay is now stateless; a re-run relists the range. - Date-only --from/--to (YYYY-MM-DD). Rejects sub-day instants instead of silently rounding them up to whole boundary days, which would put out-of-range events into the projection. - Streamed listing: no whole-range buffer, sort, or cross-prefix dedup. The CLI only ever emits ordered single-account/region prefixes. - JSON mode now returns a non-nil error when any object failed, so scripted callers exit non-zero (previously only text mode did). Help documents the no-overlap requirement. Tests cover order preservation, failure-continue, context cancel, dry-run, selection validation, and the JSON failure exit code. Part of #49 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the "assumes it is the only writer / can double-count" wording with the actual contract: replay closed days, whose objects are disjoint from live delivery, so the two can run concurrently. Part of #49 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
--bucket is no longer required. When omitted, replay reads the bucket name from the deployed ingestor CloudFormation stack (the same stack names 'trailtool status' probes), so the operator does not repeat what the deployment already knows. --bucket remains as an override. Adds a CloudTrailBucketName output to the ingestor template and reads it, falling back to the stack parameter of the same name so it works on stacks deployed before the output existed. Selection flags are validated before any AWS call, so a bad invocation still fails fast without hitting CloudFormation. Part of #49 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
validateReplaySelection already guarantees exactly one of --prefix or --from/--to is set before this runs, so the mutual-exclusion case and the default were dead. Reduce to a plain prefix-or-day-range split. Part of #49 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c9c5139 to
f09af4c
Compare
Adds
trailtool replay, the second reset-and-replay primitive from #49 (design in #54,docs/design/cloudtrail-replay.md). With reset (#55), it gives a full rebuild: reset, then replay the range.Replay lists historical CloudTrail objects in S3 and invokes the ingestor Lambda once per object with a synthetic S3 event, the same shape EventBridge delivers live. It adds no second ingestion path, so replayed and live data are identical.
Selection
--prefixreplays every object under an explicit S3 key prefix (the escape hatch for org trails or custom layouts).--from/--to(with--accountand--region) expand to per-day CloudTrail key prefixes underAWSLogs/<account>/CloudTrail/<region>/YYYY/MM/DD/. Dates acceptYYYY-MM-DDor RFC3339.Listing is ascending, which for CloudTrail's date-partitioned keys is chronological. That ordering is what keeps windowed-fallback sessions and cross-file attribution behaving as they did live (design §6). Objects are filtered to gzipped event logs; Digest/Insight/Aggregated sidecars are skipped, matching the Lambda's own skips.
Execution
--concurrency(default 4). Synchronous invocation lets the driver observe per-object success and apply backpressure.--no-resumeignores it;--dry-runlists and counts without invoking.Structure
core/replayholds the driver behindLister/Invoker/Cursorinterfaces. The AWS-backed S3 lister and Lambda invoker live inaws.go, separated from the pure loop so the driver is tested with fakes: ordering, filtering, resume-skip, contiguous high-water on partial failure, overlapping-prefix dedup, and dry-run, all under-race. Adds thes3,lambda, andaws-lambda-go/eventsdependencies.Part of #49.