feat(wfe-server): gRPC reflection, auto-generated schema endpoints, Dockerfile

- 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
This commit is contained in:
2026-04-06 23:47:42 +01:00
parent 6f4700ef89
commit 1b873d93f3
12 changed files with 283 additions and 63 deletions

View File

@@ -14,9 +14,9 @@ path = "src/main.rs"
[dependencies]
# Internal
wfe-core = { workspace = true, features = ["test-support"] }
wfe = { version = "1.8.0", path = "../wfe", registry = "sunbeam" }
wfe-yaml = { version = "1.8.0", path = "../wfe-yaml", registry = "sunbeam", features = ["rustlang", "buildkit", "containerd"] }
wfe-server-protos = { version = "1.8.0", path = "../wfe-server-protos", registry = "sunbeam" }
wfe = { version = "1.8.1", path = "../wfe", registry = "sunbeam" }
wfe-yaml = { version = "1.8.1", path = "../wfe-yaml", registry = "sunbeam", features = ["rustlang", "buildkit", "containerd"] }
wfe-server-protos = { version = "1.8.1", path = "../wfe-server-protos", registry = "sunbeam" }
wfe-sqlite = { workspace = true }
wfe-postgres = { workspace = true }
wfe-valkey = { workspace = true }
@@ -26,6 +26,7 @@ opensearch = { workspace = true }
# gRPC
tonic = "0.14"
tonic-health = "0.14"
tonic-reflection = "0.14"
prost-types = "0.14"
# HTTP (webhooks)

View File

@@ -172,6 +172,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.route("/webhooks/github", axum::routing::post(webhook::handle_github_webhook))
.route("/webhooks/gitea", axum::routing::post(webhook::handle_gitea_webhook))
.route("/healthz", axum::routing::get(webhook::health_check))
.route("/schema/workflow.proto", axum::routing::get(serve_proto_schema))
.route("/schema/workflow.json", axum::routing::get(serve_json_schema))
.route("/schema/workflow.yaml", axum::routing::get(serve_yaml_example))
.layer(axum::extract::DefaultBodyLimit::max(2 * 1024 * 1024))
.with_state(webhook_state);
@@ -180,8 +183,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let http_addr = config.http_addr;
tracing::info!(%grpc_addr, %http_addr, "servers listening");
let reflection_service = tonic_reflection::server::Builder::configure()
.register_encoded_file_descriptor_set(wfe_server_protos::FILE_DESCRIPTOR_SET)
.build_v1()
.expect("failed to build reflection service");
let grpc_server = Server::builder()
.add_service(health_service)
.add_service(reflection_service)
.add_service(WfeServer::with_interceptor(wfe_service, auth_interceptor))
.serve(grpc_addr);
@@ -248,3 +257,25 @@ async fn load_yaml_definitions(host: &wfe::WorkflowHost, dir: &std::path::Path)
}
}
}
/// Serve the raw .proto schema file.
async fn serve_proto_schema() -> impl axum::response::IntoResponse {
(
[(axum::http::header::CONTENT_TYPE, "text/plain; charset=utf-8")],
include_str!("../../wfe-server-protos/proto/wfe/v1/wfe.proto"),
)
}
/// Serve the auto-generated JSON Schema for workflow YAML definitions.
async fn serve_json_schema() -> impl axum::response::IntoResponse {
let schema = wfe_yaml::schema::generate_json_schema();
axum::Json(schema)
}
/// Serve the auto-generated JSON Schema as YAML.
async fn serve_yaml_example() -> impl axum::response::IntoResponse {
(
[(axum::http::header::CONTENT_TYPE, "text/yaml; charset=utf-8")],
wfe_yaml::schema::generate_yaml_schema(),
)
}