Docs/Push a nightly sandbox image
#

Push a nightly sandbox image

Set up a scheduled GitHub Action that builds and pushes your sandbox image every night.

Set up a scheduled GitHub Action that builds your app's image every night and pushes it to Cofactor. Each morning, new sandboxes start from last night's build.

  • Fresh every night: a push is the version claims, flow runs and scheduled runs use as soon as it's ready.
  • Named: each push is tagged nightly, plus the date, so you can claim a specific night with --at.
  • Fails loudly: the job fails if the image doesn't boot in Cofactor.

Copy this prompt and give it to your coding agent (Claude Code, Codex, Cursor). It adds the workflow to your repo and fits it to your build:

Add a nightly Cofactor sandbox push

Or set it up by hand below.

01Before you start

  • A sandbox you already push by hand: a cofactor.sandbox.yaml and a Dockerfile that build a working image. If you don't have one yet, start with Sandboxes from a pushed image.
  • A Cofactor API key with the scopes sandbox:read, sandbox:publish and property:read (create it in Settings > API Keys; see API Keys). sandbox:read also lets the key read your sandboxes' persona logins, so treat it like any other CI secret. Save it in your GitHub repository as the secret COFACTOR_API_TOKEN (Settings > Secrets and variables > Actions).

02Add the workflow

Save this as .github/workflows/cofactor-sandbox-nightly.yml. Replace Acme Tracker with your application's name, and the Dockerfile and definition paths if yours differ. If your Dockerfile needs build args, add them under build-args:.

yaml
name: Cofactor sandbox nightly
on:
  schedule:
    - cron: "0 6 * * *" # 06:00 UTC every day
  workflow_dispatch:

permissions:
  contents: read

jobs:
  push:
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v7
      - uses: docker/setup-buildx-action@v4
      - name: Build the image
        uses: docker/build-push-action@v7
        with:
          context: .
          file: Dockerfile
          platforms: linux/amd64
          load: true
          push: false
          tags: app:sandbox
          cache-from: type=gha
          cache-to: type=gha,mode=max
      - run: npm install -g @runcofactor/cli
      - name: Push to Cofactor
        env:
          COFACTOR_API_TOKEN: ${{ secrets.COFACTOR_API_TOKEN }}
        run: |
          cofactor sandbox validate --upload cofactor.sandbox.yaml
          cofactor sandbox push --application "Acme Tracker" app:sandbox \
            --definition cofactor.sandbox.yaml --tag nightly --tag "$(date -u +%F)" --wait

The build cache keeps nightly pushes small: a push uploads only the layers Cofactor doesn't already have.

03Check that it worked

  1. Run it once by hand: Actions > Cofactor sandbox nightly > Run workflow (or gh workflow run cofactor-sandbox-nightly.yml).

  2. The push step ends with a line like Push 3f6c…: ready [nightly, 2026-10-21].

  3. Claim last night's build and check the app and its logins:

    bash
    cofactor sandbox claim --application "Acme Tracker" --environment default --at nightly --wait
    

    When you're done, run cofactor sandbox destroy <id>.

A failed boot fails the job, with the failing service's log in the output. The workflow installs the latest CLI each night, so a sudden failure right after a CLI release can mean the CLI is ahead of the server; rerun it later. See Troubleshooting.