Skip to content

v10.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 28 Oct 08:46

v10: rewritten in Rust

The server is now a single static Rust binary. The image is ~33 MB instead of ~243 MB, and idle memory drops from ~280 MB to a few MB. Against v9.9 on SQLite + filesystem: uploads are 6.7× faster, first downloads 22×, lookups 17×, and small save+restore cycles go from 4/s to over 1000/s.

The Twirp cache API, block uploads, downloads, the management REST API, /health, /metrics and all environment variables stay compatible. @actions/cache and BuildKit need no change.

⚠️ Before you upgrade

  • The database migration is one-way. On first start, v10 takes over the v9 schema.
    • A v9.10 database keeps its data.
    • A database older than v9.10 is dropped and its storage is cleared. Upgrade to v9.10 first if you want to keep entries.
    • After the migration, v9 can't run against the database. Back it up if you may need to roll back. Cache data can be rebuilt, so the worst case is a round of cache misses.
  • Uploads need the Upload Capability (?sig=) in the URL (#308). Uploads already in progress during the upgrade, and uploads created by v9 replicas while the rollout runs, are refused with 403. Those saves fail once, and the next run saves again.
  • Direct downloads with SKIP_TOKEN_VALIDATION=true no longer start (#309). Turn token validation back on, or set UNSAFE_ALLOW_DIRECT_DOWNLOADS_WITHOUT_TOKEN_VALIDATION=true (local testing only).

💥 Breaking changes

  • Removed:
    • /management-api/_rpc and the TypeScript SDK
    • the -caged image tags
    • BENCHMARK, NITRO_PORT, NITRO_HOST
    • STORAGE_S3_MAX_SOCKETS, STORAGE_S3_CONTROL_MAX_SOCKETS, STORAGE_S3_CONTROL_QUEUE_TIMEOUT_MS
    • nodejs_* metrics; process_* metrics differ slightly
  • Auth:
    • Verified tokens must carry exp.
    • ac permissions are read as bit flags: a write-only scope no longer grants reads.
    • A malformed ac claim gets 401.
  • Config:
    • Invalid config exits with code 2 and a clear message.
    • An empty variable counts as unset.
    • Every variable is also a CLI flag (--help), and a flag overrides its variable.
  • Cleanup: every job runs once at startup, then once per period, no longer on local wall-clock boundaries.
  • Eager Merge on S3/GCS: Parts now stream through the server instead of being composed inside the bucket.
  • Object storage: Parts upload through presigned URLs, so the credentials must be able to sign. Without them, uploads fall back to multipart.
  • SQLite: runs in WAL mode with synchronous=normal.
  • Twirp:
    • Error bodies are {"code","msg"}.
    • JSON responses always include empty fields.
    • FinalizeCacheEntryUpload accepts only POST.
  • Range: suffix ranges (bytes=-N) get 206 instead of the whole object.
  • Management API: DELETE /management-api/storage-locations/{id} answers 409 while the location is being downloaded.

✨ New

  • DIRECT_DOWNLOAD_URL_TTL_SECONDS (1 to 3600, default 600) sets how long signed direct-download URLs stay valid.
  • ACTIONS_TOKEN_AUDIENCE requires tokens to carry one of the listed audiences.

🐛 Fixes

  • DELETE /management-api/cache-entries now respects the repoId filter.
  • Deleting a storage location no longer removes data before the database commit or while a download is reading it.
  • A negative CACHE_CLEANUP_OLDER_THAN_DAYS stops startup. It used to delete every entry daily.
  • The debug log no longer prints decoded token claims.

⎈ Helm chart 2.0.0

  • Removed values:
    • image.variant
    • config.storage.s3.maxSockets, controlMaxSockets, controlQueueTimeoutMs
  • New value: config.directDownloadUrlTtlSeconds.
  • The image has no shell. Replace exec preStop hooks such as sleep 30 with preStop: {sleep: {seconds: 30}} (Kubernetes 1.30+).
    View changes on GitHub