Writing a Custom Action for GitHub Actions
First, as background, defining a custom action for GitHub Actions is not that hard. If you can define:
- Metadata such as the action’s name, description, and branding
- The input values in inputs
- The output values in outputs
- The commands that actually run in runs
then you can build one easily.
Among these, the specification for outputs is somewhat involved, but as described in Metadata syntax for GitHub Actions - GitHub Docs, if you write a string in the prescribed format to the file named by the GITHUB_OUTPUT environment variable, you can hand the contents of outputs to the next step.
| |
For a simple example the short snippet above is all it takes, but when you want a custom action to write to outputs, the custom action has to append to the file path in $GITHUB_OUTPUT in the format output_id=....
As an aside, when the contents of an output span multiple lines, you can emit them using a here-document style like the following.
Here, $GITHUB_OUTPUT holds a value like /github/file_commands/set_output_<guid>.
Writing to the $GITHUB_OUTPUT File from a Custom Action Fails with permission denied
While building a custom action, I found that writing to /github/file_commands/set_output_<guid> failed with permission denied.
| |
To give the conclusion first: when you define and run a custom action via a Dockerfile, access to the host’s directory (the host is usually something like ubuntu-latest) may not be permitted depending on the uid inside Docker.
The custom action I had built used ko to create the docker image, which is based on chainguard, a rootless container.
The uid of a rootless container is set to something like 65534 (nobody).
But as the log above shows, the file /github/file_commands/set_output_81a41ae4-699c-4a1e-ba50-eb26527a4d69 is owned by uid 1001.
This uid 1001 appears to be the user defined on the host for GitHub Actions.
So the solutions are as follows.
- Use a Dockerfile that runs as root. The Dockerfile that fixed it ended up dropping ko and using wolfi-base, a base image that has a root user. Of course basing it on an image such as Ubuntu or Rocky is fine too
- Define the GitHub Actions user (uid 1001) with useradd inside the Dockerfile
- Note: I haven’t actually tried this, so whether it really resolves the permission denied is a guess
There isn’t much information about this behavior on the internet and it took some effort to resolve, so I wrote it up.
https://github.com/go-zen-chu/aictl/blob/9c0d780ebb4c3594a8e0aed1f5248f042fd25a57/cmd/aictl/cmd/query.go#L103-L123 has a working example of implementing outputs for a custom action written in Go, so have a look if it helps.