273 Commits
Author SHA1 Message Date
Miguel Ángel 164167341f chore: release v0.6.76 2026-06-06 04:19:56 +00:00
Miguel Ángel bb9dbfdebd chore: bump version to 0.6.75 2026-06-05 22:17:42 -04:00
Vance Ingalls 65888840fa fix(aws-lambda): validate event S3 URIs against render bucket (F-004) (#1213)
## Summary

- Adds `validateEventS3Uris()`, called immediately after `unwrapEvent()` in the Lambda handler before any S3 I/O.
- If `HYPERFRAMES_RENDER_BUCKET` env var is set, every S3 URI in the event (`ProjectS3Uri`, `PlanOutputS3Prefix`, `PlanS3Uri`, `ChunkOutputS3Prefix`, `ChunkS3Uris`, `AudioS3Uri`, `OutputS3Uri`) must resolve to that bucket. Mismatches throw `S3_URI_NOT_ALLOWED`.
- Env var unset → validation skips (backwards-compatible; existing deployments without the var continue to work).
- CDK stack (`HyperframesRenderStack`) auto-wires `HYPERFRAMES_RENDER_BUCKET: this.bucket.bucketName` so new deployments are protected without manual config.
- `S3_URI_NOT_ALLOWED` added to all three `NON_RETRYABLE_*` lists in the Step Functions state machine so the state machine does not retry on this error.

## Security

**F-004 MED** — The Lambda handler accepted S3 URIs from the event payload without verifying they targeted the function's own render bucket. An attacker who could inject a crafted Step Functions execution input could route `GetObject` / `PutObject` calls to arbitrary buckets in the same AWS account, potentially exfiltrating plan data or overwriting objects in unrelated buckets.

## Test plan

- [x] `handler` rejects a `plan` event whose `ProjectS3Uri` targets a different bucket — `S3_URI_NOT_ALLOWED` thrown, zero S3 ops recorded
- [x] `handler` rejects an `assemble` event with one cross-bucket chunk URI
- [x] Validation is skipped when `HYPERFRAMES_RENDER_BUCKET` is unset (no regression for existing callers)
- [x] All 12 handler unit tests pass
2026-06-05 17:52:53 -07:00
Miguel Ángel a7cc9161a7 chore: release v0.6.74 2026-06-05 18:41:55 -04:00
Miguel Ángel 2757949912 chore: release v0.6.73 2026-06-04 22:52:23 +00:00
James 0b98565039 chore: release v0.6.72 2026-06-04 07:38:21 +00:00
Miguel Ángel c6a91ab0e4 chore: release v0.6.71 2026-06-04 03:11:40 +00:00
Miguel Ángel f5d81cb5a7 chore: release v0.6.70 2026-06-03 04:41:52 +00:00
Miguel Ángel 598e3e957a chore: release v0.6.69 2026-06-01 20:14:01 -04:00
Miguel Ángel bda4a32a7e chore: release v0.6.68 2026-06-01 20:05:12 -04:00
James f37e3b993e chore: release v0.6.67 2026-06-01 22:28:28 +00:00
Miguel Ángel cfef6caf5f chore: release v0.6.66 2026-06-01 20:48:20 +00:00
Miguel Ángel 9ead3a83b5 chore: release v0.6.65 2026-06-01 13:50:51 +00:00
Miguel Ángel a7b874326a chore: release v0.6.64 2026-05-31 13:56:46 +00:00
Miguel Ángel 4f1f99ef1d chore: release v0.6.63 2026-05-30 17:28:36 +00:00
Miguel Ángel 31441fc752 chore: release v0.6.62 2026-05-30 13:11:49 +00:00
Miguel Ángel 13b1bffe01 chore: bump version to 0.6.61 2026-05-29 23:36:15 -04:00
Miguel Ángel d32c8dcb6f chore: release v0.6.60 2026-05-30 02:22:16 +00:00
Miguel Ángel 307e391d91 chore: release v0.6.59 2026-05-29 23:32:38 +00:00
Miguel Ángel 30c8344651 chore: bump version to 0.6.58 2026-05-29 13:18:51 -04:00
Miguel Ángel 43c56ee476 chore: bump version to 0.6.57 2026-05-29 10:34:08 -04:00
Miguel Ángel bc3701f590 chore: bump version to 0.6.56 2026-05-28 23:51:08 -04:00
Miguel Ángel b1f9587aa1 chore: bump version to 0.6.55 2026-05-28 20:58:58 -04:00
Miguel Ángel 2f3ab9f4c9 chore: bump version to 0.6.54 2026-05-28 19:18:34 -04:00
Miguel Ángel e16f916448 chore: bump version to 0.6.53 2026-05-28 17:06:50 -04:00
Miguel Ángel 7be4f92f18 chore: release v0.6.52 2026-05-27 20:23:26 -04:00
Miguel Ángel d8ce2e4b50 chore: release v0.6.51 2026-05-27 12:15:38 -04:00
Miguel Ángel 5cd4db07e3 chore: release v0.6.50 2026-05-27 15:28:56 +00:00
Miguel Ángel 7ea4d1c131 chore: release v0.6.49 2026-05-27 01:45:45 -04:00
Miguel Ángel 7cde0d9554 chore: release v0.6.48 2026-05-26 23:46:36 -04:00
Miguel Ángel 2d0acb3494 chore: release v0.6.47 2026-05-26 20:26:05 -04:00
Miguel Ángel 60cb9552e4 chore: release v0.6.46 2026-05-25 23:49:33 +00:00
Miguel Ángel 9a4a00582c chore: release v0.6.45 2026-05-25 19:45:52 +00:00
Miguel Ángel c46adb52e2 chore: release v0.6.44 2026-05-25 16:56:50 +00:00
Miguel ÁngelandClaude Sonnet 4.6 e4e2234303 chore: release v0.6.43
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 13:35:55 +00:00
Miguel Ángel d2b915be9e chore: release v0.6.42 2026-05-24 17:36:30 -04:00
Miguel Ángel 7461f1df30 chore: bump version to 0.6.41 2026-05-24 14:26:59 -04:00
Miguel Ángel 7eb92badb2 Merge pull request #1058 from kiyeonjeon21/fix/aws-lambda-build-zip-linux-ffmpeg
fix(aws-lambda): fail build-zip when ffmpeg-static binary isn't Linux x86-64
2026-05-24 12:30:00 -04:00
Kiyeon Jeon bc20b87b9a fix(aws-lambda): resolve Chromium for handlePlan before invoking probe
The producer's probe stage launches Chromium when Plan has to resolve
browser-only data: root duration unknown, unresolved sub-compositions, or
data-hf-auto-start media. Only handleRenderChunk was setting
PRODUCER_HEADLESS_SHELL_PATH, so a cold Plan invocation launched
puppeteer-core with no executablePath and failed before writing plan.tar.gz.

Mirror the renderChunk env-var guard inside handlePlan so the bundled
Sparticuz binary gets resolved on the first Plan invocation and reused on
warm starts. The skipChromeResolution dep stays honored for SAM-local RIE
smokes.

A warm Lambda environment can mask this only if it previously served a
renderChunk from another execution and left the env var sticky. Within a
single Step Functions execution, Plan still runs before RenderChunks.

A new dispatch test exercises the guard path by pre-seeding
PRODUCER_HEADLESS_SHELL_PATH and asserting Plan does not overwrite it.
2026-05-24 16:22:31 +09:00
Kiyeon Jeon 9b34114dd1 fix(aws-lambda): fail build-zip when ffmpeg-static binary is not Linux x86-64
`ffmpeg-static` materializes a single platform-selected binary at install
time. By default that follows the install host, so a default macOS/arm64
or linux/arm64 install can stage a binary that Lambda's x86-64 runtime
cannot execute.

Verify the ELF header (ELFCLASS64, EM_X86_64) before copying the binary
into `bin/ffmpeg`. When the check fails, surface the canonical workarounds:
run the build inside a linux/amd64 container, or pre-install with
`npm_config_platform=linux npm_config_arch=x64`.

In the distributed pipeline this mismatch can fail as early as Plan's
`ffmpeg -version` probe after browser probing and before chunks are
scheduled. Later encode/assemble spawns would fail for the same reason.

ffprobe already goes through the platform-segmented
`ffprobe-static/bin/linux/x64` path, so that side doesn't need the same
check.
2026-05-24 16:21:01 +09:00
James 71d1889da6 feat(distributed): add optional cfr flag for exact constant frame rate
Distributed-render output today uses -c:v copy through concat → mux →
faststart, which means PTS timestamps from each chunk pass through
unchanged. Container r_frame_rate is exact (#1040 + this PR's parent),
but stream-level avg_frame_rate stays PTS-derived and can land on
fractional rationals like 27648000/921677 over a 60s render. Same for
sub-ms duration drift.

This is the achievable bar within -c copy stream-copy concat. For most
consumers (browser playback, YouTube, etc.) the difference is invisible.
For downstream tools that strict-check avg_frame_rate or
ms-precision duration (broadcast workflows, frame-accurate compositors,
some third-party transcoders), it matters.

Adds an opt-in cfr config flag (default false). When true, the
assemble step's final pass re-encodes with -fps_mode cfr -r <fps>
instead of -c copy, producing exact CFR output. Trade-off: ~2-5x the
stitch time for a 60s 1080p clip; second-generation H.264 quality loss
is negligible at -crf 18 but is non-zero.
2026-05-24 00:24:30 -04:00
Miguel Ángel 47d57bff10 chore: bump version to 0.6.40 2026-05-23 15:01:38 -04:00
James 179b09ec9d chore: release v0.6.39 2026-05-23 17:30:05 +00:00
Miguel Ángel 3560678bb2 chore: bump version to 0.6.38 2026-05-23 00:13:50 -04:00
James 258bd6256c chore: release v0.6.37 2026-05-22 23:17:08 +00:00
JamesandClaude Opus 4.7 0f624f59fe fix(aws-lambda): surface sparticuz wedge as typed non-retryable error
Repeated Sandbox.Timedout chunks can leave @sparticuz/chromium
returning a falsy/empty path on subsequent invocations — warm
instances on the same execution environment never re-extract
chromium. The downstream puppeteer-core assertion about needing an
executablePath or channel buries the actionable cause; a cost-
analysis sweep took ~30 min to root-cause from that trace.

Guard the resolver: if mod.executablePath() returns a non-string,
empty string, or a path that does not exist on disk, throw a typed
ChromeBinaryUnavailableError whose message points at the recycle
remedy (env-var bump or redeploy). Add the error name to the three
NON_RETRYABLE lists so SFN short-circuits instead of burning four
15-min retries on a function that won't recover.

Same typed-error contract for the chrome-headless-shell fallback so
both sources fail consistently. Tests pin the wedge path (empty
string + non-existent file) and the carried metadata (source +
resolvedPath).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 16:52:41 -04:00
JamesandClaude Opus 4.7 d4384722e8 fix(aws-lambda): account for TaskScheduled/TaskSucceeded in cost
The CDK construct compiles tasks.LambdaInvoke to the optimized
arn:aws:states:::lambda:invoke integration, which emits Task* history
events with the Lambda response wrapped in .Payload. getRenderProgress
was only listening for the older LambdaFunction* events, so every CDK-
deployed stack reported $0 total cost and zero invocations on success
— a high-visibility regression that only surfaced when we manually
walked SFN history during a cost-analysis sweep.

Add cases for TaskScheduled (count invocation), TaskSucceeded (parse
Payload + accumulate billed duration / frame counts), and TaskFailed
(record error). Keep the LambdaFunction* paths so anyone wiring the
raw lambda:invokeFunction.sync task type still works. Factor out the
shared FramesEncoded-attribution logic so both branches agree on the
"only RenderChunk frames count" rule.

Tests pin a real-shape regression: replay the inspector-launch
1080p/30fps history (1 Plan + 16 RenderChunks + 1 Assemble) and assert
lambdaUsd lands at ~$0.582 — matching the cost-analysis script's
direct read against SFN history.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 16:29:25 -04:00
Miguel Ángel 154359d95d chore: bump version to 0.6.36 2026-05-22 13:37:28 -04:00
Miguel Ángel 6c191e2292 chore: bump version to 0.6.35 2026-05-22 13:31:45 -04:00
Miguel Ángel aebb7b2660 chore: bump version to 0.6.34 2026-05-22 11:44:06 -04:00