From 8057ec66c11d40456fddb8aa53502127ce91061c Mon Sep 17 00:00:00 2001 From: Tomas Srnka Date: Wed, 8 Apr 2026 14:42:00 +0200 Subject: [PATCH 1/7] ci: publish busybox binaries to GCS public builds bucket Add a publish job that uploads both amd64 and arm64 busybox binaries to the GCS public builds bucket (e2b-prod-public-builds/busybox/{arch}/busybox) after a successful build. This mirrors how fc-kernels publishes to GCS. Previously, busybox was only available via GitHub releases and had to be fetched at compile time for go:embed. The infra repo is moving to runtime disk reads (like kernels and firecracker), which requires busybox to be in the GCS bucket for host-init downloads and gcsfuse/s3fs mounts. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 40 +++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a478677..181e941 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,7 @@ on: - "v*" permissions: + id-token: write contents: write jobs: @@ -44,8 +45,8 @@ jobs: name: busybox_${{ steps.version.outputs.tag }}_${{ matrix.arch }} path: builds/${{ steps.version.outputs.busybox_version }}/${{ matrix.arch }}/busybox - release: - name: Release + publish: + name: Publish needs: build runs-on: ubuntu-24.04 steps: @@ -58,25 +59,44 @@ jobs: with: path: artifacts - - name: Prepare release + - name: Prepare GCS upload + run: | + # Restructure to {arch}/busybox for GCS bucket layout + mkdir -p gcs-upload/amd64 gcs-upload/arm64 + for dir in artifacts/busybox_*; do + arch="${dir##*_}" + cp "$dir/busybox" "gcs-upload/${arch}/busybox" + chmod +x "gcs-upload/${arch}/busybox" + done + ls -laR gcs-upload/ + + - name: Setup GCP auth + uses: google-github-actions/auth@v1 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + + - name: Upload to GCS + uses: google-github-actions/upload-cloud-storage@v1 + with: + path: gcs-upload + destination: ${{ vars.GCP_BUCKET_NAME }}/busybox + gzip: false + parent: false + + - name: Prepare GitHub release run: | TAG="${{ steps.version.outputs.tag }}" mkdir release for dir in artifacts/busybox_*; do - # dir name: busybox_v1.36.1-20260401_amd64 arch="${dir##*_}" cp "$dir/busybox" "release/busybox_${TAG}_${arch}" chmod +x "release/busybox_${TAG}_${arch}" done - ls -la release/ - for f in release/*; do - echo "$(basename "$f"): $(file "$f" | cut -d: -f2)" - done - # Generate checksums file for downstream verification cd release && sha256sum busybox_* > SHA256SUMS cat SHA256SUMS - - name: Create release + - name: Create GitHub release uses: softprops/action-gh-release@v2 with: name: BusyBox ${{ steps.version.outputs.tag }} From ca4a1d485ef7dcd4fa8ce76ad79fffa1a44134ee Mon Sep 17 00:00:00 2001 From: Tomas Srnka Date: Wed, 8 Apr 2026 14:49:25 +0200 Subject: [PATCH 2/7] fix: include version in GCS upload path Upload to busybox/{version}/{arch}/busybox instead of busybox/{arch}/busybox, matching the versioned path structure expected by infra's fetch-busybox.sh and the runtime path resolution in the orchestrator. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 181e941..dbcde69 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,12 @@ jobs: steps: - name: Extract version from tag id: version - run: echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + run: | + TAG="${GITHUB_REF_NAME}" + BUSYBOX_VERSION="${TAG#v}" + BUSYBOX_VERSION="${BUSYBOX_VERSION%%-*}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "busybox_version=${BUSYBOX_VERSION}" >> "$GITHUB_OUTPUT" - name: Download artifacts uses: actions/download-artifact@v5 @@ -61,12 +66,13 @@ jobs: - name: Prepare GCS upload run: | - # Restructure to {arch}/busybox for GCS bucket layout - mkdir -p gcs-upload/amd64 gcs-upload/arm64 + # Restructure to {version}/{arch}/busybox for GCS bucket layout + VERSION="${{ steps.version.outputs.busybox_version }}" + mkdir -p "gcs-upload/${VERSION}/amd64" "gcs-upload/${VERSION}/arm64" for dir in artifacts/busybox_*; do arch="${dir##*_}" - cp "$dir/busybox" "gcs-upload/${arch}/busybox" - chmod +x "gcs-upload/${arch}/busybox" + cp "$dir/busybox" "gcs-upload/${VERSION}/${arch}/busybox" + chmod +x "gcs-upload/${VERSION}/${arch}/busybox" done ls -laR gcs-upload/ From 47063d4e89962c0d4294ee4cf5d181da6f0ecd83 Mon Sep 17 00:00:00 2001 From: Tomas Srnka Date: Wed, 8 Apr 2026 14:49:56 +0200 Subject: [PATCH 3/7] fix: upgrade Google actions to v3 and prevent GCS failure from blocking release - Update google-github-actions/auth and upload-cloud-storage from @v1 to @v3 (v1 uses deprecated Node 16, unsupported on ubuntu-24.04 runners) - Add continue-on-error to GCS steps so GitHub release creation still proceeds if GCS auth or upload fails Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dbcde69..d33470e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,13 +77,17 @@ jobs: ls -laR gcs-upload/ - name: Setup GCP auth - uses: google-github-actions/auth@v1 + id: gcp-auth + uses: google-github-actions/auth@v3 + continue-on-error: true with: workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} service_account: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} - name: Upload to GCS - uses: google-github-actions/upload-cloud-storage@v1 + if: steps.gcp-auth.outcome == 'success' + uses: google-github-actions/upload-cloud-storage@v3 + continue-on-error: true with: path: gcs-upload destination: ${{ vars.GCP_BUCKET_NAME }}/busybox From ca64b47efd9a4ce5c487755b66b92f425e3c560c Mon Sep 17 00:00:00 2001 From: Tomas Srnka Date: Wed, 8 Apr 2026 15:02:11 +0200 Subject: [PATCH 4/7] fix: upload SHA256 sidecar alongside busybox binary in GCS Generate a busybox.sha256 checksum file for each arch and upload it alongside the binary. This allows downstream consumers (fetch-busybox.sh) to verify integrity after download. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d33470e..1964008 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,13 +66,15 @@ jobs: - name: Prepare GCS upload run: | - # Restructure to {version}/{arch}/busybox for GCS bucket layout + # Restructure to {version}/{arch}/busybox with SHA256 sidecar for GCS bucket layout VERSION="${{ steps.version.outputs.busybox_version }}" mkdir -p "gcs-upload/${VERSION}/amd64" "gcs-upload/${VERSION}/arm64" for dir in artifacts/busybox_*; do arch="${dir##*_}" cp "$dir/busybox" "gcs-upload/${VERSION}/${arch}/busybox" chmod +x "gcs-upload/${VERSION}/${arch}/busybox" + # Generate SHA256 sidecar for downstream verification + (cd "gcs-upload/${VERSION}/${arch}" && sha256sum busybox > busybox.sha256) done ls -laR gcs-upload/ From fe8115fb52a940837e8e11bfb9fdaa72e5475b4a Mon Sep 17 00:00:00 2001 From: Tomas Srnka Date: Wed, 8 Apr 2026 15:47:53 +0200 Subject: [PATCH 5/7] infra: add Terraform for WIF, service account, and GitHub secrets Mirrors the fc-kernels setup: creates a Workload Identity Federation pool, service account with objectUser access to the public builds bucket, and automatically configures the GitHub repo secrets/variables needed by the CI workflow. Co-Authored-By: Claude Opus 4.6 (1M context) --- terraform/.env.template | 3 ++ terraform/Makefile | 29 +++++++++++++ terraform/main.tf | 95 +++++++++++++++++++++++++++++++++++++++++ terraform/variables.tf | 25 +++++++++++ 4 files changed, 152 insertions(+) create mode 100644 terraform/.env.template create mode 100644 terraform/Makefile create mode 100644 terraform/main.tf create mode 100644 terraform/variables.tf diff --git a/terraform/.env.template b/terraform/.env.template new file mode 100644 index 0000000..2b3cc5e --- /dev/null +++ b/terraform/.env.template @@ -0,0 +1,3 @@ +GCP_PROJECT_ID= +PREFIX= +TERRAFORM_STATE_BUCKET= diff --git a/terraform/Makefile b/terraform/Makefile new file mode 100644 index 0000000..7f2464d --- /dev/null +++ b/terraform/Makefile @@ -0,0 +1,29 @@ +-include .env + +tf_vars := TF_VAR_gcp_project_id=$(GCP_PROJECT_ID) \ + TF_VAR_prefix=$(PREFIX) \ + TF_VAR_terraform_state_bucket=$(TERRAFORM_STATE_BUCKET) + + +.PHONY: init +init: + @ printf "Initializing Terraform\n\n" + terraform init -reconfigure -input=false -backend-config="bucket=${TERRAFORM_STATE_BUCKET}" + +.PHONY: plan +plan: + @ printf "Planning Terraform\n\n" + terraform fmt -recursive + $(tf_vars) terraform plan -out=.tfplan -compact-warnings -detailed-exitcode + +.PHONY: apply +apply: + @ printf "Applying Terraform\n\n" + $(tf_vars) \ + terraform apply \ + -auto-approve \ + -input=false \ + -compact-warnings \ + -parallelism=20 \ + .tfplan + @ rm .tfplan diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..015e5e7 --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,95 @@ +terraform { + required_version = ">= 1.5.0, < 1.6.0" + backend "gcs" { + prefix = "terraform/fc-busybox-github/state" + } + required_providers { + google = { + source = "hashicorp/google" + version = "5.6.0" + } + github = { + source = "integrations/github" + version = "5.42.0" + } + random = { + source = "hashicorp/random" + version = "3.5.1" + } + } +} + +provider "google" { + project = var.gcp_project_id +} + +data "google_project" "gcp_project" {} + +// Workload Identity Federation for GitHub Actions +resource "google_iam_workload_identity_pool" "github_actions_deployment" { + workload_identity_pool_id = "${var.prefix}gha-fc-busybox" + display_name = "GHA for ${var.github_repository} FC BusyBox" + description = "OIDC identity pool for build FC BusyBox ${var.github_repository} via GitHub Actions" +} + +resource "google_iam_workload_identity_pool_provider" "gha_identity_pool_provider" { + workload_identity_pool_id = google_iam_workload_identity_pool.github_actions_deployment.workload_identity_pool_id + workload_identity_pool_provider_id = "${var.prefix}gh-provider" + display_name = "E2B GHA identity pool provider" + attribute_mapping = { + "google.subject" = "assertion.sub" + "attribute.actor" = "assertion.actor" + "attribute.repository" = "assertion.repository" + "attribute.repository_owner" = "assertion.repository_owner" + } + attribute_condition = "assertion.repository == \"${var.github_organization}/${var.github_repository}\"" + + oidc { + issuer_uri = "https://token.actions.githubusercontent.com" + } +} + +resource "google_service_account" "fc_busybox" { + account_id = "${var.prefix}fc-busybox" + display_name = "Service account for ${var.github_repository} FC BusyBox" +} + +resource "google_storage_bucket_iam_member" "fc_busybox_bucket_iam" { + bucket = var.gcs_bucket_name + role = "roles/storage.objectUser" + member = "serviceAccount:${google_service_account.fc_busybox.email}" +} + +resource "google_service_account_iam_member" "gha_service_account_wif_tokencreator_iam_member" { + service_account_id = google_service_account.fc_busybox.name + role = "roles/iam.workloadIdentityUser" + member = "principalSet://iam.googleapis.com/projects/${data.google_project.gcp_project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.github_actions_deployment.workload_identity_pool_id}/attribute.repository/${var.github_organization}/${var.github_repository}" +} + +// GitHub secrets and variables +data "google_secret_manager_secret_version" "github_token" { + secret = "${var.prefix}github-repo-token" +} + +provider "github" { + owner = var.github_organization + token = data.google_secret_manager_secret_version.github_token.secret_data +} + +resource "github_actions_secret" "workload_identity_provider_secret" { + repository = var.github_repository + secret_name = "GCP_WORKLOAD_IDENTITY_PROVIDER" + plaintext_value = "projects/${data.google_project.gcp_project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.github_actions_deployment.workload_identity_pool_id}/providers/${google_iam_workload_identity_pool_provider.gha_identity_pool_provider.workload_identity_pool_provider_id}" +} + +resource "github_actions_secret" "service_account_email_secret" { + repository = var.github_repository + secret_name = "GCP_SERVICE_ACCOUNT_EMAIL" + plaintext_value = google_service_account.fc_busybox.email +} + +resource "github_actions_variable" "gcs_bucket_name" { + repository = var.github_repository + value = var.gcs_bucket_name + variable_name = "GCP_BUCKET_NAME" +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..e33faf4 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,25 @@ +variable "github_organization" { + type = string + default = "e2b-dev" +} + +variable "github_repository" { + type = string + default = "fc-busybox" +} + +variable "gcp_project_id" { + description = "The project to deploy the cluster in" + type = string +} + +variable "prefix" { + description = "The prefix to use for all resources in this module" + type = string +} + +variable "gcs_bucket_name" { + description = "The name of the GCS bucket to store the busybox binaries" + type = string + default = "e2b-prod-public-builds" +} From b3d64889c745d4cf9ac6de4afe8ddc168b6c456b Mon Sep 17 00:00:00 2001 From: Tomas Srnka Date: Wed, 8 Apr 2026 16:06:51 +0200 Subject: [PATCH 6/7] fix: remove unused random provider from Terraform Leftover from fc-kernels template copy. No random_* resources exist. Co-Authored-By: Claude Opus 4.6 (1M context) --- terraform/main.tf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/terraform/main.tf b/terraform/main.tf index 015e5e7..db17977 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -12,10 +12,6 @@ terraform { source = "integrations/github" version = "5.42.0" } - random = { - source = "hashicorp/random" - version = "3.5.1" - } } } From dc8070c6bb9338af12829ae58a46d17fe404ab37 Mon Sep 17 00:00:00 2001 From: Jakub Novak Date: Thu, 9 Apr 2026 12:19:25 +0200 Subject: [PATCH 7/7] chore: terraform --- .gitignore | 3 +++ terraform/.env.template | 1 - terraform/.terraform.lock.hcl | 44 +++++++++++++++++++++++++++++++++++ terraform/Makefile | 5 ++-- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 terraform/.terraform.lock.hcl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..135278c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +.tfplan +.terraform diff --git a/terraform/.env.template b/terraform/.env.template index 2b3cc5e..3451ef6 100644 --- a/terraform/.env.template +++ b/terraform/.env.template @@ -1,3 +1,2 @@ GCP_PROJECT_ID= PREFIX= -TERRAFORM_STATE_BUCKET= diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl new file mode 100644 index 0000000..d896505 --- /dev/null +++ b/terraform/.terraform.lock.hcl @@ -0,0 +1,44 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/google" { + version = "5.6.0" + constraints = "5.6.0" + hashes = [ + "h1:qhj3soOCQLWWtz4PRZp68q0sJ1F7+JSCBhGualLOEjk=", + "zh:102b6a2672fade82114eb14ed46923fb1b74be2aaca3a50b4f35f7057a9a94b9", + "zh:1a56b63175068c67efbe7d130986ba2839a938f5ffc96a14fd450153174dbfa3", + "zh:1ba1c5e0c86e8aaa8037406390846e78c89b63faf9e527c7874641f35d436e1b", + "zh:3f7161b9288b47cbe89d2f9675f78d83b58ad5880c793b01f50a71ee2583844b", + "zh:66912d6e4180dac37185d17424b345a9d4e3c3c791d45e0737b35e32c9536b35", + "zh:6f06f56e9fac2e55b50e74ffac42d9522bb379394e51dca1eddd4c3b7a68545c", + "zh:8741861ebfa13bb1ed74ea7f4865388a0725ca3a781b6d873ce45e6a4630fe41", + "zh:ae89a9c538665fbc30bb83aa3b13acb18d8380e551ccf242e1c0ab4d626089ab", + "zh:c510f8321c7599aa601b1870fdc0c76cbad3054ed5cc70fe8e37a13a8046a71f", + "zh:cf143a53d5a25c6216d09a9c0b115bb473ffcebd5c4c62b2b2594b1ebc13e662", + "zh:de05b957e5dfdbaf92db47cd9b3ef46a0f8d94599eea6d472928f33058856add", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/integrations/github" { + version = "5.42.0" + constraints = "5.42.0" + hashes = [ + "h1:rfyLEgbZCk3MMCBuGd4PNFM914vtLqGIYcsmVKr6tdg=", + "zh:0f97039c6b70295c4a82347bc8a0bcea700b3fb3df0e0be53585da025584bb7c", + "zh:12e78898580cc2a72b5f2a77e191b158f88e974b0500489b691f34842288745c", + "zh:23660933e4f00293c0d4d6cd6b4d72e382c0df46b70cecf22b5c4c090d3b61e3", + "zh:74119174b46d8d197dd209a246bf8b5db113c66467e02c831e68a8ceea312d3e", + "zh:829c4c0c202fc646eb0e1759eb9c8f0757df5295be2d3344b8fd6ca8ce9ef33b", + "zh:92043e667f520aee4e08a10a183ad5abe5487f3e9c8ad5a55ea1358b14b17b1a", + "zh:998909806b4ff42cf480fcd359ec1f12b868846f89284b991987f55de24876b7", + "zh:9f758447db3bf386516562abd6da1e54d22ddc207bda25961d2b5b049f32da0f", + "zh:a6259215612d4d6a281c671b2d5aa3a0a0b0a3ae92ed60b633998bb692e922d3", + "zh:ad7d78056beb44191911db9443bf5eec41a3d60e7b01def2a9e608d1c4288d27", + "zh:b697e7b0abef3000e1db482c897b82cd455621b488bb6c4cd3d270763d7b08ac", + "zh:db8e849eded8aebff780f89ab7e1339053d2f15c1c8f94103d70266a090527ad", + "zh:e5bdbb85fb148dd75877a7b94b595d4e8680e495c241db02c4b12b91e9d08953", + "zh:ee812c5fd77d3817fb688f720e5eb42d7ff04db67a125de48b05458c9f657483", + ] +} diff --git a/terraform/Makefile b/terraform/Makefile index 7f2464d..dbf26e5 100644 --- a/terraform/Makefile +++ b/terraform/Makefile @@ -1,8 +1,9 @@ -include .env +TERRAFORM_STATE_BUCKET ?= $(GCP_PROJECT_ID)-terraform-state + tf_vars := TF_VAR_gcp_project_id=$(GCP_PROJECT_ID) \ - TF_VAR_prefix=$(PREFIX) \ - TF_VAR_terraform_state_bucket=$(TERRAFORM_STATE_BUCKET) + TF_VAR_prefix=$(PREFIX) .PHONY: init