diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f0b34..960f475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,45 @@ All notable changes to this project will be documented in this file. +## [1.6.0] - 2026-04-01 + +### Added + +- **wfe-server**: Headless workflow server (single binary) + - gRPC API with 13 RPCs: workflow CRUD, lifecycle streaming, log streaming, log search + - HTTP webhooks: GitHub and Gitea with HMAC-SHA256 verification, configurable triggers + - OIDC/JWT authentication with JWKS discovery and asymmetric algorithm allowlist + - Static bearer token auth with constant-time comparison + - Lifecycle event broadcasting via `WatchLifecycle` server-streaming RPC + - Real-time log streaming via `StreamLogs` with follow mode and history replay + - Full-text log search via OpenSearch with `SearchLogs` RPC + - Layered config: CLI flags > env vars > TOML file +- **wfe-server-protos**: gRPC service definitions (tonic 0.14, server + client stubs) +- **wfe-core**: `LogSink` trait for real-time step output streaming +- **wfe-core**: Lifecycle publisher wired into executor (StepStarted, StepCompleted, Error, Completed, Terminated) +- **wfe**: `use_log_sink()` on `WorkflowHostBuilder` +- **wfe-yaml**: Shell step streaming mode with `tokio::select!` interleaved stdout/stderr + +### Security + +- JWT algorithm confusion prevention: derive algorithm from JWK, reject symmetric algorithms +- Constant-time static token comparison via `subtle` crate +- OIDC issuer HTTPS validation to prevent SSRF +- Fail-closed on OIDC discovery failure (server won't start with broken auth) +- Authenticated generic webhook endpoint +- 2MB webhook payload size limit +- Config parse errors fail loudly (no silent fallback to open defaults) +- Blocked sensitive env var injection (PATH, LD_PRELOAD, etc.) from workflow data +- Security regression tests for all critical and high findings + +### Fixed + +- Shell step streaming path now respects `timeout_ms` with `child.kill()` on timeout +- LogSink properly threaded from WorkflowHostBuilder through executor to StepExecutionContext +- LogStore.with_search() wired in server main.rs for OpenSearch indexing +- OpenSearch `index_chunk` returns Err on HTTP failure instead of swallowing it +- Webhook publish failures return 500 instead of 200 + ## [1.5.0] - 2026-03-29 ### Added diff --git a/Cargo.toml b/Cargo.toml index 6565948..f0215b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["wfe-core", "wfe-sqlite", "wfe-postgres", "wfe-opensearch", "wfe-valk resolver = "2" [workspace.package] -version = "1.5.0" +version = "1.6.0" edition = "2024" license = "MIT" repository = "https://src.sunbeam.pt/studio/wfe" @@ -38,15 +38,15 @@ redis = { version = "0.27", features = ["tokio-comp", "connection-manager"] } opensearch = "2" # Internal crates -wfe-core = { version = "1.5.0", path = "wfe-core", registry = "sunbeam" } -wfe-sqlite = { version = "1.5.0", path = "wfe-sqlite", registry = "sunbeam" } -wfe-postgres = { version = "1.5.0", path = "wfe-postgres", registry = "sunbeam" } -wfe-opensearch = { version = "1.5.0", path = "wfe-opensearch", registry = "sunbeam" } -wfe-valkey = { version = "1.5.0", path = "wfe-valkey", registry = "sunbeam" } -wfe-yaml = { version = "1.5.0", path = "wfe-yaml", registry = "sunbeam" } -wfe-buildkit = { version = "1.5.0", path = "wfe-buildkit", registry = "sunbeam" } -wfe-containerd = { version = "1.5.0", path = "wfe-containerd", registry = "sunbeam" } -wfe-rustlang = { version = "1.5.0", path = "wfe-rustlang", registry = "sunbeam" } +wfe-core = { version = "1.6.0", path = "wfe-core", registry = "sunbeam" } +wfe-sqlite = { version = "1.6.0", path = "wfe-sqlite", registry = "sunbeam" } +wfe-postgres = { version = "1.6.0", path = "wfe-postgres", registry = "sunbeam" } +wfe-opensearch = { version = "1.6.0", path = "wfe-opensearch", registry = "sunbeam" } +wfe-valkey = { version = "1.6.0", path = "wfe-valkey", registry = "sunbeam" } +wfe-yaml = { version = "1.6.0", path = "wfe-yaml", registry = "sunbeam" } +wfe-buildkit = { version = "1.6.0", path = "wfe-buildkit", registry = "sunbeam" } +wfe-containerd = { version = "1.6.0", path = "wfe-containerd", registry = "sunbeam" } +wfe-rustlang = { version = "1.6.0", path = "wfe-rustlang", registry = "sunbeam" } # YAML serde_yaml = "0.9" diff --git a/wfe-buildkit/Cargo.toml b/wfe-buildkit/Cargo.toml index 9b67e20..6c4b246 100644 --- a/wfe-buildkit/Cargo.toml +++ b/wfe-buildkit/Cargo.toml @@ -16,7 +16,7 @@ async-trait = { workspace = true } tracing = { workspace = true } thiserror = { workspace = true } regex = { workspace = true } -wfe-buildkit-protos = { version = "1.5.0", path = "../wfe-buildkit-protos", registry = "sunbeam" } +wfe-buildkit-protos = { version = "1.6.0", path = "../wfe-buildkit-protos", registry = "sunbeam" } tonic = "0.14" tower = { version = "0.4", features = ["util"] } hyper-util = { version = "0.1", features = ["tokio"] } diff --git a/wfe-containerd/Cargo.toml b/wfe-containerd/Cargo.toml index c8664d6..4bfa8ee 100644 --- a/wfe-containerd/Cargo.toml +++ b/wfe-containerd/Cargo.toml @@ -9,7 +9,7 @@ description = "containerd container runner executor for WFE" [dependencies] wfe-core = { workspace = true } -wfe-containerd-protos = { version = "1.5.0", path = "../wfe-containerd-protos", registry = "sunbeam" } +wfe-containerd-protos = { version = "1.6.0", path = "../wfe-containerd-protos", registry = "sunbeam" } tokio = { workspace = true } serde = { workspace = true } serde_json = { workspace = true }