fix: allow tmpfs mounts in container options (#1289)

Support tmpfs in container `options` via `--mount type=tmpfs,...`, like GitHub does. The `valid_volumes` check silently dropped these mounts because they have no source. A tmpfs is backed by memory and exposes nothing from the host, same as `--tmpfs`, which already passes. Every other mount still goes through the allowlist.

Both forms now work:

```yaml
services:
  mysql:
    image: mysql:8.4
    options: --tmpfs /var/lib/mysql # already worked
```

```yaml
services:
  mysql:
    image: mysql:8.4
    options: --mount type=tmpfs,destination=/var/lib/mysql # was dropped, now works
```

Reviewed-on: https://gitea.com/gitea/runner/pulls/1289
Reviewed-by: bircni <[email protected]>
Co-authored-by: silverwind <[email protected]>
This commit is contained in:
silverwind authored and bircni committed 2026-10-06 19:19:51 +00:00
1 parent 020f0d2861
commit 2e59141ae9
3 files changed
+33 -19

No files matched your search

+13 -14
View File
@@ -1158,9 +1158,9 @@ func parseOptionsHostConfig(options string) (*container.HostConfig, error) {
// sanitizeConfig remove the invalid configurations from `config` and `hostConfig`
func (cr *containerReference) sanitizeConfig(ctx context.Context, config *container.Config, hostConfig *container.HostConfig) (*container.Config, *container.HostConfig) {
logger := common.Logger(ctx)
matcher := newValidVolumeMatcher(ctx, cr.input.ValidVolumes)
if len(cr.input.ValidVolumes) > 0 {
matcher := newValidVolumeMatcher(ctx, cr.input.ValidVolumes)
// sanitize binds
sanitizedBinds := make([]string, 0, len(hostConfig.Binds))
for _, bind := range hostConfig.Binds {
@@ -1181,26 +1181,22 @@ func (cr *containerReference) sanitizeConfig(ctx context.Context, config *contai
}
}
hostConfig.Binds = sanitizedBinds
// sanitize mounts
sanitizedMounts := make([]mount.Mount, 0, len(hostConfig.Mounts))
for _, mt := range hostConfig.Mounts {
if matcher.isValid(mt.Source, mt.Type) {
sanitizedMounts = append(sanitizedMounts, mt)
} else {
logger.Warnf("[%s] is not a valid volume, will be ignored", mt.Source)
}
}
hostConfig.Mounts = sanitizedMounts
} else {
for _, bind := range hostConfig.Binds {
logger.Warnf("[%s] is not a valid volume, will be ignored", bind)
}
for _, mt := range hostConfig.Mounts {
hostConfig.Binds = []string{}
}
// sanitize mounts
sanitizedMounts := make([]mount.Mount, 0, len(hostConfig.Mounts))
for _, mt := range hostConfig.Mounts {
if matcher.isValid(mt.Source, mt.Type) {
sanitizedMounts = append(sanitizedMounts, mt)
} else {
logger.Warnf("[%s] is not a valid volume, will be ignored", mt.Source)
}
hostConfig.Binds = []string{}
hostConfig.Mounts = []mount.Mount{}
}
hostConfig.Mounts = sanitizedMounts
return config, hostConfig
}
@@ -1284,6 +1280,9 @@ func (m validVolumeMatcher) isValid(source string, sourceType mount.Type) bool {
if m.allowAll {
return true
}
if sourceType == mount.TypeTmpfs && source == "" { // backed by memory, exposes nothing from the host, same as --tmpfs
return true
}
if isHostVolumeSource(source, sourceType) {
normalized, err := normalizeHostVolumePath(source)
if err != nil {