Skip to content

Pantry Runner

The Pantry Runner is a GitHub Actions workflow repository that tests Jarvis command submissions in an isolated sandbox before they are published to the Pantry. It is dispatched by jarvis-pantry-store via workflow_dispatch and posts HMAC-signed results back via HTTP callback.

Quick Reference

Source jarvis-pantry-runner/
Runtime GitHub Actions (public repo)
Workflow .github/workflows/container-test.yml
Dispatcher jarvis-pantry-store via workflow_dispatch
Callback HMAC-SHA256 signed POST to pantry store

Workflow Structure

The container-test.yml workflow uses a two-job split to ensure submitted code can never access the callback signing key.

Job 1: test (no secrets)

  • Has permissions: {} — no access to GITHUB_TOKEN or the pantry-callback environment
  • Clones the submission repository
  • Pre-stage: pulls python:3.11-slim, runs pip install (network enabled) for SDK + submission deps into a named Docker volume
  • Harness run: executes the SDK test harness inside a sandboxed container with strict resource constraints (see Sandbox Security Model)
  • Uploads the harness JSON result as a build artifact

Submitted code runs only in this job. It cannot reach external services and has no access to any secrets.

Job 2: callback (needs: test, if: always())

  • Runs in the pantry-callback GHA environment (where PANTRY_CALLBACK_SIGNING_KEY lives)
  • Downloads the harness artifact from Job 1
  • Signs the result with HMAC-SHA256
  • POSTs the signed payload to jarvis-pantry-store at /v1/submissions/{id}/container-result

This job never clones or runs the submission. The signing key is only visible here, not in the test job.

Sandbox Security Model

The harness container (Job 1) runs with strict Docker constraints:

Constraint Effect
--network=none No outbound network access during test execution
--read-only Filesystem is read-only (only /output is writable via tmpfs)
--memory=128m Prevents resource exhaustion
Submission bind-mounted read-only Submitted code cannot modify itself at runtime
/tmp on tmpfs Ephemeral scratch space, not persisted

The pre-stage step (dependency install) runs with network access, but in a separate throwaway container — not the harness sandbox. Deps are written to a named Docker volume that the sandboxed container then mounts read-only.

On sdist packages: the pre-stage pip install does not restrict to binary wheels (--only-binary=:all: is not set), so submissions whose dependency tree includes sdist-only packages (e.g. pydora → blowfish==0.6.1) install correctly. The pre-stage container is throwaway and holds no Pantry secrets — the callback signing key is gated to the separate callback job. A malicious build hook's worst-case outcome is faking a passing test; it cannot exfiltrate secrets or reach external services from the harness sandbox (--network=none --read-only).

Signing Model

The runner signs the callback body using HMAC-SHA256:

digest = HMAC-SHA256(
    key  = PANTRY_CALLBACK_SIGNING_KEY,
    msg  = "{submission_id}|{nonce}|{body_bytes}"
)

The digest is sent in the X-Pantry-HMAC header. The pantry server recomputes the digest from the raw request bytes (not from parsed JSON) to verify authenticity.

The nonce is generated by the pantry store at dispatch time and passed as a workflow_dispatch input. It binds the callback to a specific submission and prevents replay attacks.

Required Secrets & Environments

Secret Location Description
PANTRY_CALLBACK_SIGNING_KEY pantry-callback GHA environment Shared HMAC key. Must match the Fly secret on jarvis-pantry-store.

See Callback Signing Key Rotation for rotation instructions.

Workflow Inputs (set by pantry store at dispatch time)

Input Description
submission_id UUID of the submission
nonce Per-submission random value for replay protection
repo_url Git URL of the submission repository
ref Git ref to test
packages Resolved pip lockfile content
sdk_ref jarvis-command-sdk git ref to install in the pre-stage

Troubleshooting

harness produced no output / harness did not write JSON

This error typically means the pre-stage pip install failed before the harness container started. Check the Pre-stage step in the GHA log:

  • Syntax error in pre-stage script: an apostrophe or unbalanced quote inside the sh -c '...' string closes the outer shell string early. Look for syntax error near unexpected token in the step output.
  • Pip install failure for sdist package: if a build hook fails (e.g. missing system library), the log will show the actual pip error above the misleading envelope message.
  • git not found: the pre-stage container is python:3.11-slim and includes git for SDK installation. If this error appears, the pre-stage image definition changed.