Skip to content

v1.21.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 11:55
· 121 commits to main since this release
1c6a09a

Highlights

  • grpc calls methods with the Connect protocol, and calls streaming methods.
  • grpc keeps to --read-only and --allow-host.
  • Each action declares the kinds of guard it keeps to. An external action does so in action.yml, which also takes params for probe check.
  • The external actions graphql and jmap have reference pages.
  • For library users: actionrpc.Guard.Keeping is replaced by Keeps.

gRPC over the Connect protocol

The grpc action can now call a method with the Connect protocol instead of gRPC. The call is a POST over HTTP, so it passes an HTTP/1.1 proxy or load balancer, as the calls of a connect-web client in a browser do.

- name: Get a user
  uses: grpc
  with:
    protocol: connect
    addr: https://api.example.com/rpc
    service: users.v1.UserService
    method: GetUser
    body:
      id: "123"
  test: res.status_code == "OK" && res.body.user.name != ""
  • addr is the URL the service is served under; the call goes to <addr>/<service>/<method>. A host and port without a scheme is taken as http, or https with tls: true.
  • codec is json (the default) or proto. Without proto files, a JSON body is sent as written and service must be the full name; codec: proto needs proto.
  • metadata is sent as headers, and timeout is also sent as Connect-Timeout-Ms. Redirects are not followed.
  • res has the same fields as for a gRPC call. A Connect error gives its gRPC code, such as NOT_FOUND; a response without one, such as a proxy's 502 page, gives the code implied by the HTTP status, such as UNAVAILABLE, as a result rather than an action error.
  • Server reflection is not used with protocol: connect.

See Connect Protocol.

gRPC streaming methods

The grpc action now calls methods that stream their requests or their responses, by gRPC and by protocol: connect, with the same parameters as a method that does not stream. The call sends every request, closes its side, and then reads the responses.

- name: Watch users
  uses: grpc
  with:
    method: WatchUsers
    body:
      filter: active
    max_messages: 3
  test: res.status_code == "" && len(res.messages) == 3 && !res.complete

- name: Import users
  uses: grpc
  with:
    method: ImportUsers
    body:
      - name: Ada
      - name: Grace
  test: res.status_code == "OK" && res.body.imported == 2
  • A list in body is the messages of a stream of requests, in order. One object is the only message, and [] sends none. A list sent to a method that does not stream its requests is an error.
  • The responses of a stream are in res.messages, the last one also in res.body. res.complete is true when the server ended the stream.
  • max_messages stops reading after that many responses. The server has then sent no status, so res.status_code is empty and res.complete is false.
  • A stream that breaks off after some responses returns them with the status it ended with, such as DEADLINE_EXCEEDED.
  • A method that streams both ways is refused before anything is sent.
  • With protocol: connect, a streaming method is called only when proto files declare it. With proto, each message is checked, and a violation names it by index, such as $[1].user.email.

See Streaming Methods.

The grpc action keeps to the guard

The grpc action now runs under --read-only and --allow-host without --allow-action grpc. It refuses a call the guard does not allow before anything is sent, and the step fails with the kind refused.

  • --allow-host is checked against the host and port of addr, port 443 when none is named. dns:/// and passthrough:/// targets are read through, and the DNS server of a dns://server/ target is checked too, port 53 when none is named. A target that names no host, such as unix:///tmp/grpc.sock, is refused. With protocol: connect, the host of the URL is checked, at the port of its scheme when none is named.
  • Under --read-only, a method is called only when every definition of it at hand, the server's reflection and the .proto files of proto, declares option idempotency_level = NO_SIDE_EFFECTS;. A Connect call without proto has no definition and is refused.
  • The action applies these checks even when --allow-action grpc is given. Under --read-only, a workflow that ran every grpc step with --allow-action grpc in v1.20.0 now has calls to methods not declared NO_SIDE_EFFECTS refused.

See Under a Guard.

Actions declare the guard they keep to

Which actions run under --read-only and --allow-host used to be a fixed list of built-in names in Probe, so an external action was always refused under a guard unless --allow-action named it. Each action now declares the kinds of guard it keeps to, and an external action does so with guard in its action.yml:

name: greet
description: Say hello over HTTP
guard: [read-only, allow-host]
params: [url, name]
runs:
  using: binary
  url: https://github.com/<owner>/probe-greet/releases/download/v0.1.0/probe-greet_{os}_{arch}
  checksums:
    linux_amd64: <SHA-256 of probe-greet_linux_amd64>
  • The kinds are read-only and allow-host. A step runs under a guard only when its action declares every kind the run is under, or when --allow-action names it. An unknown kind is ignored.
  • Probe does not verify a declaration. The guard holds only as far as the external actions a workflow uses keep to what they declare, so review them before running a workflow under a guard.
  • The built-in actions keep to the guard as before: http, db, grpc, embedded and hello declare both kinds.
  • The refusal now names the missing kinds, such as does not keep to --read-only and --allow-host, which the run is under.
  • Probe reads action.yml of every external action before the first job, and downloads the executable only for one that the guard lets run.
  • params lists the keys the action takes in with. probe check reports a key that is not listed, in a step's with and in a job's defaults. Without params, with is not checked. An action.yml that probe check cannot read gives a warning.

The new Guard page describes what Probe and the actions each do, the table of what each built-in action refuses (moved from the CLI reference), and how an external action keeps to the guard. The action.yml fields are in External Actions.

Reference pages for graphql and jmap

The external actions graphql and jmap now have reference pages, in English and Japanese, and probe guide graphql and probe guide jmap print them. Both repositories moved to mozership; the docs and examples now pin these:

uses: github.com/mozership/probe-graphql@ad456d1eefd30a63d14b49c730e5239c4749b34b # v0.1.1
uses: github.com/mozership/probe-jmap@295701f5263fffd64161a34dd377722ccad3923a # v0.1.0
  • probe-graphql v0.1.1 is the same action as v0.1.0, released from mozership/probe-graphql, and its action.yml downloads the executables from there.
  • The action.yml of neither release declares guard yet, so both are still refused under a guard unless --allow-action names them. probe-jmap refuses what the guard does not allow when it is told the guard.

See GraphQL and JMAP.

For library users

This release breaks the Go API; workflow files are not affected. actionrpc.Guard.Keeping []string is replaced by Keeps map[string][]string, the kinds of guard each action keeps to by its uses, and a Guard built with Keeping: actions.Keeping() is now built with Keeps: actions.Keeps(). Guard.Runs now requires every kind in Guard.Kinds(). In pb.Guard, field 4 is reserved and keeps is field 5. An external action built with an earlier actionrpc still reads the guard it is sent. See CHANGELOG.md for the full table.

New public API:

  • actionrpc: Guard.Kinds, Guard.Missing, Guard.WithKeeps, and the constants KindReadOnly and KindAllowHost.
  • actions.Keeps(), and a Keeps() in each of db, embedded, grpc, hello and http. actions.Keeping() stays, computed from the declarations.
  • actionref.Manifest gains Guard and Params; Resolver.Manifest and actionref.ReadManifest read an action.yml without fetching the executable.
  • probe.CheckOptions.Manifest, which probe check sets to actionref.ReadManifest to check an external action's with against its params.
  • grpc.RequestStep, and RunStep on the grpc action, which make a call under the guard of the run; grpc.Request stays and calls RequestStep without a guard.

Changelog

  • 9245df5 Call a gRPC method with the Connect protocol
  • c5bd19d Call streaming methods with gRPC and the Connect protocol
  • 5212a1a Check an addr without a scheme as the URL it stands for
  • dc37b8e Check the DNS server a dns:// target names against the guard
  • a4640a5 Close the connection, keep the timeout header in range, read a reply as JSON
  • 446f932 Document graphql and jmap as external actions, apart from the built-in ones
  • 2f48226 Keep the grpc action to the guard of a run
  • d767575 Let each action declare the guard it keeps to, and document the guard
  • abefbbb Merge pull request #347 from mozership/feat/grpc-connect
  • 609df22 Merge pull request #348 from mozership/feat/grpc-guard
  • e7de25c Merge pull request #349 from mozership/feat/grpc-streaming
  • d8ac12f Merge pull request #350 from mozership/docs/external-actions
  • deacd73 Merge pull request #351 from mozership/chore/probe-graphql-v0.1.1
  • 692a145 Merge pull request #352 from mozership/feat/guard-declared-by-actions
  • 1c6a09a Merge pull request #353 from mozership/release/v1.21.0
  • 7675e46 Name probe-graphql by its current owner, mozership
  • a0edff3 Pin probe-graphql v0.1.1, whose action.yml names mozership
  • 7663cab Prepare the changelog for v1.21.0
  • 0c22b87 Read an envelope as it comes, send the protocol version, tell a stream that does not fit
  • 8ff4441 Replace a declaration the guard came with, and tell local actions apart
  • 676edd1 Say once that workflow files are not affected
  • c671dfa Say which idempotency_level a refused method has, and where
  • f6a9c71 Say 許可 for what a document, a schema or umask allows, too
  • 823f9ff Say 許可 for what the guard allows in the Japanese docs