1
0
Fork 0
mirror of https://code.forgejo.org/forgejo/runner.git synced 2025-09-15 18:57:01 +00:00

fix(security): ensure unique names for container images created by actions

Container images built by the runner are tagged with a unique name:

- based on the specified `uses` URL for remote actions.
- random for local actions.

In the case of local actions, this will create new tags for each run
but the images (and their layers) will be shared and not be
duplicated. The least recently used tags can be garbage collected by
tools such as https://github.com/stepchowfun/docuum.

Using a different method for creating the tag name for the remote
actions is to help with maintenance by establishing a direct relation
with the `uses` field. It was instead relying on a name transformed
multiple times which makes it more difficult to verify name collision
are not accidentally made possible by one of those transformations.

Without this fix, when a workflow ran a local [docker action](https://forgejo.org/docs/next/user/actions/actions/#docker-actions)
(e.g. the [example in the end-to-end
tests](8f920b4b7a/actions/example-force-rebuild/.forgejo/workflows/test.yml)),
it used an image tag that could collide with other workflows that
happen to use the same name.

The workaround for older runner versions is to set
[`[container].force_rebuild: true`](https://forgejo.org/docs/next/admin/actions/runner-installation/#configuration)
in the runner configuration file.
This commit is contained in:
Earl Warren 2025-08-28 10:17:00 +02:00
parent 7efe25f13d
commit 11a96bb462
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00

View file

@ -277,7 +277,6 @@ func removeGitIgnore(ctx context.Context, directory string) error {
return nil
}
// TODO: break out parts of function to reduce complexicity
func execAsDocker(ctx context.Context, step actionStep, actionName, basedir string, localAction bool) error {
logger := common.Logger(ctx)
rc := step.getRunContext()
@ -291,10 +290,11 @@ func execAsDocker(ctx context.Context, step actionStep, actionName, basedir stri
// Apply forcePull only for prebuild docker images
forcePull = rc.Config.ForcePull
} else {
// "-dockeraction" enshures that "./", "./test " won't get converted to "act-:latest", "act-test-:latest" which are invalid docker image names
image = fmt.Sprintf("%s-dockeraction:%s", regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(actionName, "-"), "latest")
image = fmt.Sprintf("act-%s", strings.TrimLeft(image, "-"))
image = strings.ToLower(image)
if localAction {
image = fmt.Sprintf("runner-local-docker-action-%s:latest", common.MustRandName(16))
} else {
image = fmt.Sprintf("runner-remote-docker-action-%s:latest", common.Sha256(step.getStepModel().Uses))
}
contextDir, fileName := filepath.Split(filepath.Join(basedir, action.Runs.Image))
anyArchExists, err := container.ImageExistsLocally(ctx, image, "any")