detached 33a243c

exec.proto RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3// Internal wire format between the host process of ermite-runner and the
4// executor running inside a sandbox (vsock in a micro-VM, Unix socket in a
5// container). Frames are length-prefixed on the stream (see frame.go); this file
6// defines the payload. It is internal to ermite-runner: no compatibility is
7// promised between runner versions, which is safe because the host attaches its
8// own executable to every sandbox.
9
10syntax = "proto3";
11
12package ermite.runner.exec.v1;
13
14option go_package = "bnema.dev/ermite-runner/internal/execstream/execpb";
15
16// Frame is the only message on the stream.
17message Frame {
18  oneof body {
19    Hello hello = 1;   // executor -> host, first frame
20    Run run = 2;       // host -> executor, after Hello
21    Output output = 3; // executor -> host
22    Exit exit = 4;     // executor -> host, last frame
23    Cancel cancel = 5; // host -> executor
24    StepStarted step_started = 6;     // executor -> host
25    StepCompleted step_completed = 7; // executor -> host
26    Log log = 8;                      // executor -> host
27    JobResult job_result = 9;         // executor -> host, before Exit
28    StepAnnotations step_annotations = 10; // executor -> host, before the StepCompleted of the step
29    StepSummary step_summary = 11;         // executor -> host, before the StepCompleted of the step
30    ResolveRequest resolve_request = 12;   // executor -> host
31    ResolveResponse resolve_response = 13; // host -> executor, answers a ResolveRequest
32    NamedValue secret = 14; // host -> executor, one per secret, before Run
33    NamedValue var = 15;    // host -> executor, one per variable, before Run
34  }
35}
36
37// NamedValue is one secret (Job.secrets) or one variable (Job.vars) of the job.
38// They travel in frames of their own, before Run, rather than in JobSpec: a
39// frame is at most 2 MiB (execstream.MaxFrame) and ermite allows many secrets of
40// 48 KiB, so a map in Run could not carry them. The executor keeps them until
41// Run arrives. Secrets are never logged nor written to disk.
42message NamedValue {
43  string name = 1;
44  string value = 2;
45}
46
47message Hello {
48  string version = 1;  // runner version of the executor
49  string sandbox = 2;  // "vm" or "container"
50  string hostname = 3;
51  map<string, int64> boot_ms = 4;
52}
53
54// Run asks the executor to run a script or a job. Without job it is the stub
55// executor of sandbox-check: the script is run with `sh -c`; an empty script
56// means the built-in diagnostics script. With job the executor runs the job
57// like a GitHub Actions runner and reports it with StepStarted, Log,
58// StepCompleted and JobResult frames, then Exit.
59message Run {
60  string script = 1;
61  map<string, string> env = 2;
62  JobSpec job = 3;
63}
64
65// JobSpec is the job to run: the fields of the job that ermite handed to the
66// host process, minus the tokens (the sandbox never sees them).
67message JobSpec {
68  string workflow_path = 1;
69  string workflow_yaml = 2;
70  string job_key = 3;
71  string matrix = 4;   // JSON object
72  string contexts = 5; // JSON object
73  string repo = 6;     // repository name
74  int32 timeout_minutes = 7;
75  string runner_name = 8;
76  string runner_version = 9;
77  // runner_environment is the runner.environment value ("github-hosted" or "self-hosted").
78  string runner_environment = 10;
79  bool debug = 11; // ACTIONS_STEP_DEBUG
80  // deadline_ms is what is left of the job timeout when the host sends this
81  // Run, in milliseconds: the timeout counts from the moment the host received
82  // the job (runner.proto: Job.timeout_minutes), not from the start of the
83  // executor, and booting the sandbox takes time. 0 means "use
84  // timeout_minutes from now".
85  int64 deadline_ms = 12;
86  // send_annotations and send_summaries say that the server keeps annotations
87  // (feature ci.annotations) and step summaries (ci.summaries). The executor
88  // sends StepAnnotations and StepSummary frames only when they are set.
89  bool send_annotations = 13;
90  bool send_summaries = 14;
91  // cache_port and cache_token, when set, are the runner's cache service for
92  // this job. The service is not on the network: the executor starts a relay
93  // on the sandbox's own loopback, 127.0.0.1:<cache_port>, that carries each
94  // connection over the host channel (a vsock port, or a Unix socket next to
95  // the executor's) to the service. The executor gives
96  // ACTIONS_CACHE_URL=http://127.0.0.1:<port>/ and the token as
97  // ACTIONS_RUNTIME_TOKEN to node and docker actions only, as the official
98  // runner does, and masks the token. The token is not an ermite credential: it
99  // is a JWT (HS256) that only the runner's runtime services accept, scoped to
100  // this job's repository and refs (and its run, see results).
101  uint32 cache_port = 15;
102  string cache_token = 16;
103  // Job.secrets and Job.vars are not here: they come in NamedValue frames
104  // before Run (see NamedValue). The executor takes the vars of those frames
105  // for the "vars" context when contexts has none.
106  reserved 17, 18;
107  reserved "secrets", "vars";
108  // secrets_withheld is set by the host when the server sends Job.trusted and
109  // the job is not trusted (feature ci.secrets): "Set up job" then says that
110  // secrets are not available. Never set for servers without the feature, for
111  // which an absent Job.trusted only means "not sent".
112  bool secrets_withheld = 19;
113  // id_token_url and id_token_request_token are Job.id_token_url and
114  // Job.id_token_request_token: the OIDC token endpoint of the server, its
115  // origin rewritten as for github.server_url, and the bearer for it. The
116  // executor gives them as ACTIONS_ID_TOKEN_REQUEST_URL and
117  // ACTIONS_ID_TOKEN_REQUEST_TOKEN to run steps, node actions and docker
118  // actions (ScriptHandler.cs:315-319, NodeScriptActionHandler.cs:66-70,
119  // ContainerActionHandler.cs:232-236), and masks the token before anything
120  // runs. Both are set or neither. (21 and 22 are taken by the artifacts
121  // branch.)
122  string id_token_url = 23;
123  string id_token_request_token = 24;
124  // token_permissions are the effective permissions of the job's GITHUB_TOKEN
125  // as the server sent them (Job.permissions, feature ci.secrets): "Set up job"
126  // prints them instead of working them out from the workflow. Unset when the
127  // server sent none (an older server): the executor then reads them from the
128  // workflow.
129  TokenPermissions token_permissions = 20;
130  // cache_mode is ACTIONS_CACHE_MODE of the node and docker actions: "write"
131  // when the job's cache scope has a write ref, "read" when it has none. Unset
132  // without a cache service, and unset when the channel serves the results
133  // service only (results set, no cache scope): no ACTIONS_CACHE_URL then.
134  string cache_mode = 21;
135  // results says that the service behind cache_port also serves artifacts
136  // (Twirp github.actions.results.api.v1.ArtifactService and its blobs) and
137  // that cache_token carries the job's Actions.Results scope. The executor
138  // then gives node and docker actions ACTIONS_RESULTS_URL (the same origin as
139  // ACTIONS_CACHE_URL) and sets GITHUB_SERVER_URL to a *.ghe.localhost host in
140  // the process of the node steps of the artifact actions only (README,
141  // "Artifacts"). Set only when the server has the feature ci.artifacts.
142  bool results = 22;
143}
144
145// TokenPermissions maps a permission key ("contents", "pull-requests", ...) to
146// "read", "write" or "none"; a key that is absent is none.
147message TokenPermissions {
148  map<string, string> levels = 1;
149}
150
151enum StreamKind {
152  STREAM_KIND_UNSPECIFIED = 0;
153  STREAM_KIND_STDOUT = 1;
154  STREAM_KIND_STDERR = 2;
155}
156
157message Output {
158  StreamKind stream = 1;
159  bytes data = 2;
160  int64 unix_nano = 3;
161}
162
163message Exit {
164  int32 code = 1;
165  string error = 2; // set when the executor failed to run the script at all
166}
167
168// Cancel asks the executor to stop the running script. The executor escalates
169// like the official runner: SIGINT to the script's process group at once,
170// SIGTERM 7.5 s later, SIGKILL 2.5 s after that.
171message Cancel {
172  // reason is for the job log and diagnostics ("cancelled by the user",
173  // "job timeout", ...); it never changes the behaviour.
174  string reason = 1;
175  // kind tells the job executor how the job ends: cancelled, timed out, or
176  // cancelled because the runner shuts down. The stub executor ignores it.
177  CancelKind kind = 2;
178}
179
180enum CancelKind {
181  CANCEL_KIND_UNSPECIFIED = 0; // same as USER
182  CANCEL_KIND_USER = 1;
183  CANCEL_KIND_TIMEOUT = 2;
184  CANCEL_KIND_SHUTDOWN = 3;
185}
186
187// Steps are numbered like GitHub's log: "Set up job" is 1, the steps of the
188// workflow follow, "Complete job" is last.
189message StepStarted {
190  int32 number = 1;
191  string name = 2;
192  int64 unix_nano = 3;
193}
194
195message StepCompleted {
196  int32 number = 1;
197  string name = 2;
198  StepConclusion conclusion = 3;
199  int64 unix_nano = 4;
200  // outcome is steps.<id>.outcome: the result before continue-on-error. It
201  // differs from conclusion only for a failed step with continue-on-error.
202  // UNSPECIFIED means the same as conclusion.
203  StepConclusion outcome = 5;
204}
205
206enum AnnotationLevel {
207  ANNOTATION_LEVEL_UNSPECIFIED = 0;
208  ANNOTATION_LEVEL_NOTICE = 1;
209  ANNOTATION_LEVEL_WARNING = 2;
210  ANNOTATION_LEVEL_FAILURE = 3;
211}
212
213// Annotation is one ::notice, ::warning or ::error (or a problem matcher
214// match), masked. The host validates every field again before it sends them.
215message Annotation {
216  AnnotationLevel level = 1;
217  string title = 2;
218  string message = 3;
219  string file = 4; // relative to the repository when the file is in it
220  int32 start_line = 5;
221  int32 end_line = 6;
222  int32 start_column = 7;
223  int32 end_column = 8;
224}
225
226// StepAnnotations is the complete list of the annotations of a step (the ones
227// the runner keeps: at most 10 per level), replacing any earlier list of that
228// step. Annotations of the steps inside a composite action are those of the
229// step of the workflow that uses it.
230message StepAnnotations {
231  int32 step = 1;
232  repeated Annotation annotations = 2;
233}
234
235// StepSummary is the masked content of GITHUB_STEP_SUMMARY after a step, at
236// most 1 MiB.
237message StepSummary {
238  int32 step = 1;
239  string markdown = 2;
240}
241
242enum StepConclusion {
243  STEP_CONCLUSION_UNSPECIFIED = 0;
244  STEP_CONCLUSION_SUCCESS = 1;
245  STEP_CONCLUSION_FAILURE = 2;
246  STEP_CONCLUSION_CANCELLED = 3;
247  STEP_CONCLUSION_SKIPPED = 4;
248  STEP_CONCLUSION_TIMED_OUT = 5; // jobs only
249}
250
251// Log is one line of the job log, without terminator, valid UTF-8. A line of
252// more than 64 KiB is cut by the executor into pieces at character boundaries;
253// every piece but the first has continued set (the AppendLog rule).
254message Log {
255  int32 step = 1;
256  int64 unix_nano = 2;
257  string text = 3;
258  bool continued = 4;
259}
260
261// JobResult is the outcome of the job; Exit follows.
262message JobResult {
263  StepConclusion conclusion = 1;
264  map<string, string> outputs = 2;
265  string error = 3;
266  bool runner_shutdown = 4;
267}
268
269// ResolveRequest asks the host to resolve actions with RunnerService.
270// ResolveActions: the job token stays in the host, so the executor cannot call
271// it. The executor sends one per level of composite actions (the runner's own
272// "one more round per level") and waits for the ResolveResponse with the same id.
273message ResolveRequest {
274  int64 id = 1;
275  repeated string uses = 2; // "owner/repo[/path]@ref", at most 100
276}
277
278// ResolveResponse answers a ResolveRequest. error is set when the call itself
279// failed (the executor fails the job); actions has one entry per uses otherwise.
280message ResolveResponse {
281  int64 id = 1;
282  string error = 2;
283  repeated ResolvedAction actions = 3;
284}
285
286// ResolvedAction mirrors ermite.ResolvedAction (the token is a secret: the
287// executor masks it).
288message ResolvedAction {
289  string ref = 1;
290  string name_with_owner = 2;
291  string path = 3;
292  string resolved_sha = 4;
293  string tarball_url = 5;
294  string token = 6;
295  string source = 7;
296  string error = 8;
297  // auth_origin (scheme://host[:port], as the sandbox reaches it) is the only
298  // origin the token may be sent to; empty means the token is never sent. The
299  // host sets it for archives served by the ermite server, from its own
300  // configuration, never from the URL alone.
301  string auth_origin = 9;
302}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 11

↑↓ moveenter openesc close