Conversation
Adds a project-local `bash` tool for the things the purpose-built tools
don't cover: an HTTP request with `curl`, reshaping JSON with `jq`, a
one-off computation. Each call starts a fresh container, runs the commands
as one script under `set -euo pipefail`, and removes the container when the
script exits. Nothing carries over between calls.
```json
{"commands": ["curl -sS https://api.example.com/status | jq -r .version"]}
```
The container sees nothing of the host unless it is asked for. Workspace
paths named in `mounts` are checked against `access.fs` and bind-mounted
**read-only** under `/workspace`, so the tool structurally cannot become a
substitute for `fs_modify_file` and friends. Variables named in `envs` are
checked against `access.env`: a granting rule forwards them, a denying rule
refuses the call, and a variable no rule mentions prompts the user before it
is exposed. Values are forwarded by name (`--env NAME`) rather than by
value, keeping secrets out of the command line and out of `ps`, and the
prompt names the variable without ever carrying what it holds.
The default image is `registry.gitlab.com/gitlab-ci-utils/curl-jq` pinned at
`5.0.2`, carrying `curl`, `jq`, `bash`, `git`, GNU `coreutils`, and `zip`. It
runs as an unprivileged user, so a command cannot install anything the image
does not already ship — a real ceiling, and one the tool's description names
so the assistant asks rather than trying to fetch a missing tool. Point
`options.image` elsewhere to widen the set.
Any of `container`, `docker`, or `podman` will do, whichever is found on
`PATH` first; all three take the same flags, so only the program name
differs. Detection is the only part that touches the host, which is what
makes the read-only mount flag and the by-name env forwarding assertable
without a runtime installed. An `#[ignore]`d test covers the rest against a
real container: that `:ro` holds, that `bash` is present in the image, and
that no `ENTRYPOINT` swallows the `bash -c` invocation.
Networking is left at the runtime default. A container that can reach the
network can also exfiltrate what it has been given, so this is not an
isolation boundary — it is the same posture every other local tool already
has, with the filesystem narrowed considerably.
Signed-off-by: Jean Mertz <git@jeanmertz.com>
…iner Signed-off-by: Jean Mertz <git@jeanmertz.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a project-local
bashtool for the things the purpose-built tools don't cover: an HTTP request withcurl, reshaping JSON withjq, a one-off computation. Each call starts a fresh container, runs the commands as one script underset -euo pipefail, and removes the container when the script exits. Nothing carries over between calls.{"commands": ["curl -sS https://api.example.com/status | jq -r .version"]}The container sees nothing of the host unless it is asked for. Workspace paths named in
mountsare checked againstaccess.fsand bind-mounted read-only under/workspace, so the tool structurally cannot become a substitute forfs_modify_fileand friends. Variables named inenvsare checked againstaccess.env: a granting rule forwards them, a denying rule refuses the call, and a variable no rule mentions prompts the user before it is exposed. Values are forwarded by name (--env NAME) rather than by value, keeping secrets out of the command line and out ofps, and the prompt names the variable without ever carrying what it holds.The default image is
registry.gitlab.com/gitlab-ci-utils/curl-jqpinned at5.0.2, carryingcurl,jq,bash,git, GNUcoreutils, andzip. It runs as an unprivileged user, so a command cannot install anything the image does not already ship — a real ceiling, and one the tool's description names so the assistant asks rather than trying to fetch a missing tool. Pointoptions.imageelsewhere to widen the set.Any of
container,docker, orpodmanwill do, whichever is found onPATHfirst; all three take the same flags, so only the program name differs. Detection is the only part that touches the host, which is what makes the read-only mount flag and the by-name env forwarding assertable without a runtime installed. An#[ignore]d test covers the rest against a real container: that:roholds, thatbashis present in the image, and that noENTRYPOINTswallows thebash -cinvocation.Networking is left at the runtime default. A container that can reach the network can also exfiltrate what it has been given, so this is not an isolation boundary — it is the same posture every other local tool already has, with the filesystem narrowed considerably.