Files
client/interface/proto/forest/v1/runner.proto
2026-03-15 22:38:42 +01:00

228 lines
7.2 KiB
Protocol Buffer

syntax = "proto3";
package forest.v1;
// RunnerService is exposed by the forest-server. Runners (workers) call these
// RPCs to register for work, fetch release artifacts, stream logs, and report
// completion. Authentication for all post-assignment RPCs uses a release-scoped
// opaque token rather than the regular JWT flow.
service RunnerService {
// Bidirectional stream used for runner registration and work assignment.
// The runner sends a RunnerRegister as its first message, then periodic
// RunnerHeartbeat messages. The server responds with a RegisterAck followed
// by WorkAssignment messages when releases matching the runner's capabilities
// become available.
rpc RegisterRunner(stream RunnerMessage) returns (stream ServerMessage);
// Fetch the artifact files for a release assigned to this runner.
// Scoped by the release_token received in the WorkAssignment.
rpc GetReleaseFiles(GetReleaseFilesRequest) returns (stream ReleaseFile);
// Stream log lines back to the server for real-time display.
// Each message must include the release_token for authentication.
rpc PushLogs(stream PushLogRequest) returns (PushLogResponse);
// Fetch the original spec files for a release.
// Scoped by the release_token received in the WorkAssignment.
rpc GetSpecFiles(GetSpecFilesRequest) returns (stream ReleaseFile);
// Fetch the annotation (metadata context) for a release.
rpc GetReleaseAnnotation(GetReleaseAnnotationRequest) returns (ReleaseAnnotationResponse);
// Fetch project info (organisation + project name) for a release.
rpc GetProjectInfo(GetProjectInfoRequest) returns (ProjectInfoResponse);
// Report the final outcome of a release (success or failure).
// This commits the release status and revokes the token.
rpc CompleteRelease(CompleteReleaseRequest) returns (CompleteReleaseResponse);
}
// ============================================================================
// Connect stream: Runner → Server
// ============================================================================
message RunnerMessage {
oneof message {
RunnerRegister register = 1;
RunnerHeartbeat heartbeat = 2;
WorkAck work_ack = 3;
}
}
// First message a runner sends on the Connect stream.
message RunnerRegister {
// Runner-chosen unique identifier. If empty, the server assigns one.
string runner_id = 1;
// Destination types this runner can handle.
repeated DestinationCapability capabilities = 2;
// Maximum number of simultaneous releases this runner can process.
int32 max_concurrent = 3;
}
// Describes a destination type the runner supports.
message DestinationCapability {
string organisation = 1;
string name = 2;
uint64 version = 3;
}
// Periodic keepalive sent by the runner (recommended every 10s).
message RunnerHeartbeat {
// Current number of in-progress releases on this runner.
int32 active_releases = 1;
}
// Runner's response to a WorkAssignment.
message WorkAck {
string release_token = 1;
// false = runner rejects the work (e.g., overloaded). The server will
// reassign or fall back to in-process execution.
bool accepted = 2;
}
// ============================================================================
// Connect stream: Server → Runner
// ============================================================================
message ServerMessage {
oneof message {
RegisterAck register_ack = 1;
WorkAssignment work_assignment = 2;
}
}
// Server response to RunnerRegister.
message RegisterAck {
// Server-confirmed (or server-assigned) runner ID.
string runner_id = 1;
bool accepted = 2;
string reason = 3;
}
// Execution mode for a work assignment.
enum ReleaseMode {
RELEASE_MODE_UNSPECIFIED = 0;
// Normal deployment execution.
RELEASE_MODE_DEPLOY = 1;
// Dry-run / plan only (e.g. terraform plan). Runner should capture
// plan output and include it in CompleteRelease.plan_output.
RELEASE_MODE_PLAN = 2;
}
// Work assignment pushed to a runner when a matching release is available.
message WorkAssignment {
// Scoped opaque auth token. Use this for GetReleaseFiles, PushLogs,
// and CompleteRelease. The token restricts access to only the data
// associated with this specific release.
string release_token = 1;
string release_id = 2;
string release_intent_id = 3;
string artifact_id = 4;
string destination_id = 5;
// Full destination configuration including metadata.
DestinationInfo destination = 6;
// Execution mode. Defaults to DEPLOY if unset.
ReleaseMode mode = 7;
}
// Destination configuration sent with the work assignment.
message DestinationInfo {
string name = 1;
string environment = 2;
map<string, string> metadata = 3;
DestinationCapability type = 4;
string organisation = 5;
}
// ============================================================================
// GetReleaseFiles
// ============================================================================
message GetReleaseFilesRequest {
string release_token = 1;
}
message ReleaseFile {
string file_name = 1;
string file_content = 2;
}
// ============================================================================
// GetSpecFiles
// ============================================================================
message GetSpecFilesRequest {
string release_token = 1;
}
// ============================================================================
// GetReleaseAnnotation
// ============================================================================
message GetReleaseAnnotationRequest {
string release_token = 1;
}
message ReleaseAnnotationResponse {
string slug = 1;
string source_username = 2;
string source_email = 3;
string context_title = 4;
string context_description = 5;
string context_web = 6;
string reference_version = 7;
string reference_commit_sha = 8;
string reference_commit_branch = 9;
string reference_commit_message = 10;
string created_at = 11;
}
// ============================================================================
// GetProjectInfo
// ============================================================================
message GetProjectInfoRequest {
string release_token = 1;
}
message ProjectInfoResponse {
string organisation = 1;
string project = 2;
}
// ============================================================================
// PushLogs
// ============================================================================
message PushLogRequest {
string release_token = 1;
// "stdout" or "stderr"
string channel = 2;
string line = 3;
uint64 timestamp = 4;
}
message PushLogResponse {}
// ============================================================================
// CompleteRelease
// ============================================================================
message CompleteReleaseRequest {
string release_token = 1;
ReleaseOutcome outcome = 2;
// Error description when outcome is FAILURE.
string error_message = 3;
// Plan output text when mode was "plan" and outcome is SUCCESS.
// Stored in release_states.plan_output for UI review.
optional string plan_output = 4;
}
enum ReleaseOutcome {
RELEASE_OUTCOME_UNSPECIFIED = 0;
RELEASE_OUTCOME_SUCCESS = 1;
RELEASE_OUTCOME_FAILURE = 2;
}
message CompleteReleaseResponse {}