Three related host.rs changes that together make the 1.9 name support
end-to-end functional.
1. `WorkflowHost::start()` now calls `persistence.ensure_store_exists()`.
The method existed on the trait and was implemented by every
provider but nothing ever invoked it, so the Postgres/SQLite schema
was never auto-created on startup — deployments failed on first
persist with `relation "wfc.workflows" does not exist`.
2. New `start_workflow_with_name` entry point accepting an optional
caller-supplied name override. The normal `start_workflow` is now a
thin wrapper that passes `None` (auto-assign). The default path
calls `next_definition_sequence(definition_id)` and formats the
result as `{definition_id}-{N}` before persisting. Sub-workflow
children also get auto-assigned names via HostContextImpl.
3. `get_workflow`/`suspend_workflow`/`resume_workflow`/
`terminate_workflow` now accept either a UUID or a human-friendly
name. `get_workflow` tries the UUID index first, then falls back to
name lookup. A new `resolve_workflow_id` helper returns the
canonical UUID so the gRPC log/lifecycle streams (which are keyed
by UUID internally) can translate before subscribing.
Land the `name` field and `next_definition_sequence` counter in the
two real persistence backends. Both providers:
* Add `name TEXT NOT NULL UNIQUE` to the `workflows` table.
* Add a `definition_sequences` table (`definition_id, next_num`) with
an atomic UPSERT + RETURNING to give the host a race-free monotonic
counter for `{def_id}-{N}` name generation.
* INSERT/UPDATE queries now include `name`; SELECT row parsers hydrate
it back onto `WorkflowInstance`.
* New `get_workflow_instance_by_name` method for name-based lookups
used by grpc handlers.
Postgres includes a DO-block migration that back-fills `name` from
`id` on pre-existing deployments so the NOT NULL + UNIQUE invariant
holds retroactively; callers can overwrite with a real name on the
next persist.
Add a `name` field to both `WorkflowDefinition` (optional display name
declared in YAML, e.g. "Continuous Integration") and `WorkflowInstance`
(required, unique alongside the UUID primary key). Instance names are
auto-assigned as `{definition_id}-{N}` via a per-definition monotonic
counter so the 42nd run of `ci` becomes `ci-42`.
Persistence trait gains two methods:
* `get_workflow_instance_by_name` — name-based lookup for Get/Cancel/
Suspend/Resume/Watch/Logs RPCs so callers can address instances
interchangeably as either UUID or human name.
* `next_definition_sequence` — atomic per-definition counter used by
the host at start time to allocate the next N.
This commit wires the in-memory test provider and touches the deno
bridge test helper; the real postgres/sqlite impls follow in the next
commit. UUIDs remain the primary key throughout — names are a second
unique index, never a replacement.
Kubernetes step jobs with a `run:` block were invoked via
`/bin/sh -c <script>`. On debian-family base images that resolves to
dash, which rejects `set -o pipefail` ("Illegal option") and other
bashisms (arrays, process substitution, `{1..10}`). The first line of
nearly every real CI script relies on `set -euo pipefail`, so the
steps were failing with exit code 2 before running a single command.
Switch to `/bin/bash -c` so `run:` scripts can rely on the bash
feature set. Containers that lack bash should use the explicit
`command:` form instead.
Pure formatting pass from `cargo fmt --all`. No logic changes. Separating
this out so the 1.9 release feature commits that follow show only their
intentional edits.
SubWorkflowStep was hard-coding `inputs: serde_json::Value::Null` from
the YAML compiler, so every `type: workflow` step kicked off a child
instance with an empty data object. Scripts in child workflows then
saw empty `$REPO_URL`, `$COMMIT_SHA`, etc. and failed immediately.
Now: when no explicit inputs are set, the child inherits the parent
workflow's data (when it's an object). Scripts in child workflows can
reference the same top-level inputs the parent was started with without
every `type: workflow` step needing to re-declare them.
Local dev runs with the SQLite backend leave `wfe.db{,-shm,-wal}` files
in the repo root, and `workflows.schema.yaml` is a generated artifact
we prefer to fetch from the running server's `/schema/workflow.yaml`
endpoint rather than checking in.
- tonic-reflection for gRPC service discovery
- /schema/workflow.json (JSON Schema from schemars derives)
- /schema/workflow.yaml (same schema in YAML)
- /schema/workflow.proto (raw proto file)
- Multi-stage alpine Dockerfile with all executor features
- Comprehensive configuration reference (wfe-server/README.md)
- Release script (scripts/release.sh)
- Bumped to 1.8.1
Sets step_name on execution pointers when advancing to next steps,
compensation steps, and parallel branch children so that runtime
consumers can identify steps by name without lookup.
Adds WorkflowBuilder::add_step_typed<S>() for adding named, configured
steps directly — needed for parallel branch closures in the CLI.
Makes wire_outcome() public so callers can wire custom step graphs.
Adds StepBuilder::config() to attach arbitrary JSON configuration to
individual steps, readable at runtime via context.step.step_config.
Bumps version to 1.6.1.
Add wfe-server-protos and wfe-server to workspace members.
Update StepExecutionContext constructions with log_sink: None
in buildkit and containerd test files.
Shell step streaming: when LogSink is present, uses cmd.spawn() with
tokio::select! to interleave stdout/stderr line-by-line. Respects
timeout_ms with child.kill() on timeout. Falls back to buffered mode
when no LogSink.
Security: block sensitive env var overrides (PATH, LD_PRELOAD, etc.)
from workflow data injection. Proper error handling for pipe capture.
4 LogSink regression tests + 2 env var security regression tests.
LogSink trait for real-time step output streaming. Added to
StepExecutionContext as optional field (backward compatible).
Threaded through WorkflowExecutor and WorkflowHostBuilder.
Wired LifecyclePublisher.publish() into executor at 5 points:
StepStarted, StepCompleted, Error, Completed, Terminated.
Also added lifecycle events to host start/suspend/resume/terminate.
Full changelog covering v1.0.0, v1.4.0, and v1.5.0 releases.
Also fix containerd integration test default address to handle
Lima socket forwarding gracefully.
879 tests passing. 88.8% coverage on wfe-rustlang.
Lima wfe-test VM: Alpine with system containerd + BuildKit from apk,
TCP socat proxy for reliable gRPC transport, probes with sudo for
socket permission fixes. 2 core / 4GB / 20GB.
CI pipeline: add wfe-rustlang to feature-tests, package, and publish
steps. Container tests use TCP proxy (http://127.0.0.1:2500) instead
of Unix socket forwarding. Containerd tests set WFE_IO_DIR for shared
filesystem support.
Add rustlang feature flag to wfe-yaml with support for all cargo and
rustup step types (15 total), including cargo-doc-mdx.
Schema additions: output_dir, package, features, all_features,
no_default_features, release, profile, toolchain, extra_args,
components, targets, default_toolchain fields on StepConfig.
Integration tests for compiling all step types from YAML, and
containerd-based end-to-end tests for running Rust toolchain
inside containers from bare Debian images.
Four bugs fixed in the containerd gRPC executor:
- Snapshot parent: resolve image chain ID from content store instead of
using empty parent, which created rootless containers with no binaries
- I/O capture: replace FIFOs with regular files for stdout/stderr since
FIFOs don't work across virtiofs filesystem boundaries (Lima VMs)
- Capabilities: grant Docker-default capability set (SETUID, SETGID,
CHOWN, etc.) when running as root so apt-get and similar tools work
- Shell path: use /bin/sh instead of sh in process args since container
PATH may be empty
Also adds WFE_IO_DIR env var for shared filesystem support with remote
daemons, and documents the remote daemon setup in lib.rs.