Skip to content

feat: Add initial deny list for user mounted directories#1436

Open
lbeckman314 wants to merge 5 commits into
developfrom
feat/deny-lists
Open

feat: Add initial deny list for user mounted directories#1436
lbeckman314 wants to merge 5 commits into
developfrom
feat/deny-lists

Conversation

@lbeckman314

@lbeckman314 lbeckman314 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Overview ⚙️

This PR adds a default "deny list" to user-submitted task volumes to prevent errors related to trying to mount to system directories.

Current Behavior ⚠️

  • Submitted task that mounts an input file to /dev:
➜ helm upgrade --install funnel calypr/funnel --version 0.1.99-rc.37 --values values.yaml

➜ kubectl get deployments -o wide
NAME            IMAGES
funnel-server   quay.io/ohsu-comp-bio/funnel:2026-05-27

➜ kubectl port-forward svc/funnel 8000:8000
➜ cat mount-test.json
{
  "name": "deny-input-dev",
  "description": "Issue #92: Input mounted to /dev (develop → accepted, feat/deny-lists → rejected)",
  "executors": [
    {
      "image": "alpine",
      "command": ["ls", "-la", "/dev"]
    }
  ],
  "inputs": [
    {
      "url": "https://raw.githubusercontent.com/calypr/funnel/refs/heads/develop/README.md",
      "path": "/dev"
    }
  ]
}

➜ funnel task create mount-test.json
d8pfs1s622hs739b7rh0
  • Able to replicate EXECUTOR_ERROR stemming from OCI StartError: 🐛
➜ funnel task get d8pfs1s622hs739b7rh0

{
  ...
  "id":  "d8pfs1s622hs739b7rh0",
  "logs":  [
    {
      "logs":  [
        {
          "exitCode":  128,
        }
      ],
      "systemLogs":  [
         ...
        "level='error' msg='Exec error' error='executor job d8pfs1s622hs739b7rh0-0 failed with exit code 128 (StartError): failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting \"/var/lib/kubelet/pods/64a9fb7a-5822-496c-992d-2c081d929297/containers/funnel-executor-d8pfs1s622hs739b7rh0/4dc52fb5\" to rootfs at \"/dev/termination-log\": open o_path procfd: open /run/containerd/io.containerd.runtime.v2.task/k8s.io/e4a407b35fca352200248175af22997988a90d0765dafbc358bc7fcf0f186d7c/rootfs/dev/termination-log: not a directory: unknown'"
      ]
    }
  ],
  "state":  "EXECUTOR_ERROR"
}

New Behavior ✔️

forbiddenPathPrefixes

  • /dev
  • /proc
  • /sys
  • /run
  • /var/run

Tested against PR #1436 (funnel:6e404ed):

➜ helm upgrade --install funnel calypr/funnel --version 0.1.99-rc.37 --values values.yaml --set image.tag=6e404ed

➜ kubectl get deployments -o wide
NAME            IMAGES
funnel-server   quay.io/ohsu-comp-bio/funnel:6e404ed

➜ kubectl port-forward svc/funnel 8000:8000
  • Getting 400 response code when attempting to submit tasks that mount /dev:

funnel

➜ funnel task create mount-test.json
Error: [STATUS CODE - 400]      {
  "error": "invalid task message:\nTask.Inputs[0].Path: \"/dev\" is not allowed as an input path\n"
} 

curl

➜ curl -X POST http://localhost:8000/v1/tasks --data @mount-test.json -w "\n[STATUS CODE - %{http_code}]\n"
{
  "error": "invalid task message:\nTask.Inputs[0].Path: \"/dev\" is not allowed as an input path\n"
}
[STATUS CODE - 400]

Breaking Changes? ❌

  • This can technically be considered a breaking change since Funnel now rejects tasks that would previously run (and error) due to mounting inputs/outputs to system directories.

Next Steps 🌀

  • Merge to develop
  • Create new image/tag (e.g. 2026-06-23)
  • Release in Helm Chart v0.1.99-rc.39

@github-actions

Copy link
Copy Markdown

Gen3 Integration Tests

filepath passed skipped SUBTOTAL
tests/test_gen3_workflow.py 25 4 29
TOTAL 25 4 29

@lbeckman314 lbeckman314 marked this pull request as ready for review June 16, 2026 23:27
@github-actions

Copy link
Copy Markdown

Gen3 Integration Tests

filepath passed skipped SUBTOTAL
tests/test_gen3_workflow.py 25 4 29
TOTAL 25 4 29

@github-actions

Copy link
Copy Markdown

Gen3 Integration Tests

filepath passed skipped SUBTOTAL
tests/test_gen3_workflow.py 25 4 29
TOTAL 25 4 29

Add Kubernetes.ForbiddenPathPrefixes to the Funnel config so operators can
customize the deny list of container paths that user-submitted tasks may not
mount inputs, outputs, volumes, or working directories into. When set, the
configured list replaces Funnel's built-in defaults (/dev, /proc, /sys, /run,
/var/run); when empty, the defaults still apply.

Validate and InitTask now accept the deny list as a parameter (the tes package
cannot import config without an import cycle), and the server's CreateTask path
passes the configured prefixes. Client- and worker-side pre-flight validation
continue to use the defaults.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Assisted-by: Claude Code:claude [Claude Code]
@github-actions

Copy link
Copy Markdown

Gen3 Integration Tests

filepath passed skipped SUBTOTAL
tests/test_gen3_workflow.py 25 4 29
TOTAL 25 4 29

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants