- WebP output carries ICC, EXIF, and XMP in
ICCP/EXIF/XMPcontainer chunks, lossy encoding included. libwebp embeds no metadata, so truss now writes the chunks itself, promoting the container to the extended (VP8X) format when needed. - E2E coverage (atago) for the output pixel budget, color-model preservation, and metadata retention, plus an
integration/fixtures/icc-profile.jpgfixture carrying an embedded sRGB profile.
--strip-metadatanow documents, intruss help convert/help optimizeand the README, that lossy optimization keeps the ICC profile so colors are not shifted by the re-encode. The README also gains a per-format metadata support table.
convert/optimize: enforceMAX_OUTPUT_PIXELSagainst the real output size when only one of--width/--heightis given (#252). The check previously used the source size for the omitted axis, so--width 10000on a small image produced a 100-megapixel output with exit 0, and a large enough single dimension stalled while allocating the resize buffer.convert/optimize: stop adding an alpha channel to opaque images (#253). Every decoded image was widened to RGBA8 before encoding, so a no-op same-format pass flippedhasAlphafromfalsetotrueand grew the file. PNG, WebP, BMP, TIFF, and AVIF output now use an RGB color model whenever the pixels are fully opaque, and keep alpha whenever any pixel is not.inspect: reporthasAlphafor lossless WebP (VP8L) instead ofnull; thealpha_is_usedheader bit is now read.optimize --format webp --mode lossyno longer fails on ICC-bearing input (#279). The lossy encoder rejected any retained metadata, while a strip request is upgraded to "preserve ICC" for lossy output, so no flag combination worked —--strip-metadatawas itself the reason the command failed.- The lossy "preserve ICC" upgrade now applies only to formats that can carry a profile (JPEG, PNG, WebP). For AVIF it stays a full strip instead of putting the pipeline into a state the encoder rejects.
- Batch dependency updates (consolidated from Dependabot PRs):
- Rust:
hmac0.12 → 0.13 andsha20.10 → 0.11 (RustCryptodigest0.11);rav1d-safe0.3 → 0.5;azure_storage_blob0.9 → 0.10 withazure_core0.32 → 0.33;tokio1.50 → 1.52,uuid1.22 → 1.23,aws-sdk-s31.127 → 1.129,google-cloud-storage1.9 → 1.10,google-cloud-auth1.7 → 1.8,libc0.2.183 → 0.2.186,rand0.9.2 → 0.9.4. - Examples:
typescript5.9 → 6.0 (Next.js),puppeteer-core24 → 25.vitekept on the 7.x line (7.3.5); Vite 8 drops the wasm-bindgennew URL(..., import.meta.url)asset reference and breaks the WASM example, so the upgrade is deferred. - GitHub Actions:
actions/configure-pages5 → 6,actions/upload-pages-artifact4 → 5,actions/deploy-pages4 → 5,softprops/action-gh-release2 → 3.
- Rust:
- Pin integration-test container images to fixed versions (
adobe/s3mock4.11.0,fsouza/fake-gcs-server1.54.0,azurite3.35.0,runnv1.9.2) to avoid breakage from floating:latesttags. s3mock 5.0.0 changedGET /<bucket>to return an HTTP error instead of 200, which broke the s3 readiness probe.
- Update
rustls-webpki0.103.10 → 0.103.13 to patch RUSTSEC-2026-0098/0099/0104 (name-constraint bypass and CRL-parsing panic) on the modern rustls 0.23 path. - Ignore RUSTSEC-2026-0098/0099/0104 for the transitive
rustls-webpki0.101.7 (legacy AWS SDKrustls0.21 path; upstream has not migrated yet — same rationale as RUSTSEC-2026-0049).
- Bump MSRV from 1.87 to 1.92.
- Update
aws-lc-sys0.38.0 → 0.39.0 to fix CRL Distribution Point scope check logic error and X.509 Name Constraints bypass via wildcard/unicode CN (high severity). - Update
rustls-webpki0.103.9 → 0.103.10 to fix certificate revocation enforcement bug (medium severity). - Ignore RUSTSEC-2026-0049 for
rustls-webpki0.101.7 (transitive dep via AWS SDK'srustls0.21; upstream has not migrated yet).
- Port security and edge-case tests:
- SSRF: redirect chain to metadata endpoint, scheme rejection (ftp/file/data), userinfo rejection, private IP/port blocking in strict mode.
- Path traversal: E2E coverage for
../../etc/passwd, mid-path dotdot,.gitfile content leak prevention. - Remote errors: upstream 4xx/5xx/403 mapped to 502, Content-Length exceeding limit returns 413, unsupported Content-Encoding (deflate, zstd) returns 502.
- Image edge cases: corrupted/empty/truncated images return 415, ETag stability and divergence across processing options, ETag mismatch returns 200.
- IP deny-list boundary tests: CGNAT, TEST-NET 198.18/15, broadcast, multicast, documentation ranges, IPv6 mapped/compatible/6to4/Teredo variants.
- Path resolution: null byte injection, backslash literal on Unix, unicode filenames, very long components, multiple leading slashes, trailing dotdot.
- Content-Encoding: multiple known encodings, mixed with unknown, whitespace handling.
- Cloud metadata: GCP/AWS path variants, non-metadata IP allowed.
- Align crate, npm package, OpenAPI, example lockfile, and changelog release metadata for the
v0.11.3release.
- Publish a production-oriented Next.js example that signs public truss URLs with
@nao1215/truss-url-signer.
- Verify Homebrew installs against
nao1215/tap/trussduring tagged releases and keep the formula layout aligned withnao1215/homebrew-tap.
- Align crate, npm package, OpenAPI, example lockfile, and changelog release metadata for the
v0.11.2release.
- Publish
trussHomebrew formulas from tagged releases tonao1215/homebrew-tapand verify installation on macOS.
- Publish
@nao1215/truss-url-signerfrom tagged releases via npm trusted publishing. - Add README and deployment guide install paths for Homebrew and clarify the release prerequisites for the tap automation.
- Align crate, npm package, OpenAPI, example lockfile, and changelog release metadata for the
v0.11.1release.
- Official
@nao1215/truss-url-signernpm package source and release artifact flow for Node.js / TypeScript public signed URLs. - Type definition compile checks plus Rust/Node compatibility coverage for
HEADsigning, presets, and watermark parameters.
- Validate signed URL transform and watermark options in the TypeScript signer so it rejects server-invalid values before signing.
- Align crate, npm package, OpenAPI, and changelog release metadata for the
v0.11.0release.
- Align crate, package, OpenAPI, and changelog release metadata for the
v0.10.4tag after bootstrapping the npm package and trusted publisher settings.
- Switch npm package publishing in GitHub Actions from
NPM_TOKEN-based authentication to npm trusted publishing with GitHub OIDC.
- Align crate, package, OpenAPI, and changelog release metadata for the
v0.10.3tag.
- Fix GitHub release workflow validation so the npm publish job no longer references
secretsdirectly in anif:expression. - Align crate, package, OpenAPI, and changelog release metadata for the
v0.10.2tag.
- Official
@nao1215/truss-wasmnpm package source for third-party browser integration with a fixedwasm,svg,aviffeature set. - Release automation to pack the Wasm npm package, attach its tarball to GitHub Releases, and publish to npm when
NPM_TOKENis configured.
- Expanded WASM documentation with npm package quick-start guidance, bundler-focused distribution details, build-mode differences, and local packaging instructions.
- Clarified the supported browser build matrix so AVIF support and WebP lossless behavior are explicit in the official package flow.
- Format-aware image optimization across the CLI, HTTP API, signed URLs, presets, and WASM with
optimize=auto|lossless|lossyplus perceptualtargetQualitycontrols. - Optional Bearer token authentication for
/healthviaTRUSS_HEALTH_TOKEN, while keeping/health/liveand/health/readyunauthenticated for orchestrator probes (#73). - Readiness probe hysteresis via
TRUSS_HEALTH_HYSTERESIS_MARGINto reduce flapping near disk and memory thresholds (#72). - Additional fast coverage for lifecycle signal handling, public
HEADendpoints, and CLI runtime error paths.
- Gate AVIF/WebP native dependencies behind feature flags so the WASM build no longer imports unavailable C-backed components.
- Skip serializing transformed image bytes into WASM response JSON to avoid OOM on large outputs.
- Reject truncated JPEG input during lossless optimization.
- Stabilize HEAD and optimization-related tests after the runtime-target optimization work.
- Consolidate project documentation under
docs/and expand CLI examples for piping, stdin/stdout usage, and optimization workflows. - Deduplicate cloud integration test helpers and parameterize HEAD request tests with
rstest. - Update the OpenAPI and configuration docs to cover optimization controls,
/healthauthentication, and readiness hysteresis behavior.
- Lock-free syscall caching for health check endpoints (
disk_free_bytes,process_rss_bytes) with configurable TTL viaTRUSS_HEALTH_CACHE_TTL_SECS(default: 5s, range: 0–300). Eliminates redundant kernel context switches under high-frequency polling (#74). ServerConfig::with_health_cache_ttl_secs()builder method for programmatic TTL override.- Per-IP rate limiting with sharded buckets to reduce mutex contention (#127).
- Reverse proxy support: resolve real client IP behind trusted proxies for rate limiting via
TRUSS_TRUSTED_PROXIES(#117). #[must_use]annotations on key public types and functions (#130).#[non_exhaustive]on public enums for semver safety (#122).- Integration tests for HEAD requests (#123).
- Unit tests for routing, signing, and inspect modules (#124).
- Non-ASCII input tests for
Rgba8::from_hex(#131). - Security audit CI on pull requests (#128).
- PR template and updated stale bug report placeholder (#126).
- Block SSRF bypass via IPv4-compatible, 6to4, and Teredo IPv6 addresses (#118).
- Add element count and nesting depth limits to SVG sanitizer; fix CSS
url()search performance (#119). - Disambiguate NUL escape to avoid clippy
octal_escapeslint (#124). - Guard
Rgba8::from_hexagainst non-ASCII input (#131). - Add
#[serial]to cloud integration tests that useenv::set_var(#116). - Prevent flaky redirect-limit test on Windows (WSAECONNABORTED).
- Use acquire/release memory ordering in
HealthCachefor correctness on weakly-ordered architectures.
- Extract
collect_resource_checks()to deduplicate ~70 lines of identical logic betweenhandle_health()andhandle_health_ready(). - Introduce unified transform dispatch to eliminate SVG/raster routing duplication (#115).
- Remove ~2400 lines of duplicated code from
server/mod.rs(#114). - Replace relay imports with direct submodule references in
auth.rsandmetrics.rs. - Consolidate duplicated test helpers in CLI integration tests (#121).
- Replace manual JSON construction with
serde_jsonin inspect command (#129). - Throttle cache eviction scans and remove unnecessary
fsync(#120). - Hide
HealthCachefrom public API; expose TTL via builder method. - Document
TRUSS_HEALTH_CACHE_TTL_SECS,TRUSS_HEALTH_CACHE_MIN_FREE_BYTES, andTRUSS_HEALTH_MAX_MEMORY_BYTESinfrom_envrustdoc. - Update pipeline and Prometheus docs with crop/sharpen stages and watermark metric (#125).
- Bump clap 4.5→4.6, clap_complete 4.5→4.6, aws-sdk-s3 1.125→1.126.
- Fix aarch64 cross-compilation failure by using newer cross-rs base image with OpenSSL 3.x support.
- Hot-reload for transform presets via
TRUSS_PRESETS_FILEwith file-watching support. - Dynamic log level switching via
TRUSS_LOG_LEVELenv var andSIGUSR1signal. - Unit and integration tests for log level and preset hot-reload.
- Crop, rotate, fit, and inspect examples to README.
- Use
saturating_duration_sincein rate limiter for Windows compatibility. - Do not update
last_modifiedon preset parse failure to handle torn reads. - Use
wasm32-wasip1C target for wasi-sdk sysroot header resolution in Pages CI.
- Update
Cargo.tomlkeywords for better crates.io discoverability. - Comprehensive project improvements from multi-perspective review.
- Configurable max input pixel limit (
TRUSS_MAX_INPUT_PIXELS) with 422 response for oversized images. - Configurable max upload body size (
TRUSS_MAX_UPLOAD_BYTES) with 413 response for oversized uploads. - Optional Bearer token protection for
/metricsendpoint (TRUSS_METRICS_TOKEN) and disable flag (TRUSS_DISABLE_METRICS). - Configurable keep-alive max requests (
TRUSS_KEEP_ALIVE_MAX_REQUESTS). - Config validation subcommand (
truss validate) for CI/CD pre-flight checks. - Enhanced health checks: cache disk free space (
TRUSS_HEALTH_CACHE_MIN_FREE_BYTES), transform capacity, and process memory usage (TRUSS_HEALTH_MAX_MEMORY_BYTES). - Graceful shutdown with configurable drain period (
TRUSS_SHUTDOWN_DRAIN_SECS);/health/readyreturns 503 immediately on SIGTERM/SIGINT. - Custom response headers via
TRUSS_RESPONSE_HEADERSJSON env var with security-critical header rejection. - Gzip response compression for non-image responses with configurable level (
TRUSS_COMPRESSION_LEVEL) and disable flag (TRUSS_DISABLE_COMPRESSION). - Crop control in the WASM demo page UI.
- SVG and lossy WebP features enabled in the WASM demo build.
Box::leakper-request memory leak in custom response headers.- Reject security-critical headers (framing, hop-by-hop) in
TRUSS_RESPONSE_HEADERSat startup. - Merge
Varyheaders into a single line to avoid duplication. - Reduce worker drain timeout to 15 s for Kubernetes compatibility.
- Replace busy-wait accept loop with
poll(2)on Unix. - Windows graceful shutdown via SIGINT handler and draining check.
- Use
sigaction,AtomicI32,cast_mut, andO_NONBLOCKon write fd for signal safety. - Pixel-cap check moved before cache lookup to prevent unnecessary cache reads.
- Early-reject
/metricsbefore body read. - README:
--bearer-tokenCLI flag corrected toTRUSS_BEARER_TOKENenv var. - README:
POST /images:transformcurl example corrected toPOST /imagesfor multipart uploads.
- OpenAPI spec documents HEAD method support on all GET endpoints.
UnprocessableEntityresponse includes example in OpenAPI spec.maxInputPixelsmarked as required inHealthDiagnosticResponseschema.- Extracted
parse_env_u64_rangedhelper for env var parsing.
- aarch64 cross-compilation failure:
Cross.tomlpre-build now installslibssl-dev:arm64instead of the host-architecture package, soopenssl-sysfinds the correct headers.
- Release profile: enable thin LTO, single codegen unit, and binary stripping for smaller, faster binaries.
- Unified
stderr_writeusage across S3, GCS, and Azure backends to avoid Rust 2024ReentrantLockissues witheprintln!. - Cache key computation uses streaming
Sha256hasher and inline parameter builder, eliminating intermediate allocations and sort. - Watermark margin capped at 9999 with explicit validation on both JSON and multipart endpoints.
- Docker Compose healthcheck added for the
trussservice.
- Unit tests for
auth,http_parse,multipart,negotiate, andresponsemodules (314 new tests).
- HTTP response splitting (CRLF injection) via
X-Request-Idheader — CR, LF, and NUL bytes are now rejected. - Integer overflow in AVIF decode when frame dimensions exceed address space (
width * height * 4). - aarch64-unknown-linux-gnu release build failure caused by missing OpenSSL (
Cross.tomlpre-build step).
- Extracted
ServerConfigand related types into dedicatedconfig.rsmodule (~980 lines out ofmod.rs). - Deduplicated
read_remote_source_bytes/read_remote_watermark_bytesinto sharedfetch_remote_byteswithRemoteFetchPolicy. - Cleaned up unused imports in server module after config extraction.
- Integration tests: health endpoint 200, unknown path 404, CRLF injection prevention, missing Content-Type 415, invalid JSON body 400, missing source file 404.
- Characterization unit tests for
extract_request_id,ServerConfigdefaults/builder,route_request, andTransformSlotconcurrency.
- Explicit crop operation (
--crop x,y,w,hCLI flag,cropquery parameter, JSON/WASM adapters). Applied after auto-orient and rotation but before resize. Not supported for SVG inputs. - Signed URL key rotation via
TRUSS_SIGNING_KEYSJSON env var. Multiple key IDs can be active simultaneously for zero-downtime key rotation. - Server-side transform presets via
TRUSS_PRESETS/TRUSS_PRESETS_FILEenv vars withpresetquery parameter. - Sharpen filter (
--sharpenCLI flag,sharpenquery parameter, WASM adapter) using unsharp mask. Valid sigma range 0.1–100.0. - TIFF format support for input and output across CLI, HTTP server, and WASM.
- Watermark overlay support for signed public URLs (
watermarkUrl,watermarkPosition,watermarkOpacity,watermarkMarginquery params). sign_public_urland CLIsigncommand now accept watermark parameters.truss_watermark_transforms_totalPrometheus counter.watermarkfield in structured access log entries.MAX_WATERMARK_PIXELSlimit (4 MP) checked before watermark decode.- Request deadline (60 s) caps total outbound fetch time per request.
- Origin cache namespace separation (
src:/wm:) prevents cross-contamination. - WASM UI: watermark file type validation, 10 MB size limit, loading/clear feedback.
- Integration tests for orphaned watermark params, empty URL, SVG + watermark rejection, and redirect following.
- Prebuilt release binaries with checksums for Linux (x86_64, aarch64), macOS (x86_64, aarch64), and Windows (x86_64).
- Multi-arch container images (amd64, arm64) published to GHCR on release.
- Watermark fetch is deferred until concurrency slot is acquired (two-phase validation + fetch).
- SVG sources with watermark requests are rejected early with 400.
- Watermark fetch errors are sanitized; detailed errors logged server-side only.
- Cache key normalization uses parsed
Positionfor consistent hashing. - WASM UI: blur values below 0.1 treated as no blur; "Blur sigma" label simplified to "Blur".
- WASM UI:
.is-busyscoped to interactive elements instead of entire page. - WASM UI: download filename includes
-watermarkedsuffix when applicable. - Integration test workflow refactored from 4 duplicate jobs to a single matrix strategy.
Dockerfile.releaseusesCOPY --chownand explicitchmodfor binary permissions.parse_presets_from_envtreats emptyTRUSS_PRESETS_FILEas unset; JSON parse errors include source info.ServerConfig::PartialEqcompares preset contents instead of only length.
- Accessibility:
role="alert"on error box,:focus-withinon dropzones,nameattributes on watermark inputs,<noscript>fallback.
- Prometheus
/metricsendpoint with histograms (HTTP request duration, transform duration, storage duration) and error counters. - Prometheus metrics documentation (
docs/prometheus.md). - Dedicated 304 status counter for cache-validation traffic tracking.
/metricsendpoint no longer requires bearer token authentication for Prometheus scraper compatibility.- Cross-platform CI tests (macOS/Windows) now run on pull requests, not only on main pushes.
- Storage duration metrics now reflect actual source kind (filesystem/S3/GCS/Azure) instead of server config default.
- HTTP request duration histogram records on all exit paths including auth and body-read errors.
- Windows compilation error:
unsafe extern "system"block for Rust 2024 edition. - Cross-platform
stderr_writeusingGetStdHandleon Windows.
- S3-compatible object storage backend (
--features s3). - Google Cloud Storage backend (
--features gcs). - Azure Blob Storage backend (
--features azure). - SSRF validation for S3/GCS/Azure backend endpoint URLs.
- Signed URL support for S3/GCS/Azure source images.
- Structured JSON access logs with request ID (
X-Request-Id) and RAII concurrency guard. - Configurable server concurrency and deadline limits.
- Startup health check for storage backends (fail-fast).
- Configurable storage timeout via
TRUSS_STORAGE_TIMEOUT_SECS.
- Bump
quick-xml0.37→0.39 andresvg0.45→0.47. - Azure environment variable renamed from
TRUSS_AZURE_BUCKETtoTRUSS_AZURE_CONTAINER. - Use
subtle::ConstantTimeEqfor bearer token comparison. - Graceful shutdown with 30-second deadline.
- Backend 401 responses mapped to 502 Bad Gateway.
- Health check name unified to
storageBackendacross all backends. - Debug output masks
bearer_tokenandsigned_url_secretas[REDACTED].
- Access-log latency measured after header read and after response write.
- Per-server in-flight counter and pool sizing.
- Blur filter support (
blurquery parameter) for image transforms. - Watermark overlay support for image transforms.
- Sample image and template for documentation.
- Refactored README for clarity.
- Optimized GitHub Actions workflows for faster CI.
- Blur cache key precision issue.
- SVG blur/watermark rejection handling.
- Watermark pixel limit validation.
- Relaxed watermark size check to match position-based margin usage.
- Pass watermark to
transform_svgfor proper SVG input rejection. - Updated help text and OpenAPI spec for blur/watermark options.
- Update OpenAPI spec version from 0.2.0 to 0.3.0.
- HTTP/1.1 keep-alive and HEAD method support for CDN origin use.
- SVG rasterization and input-format preservation in Accept negotiation.
TRUSS_DISABLE_ACCEPT_NEGOTIATIONflag to avoid CDN cache key mismatches.- Configurable
Cache-Controlmax-age / stale-while-revalidate via environment variables. - Signed URL support for public GET endpoints (
GET /images/by-path,GET /images/by-url). - Download counter.
- Benchmark results to README.
- CDN architecture documentation and cache key configuration guidance.
- Mobile-friendly WASM demo with aspect ratio lock.
- Edge case tests.
truss help completionsandtruss help versionhelp topics.- Shell completions now expose implicit-convert (
-o,INPUT) and implicit-serve (--bind,--storage-root) arguments. - Commands table and shell completion setup guide in README.
- Exit code 5 (runtime error) documented in
--helpexit code listing.
- Refactored
server.rsinto 9 sub-modules for maintainability. - Normalize default fit/position in cache key for better hit rate.
- Authenticate private POST routes before reading request body.
- Use unique temp-file suffix for concurrent cache writes.
- Accept negotiation uses specificity to break ties (e.g.
image/pngoverimage/*).
- Validate multipart boundary suffix to prevent payload collision.
- Apply rotation in SVG rasterization path.
- Treat extensionless files as implicit
convertinput; useis_file()to exclude directories. - Reject Transfer-Encoding header to prevent request smuggling.
- Warn at startup when signed URL credentials are set without
TRUSS_PUBLIC_BASE_URL. - Accept
Authorization: bearer(case-insensitive scheme) per RFC 7235. - Preserve tail bytes for keep-alive connections instead of truncating.
- Reject header names with leading/trailing whitespace.
- Enforce
MAX_HEADER_BYTESat header terminator, not just buffer size. - Handle weak ETags (
W/"...") inIf-None-Matchcomparison. - Only treat 2xx HTTP responses as successful remote fetches.
- Block IPv4-mapped IPv6 addresses (
::ffff:127.0.0.1) in SSRF check. - Correct inverted
data:image/*allowlist in SVG sanitizer;data:image/pngetc. were incorrectly blocked whiledata:image/svg+xmlwas incorrectly allowed. - Clamp aspect-ratio synced dimensions to minimum of 1 in WASM demo.
- Reduce idle timeout for unconsumed fixture responses to speed up tests.
- Map
InvalidOptionsto exit code 1 (usage) andInvalidInputto exit code 3 (input); previously both mapped to exit code 2 (I/O). - Map output file write failure to exit code 2 (I/O) instead of exit code 5 (runtime).
- Use Drop guard for
TRANSFORMS_IN_FLIGHTin backpressure test to prevent flaky parallel test failures. - Update OpenAPI spec version from 0.1.0 to 0.2.0.
- Sanitize SVG
href/xlink:hrefwith allowlist approach; block embedded SVG payloads. - Validate remote fetch targets against SSRF policy before serving cached responses.
- Reject whitespace-padded HTTP header names to prevent proxy interpretation differences.
- Initial release.