Skip to content

functions: use Cloud Run uploadSource API instead of BYO GCS bucket for direct-to-Run deploys #11159

Description

@kevmoo

[REQUIRED] Use case

In src/deploy/functions/deploy.ts (introduced in #9707), uploadSourceV2 currently provisions and manages a custom Bring-Your-Own (BYO) GCS bucket (firebase-functions-src-${projectNumber}) whenever deploying directly to the Cloud Run v2 API (platform === "run", dartfunctions, or the functionsrunapionly experiment):

// Future behavior: BYO bucket if we're using the Cloud Run API directly because it does not provide a source upload API.
// We use this behavior whenever the "functionsrunapionly" experiment is enabled for now just to help vet the codepath incrementally.
// Using project number to ensure we don't exceed the bucket name length limit (in addition to PII controversy).
const baseName = `firebase-functions-src-${projectNumber}`;
const bucketName = await gcs.upsertBucket({
  product: "functions",
  createMessage: `Creating Cloud Storage bucket in ${region} to store Functions source codeUploads...`,
  projectId,
  req: {
    baseName,
    location: region,
    lifecycle: {
      rule: [{ action: { type: "Delete" }, condition: { age: 1 } }],
    },
  },
});
const objectPath = `${source.functionsSourceV2Hash}${path.extname(source.functionsSourceV2!)}`;
await gcs.upload(uploadOpts, `${bucketName}/${objectPath}`, undefined, true /* ignoreQuotaProject */);
return { bucket: bucketName, object: objectPath };

As noted in the inline comment, this BYO bucket workaround was needed because Cloud Run v2 did not previously expose a native source upload endpoint comparable to gcfv2.generateUploadUrl. Managing the bucket client-side requires the caller to hold storage.buckets.get, storage.buckets.create, storage.buckets.update, and storage.objects.create permissions, and requires firebase-tools to handle bucket naming, region provisioning, and lifecycle cleanup rules.

Cloud Run v2 now provides a native projects.locations.sourceUploads.upload (uploadSource) API (already used by default in gcloud for --no-build source deployments).

[REQUIRED] Proposal

Update uploadSourceV2 in src/deploy/functions/deploy.ts (and src/gcp/runv2.ts) to upload source archives via Cloud Run's native uploadSource endpoint instead of upserting firebase-functions-src-${projectNumber}:

  • Endpoint: POST https://run.googleapis.com/upload/v2/projects/{project}/locations/{location}:uploadSource
  • Response: Returns UploadSourceResponse containing cloudStorageSource ({ bucket, object, generation }), which maps directly to the storage.Source / cloudStorageSource field expected by runv2 service creation/updates.
  • Benefits:
    1. Eliminates client-side bucket orchestration: Cloud Run provisions and manages the regional source bucket (run-sources-{project}-{region}) server-side.
    2. Simpler IAM footprint: Callers only need run.locations.uploadSource rather than broad Cloud Storage bucket creation/lifecycle permissions.
    3. Parity with gcloud and gcfv2: Aligns the direct-to-Cloud-Run (dartfunctions / functionsrunapionly) upload flow with gcloud run deploy --no-build.

[OPTIONAL] Implementation

  1. Add an uploadSource helper in src/gcp/runv2.ts targeting POST https://run.googleapis.com/upload/v2/projects/${projectId}/locations/${region}:uploadSource.
  2. In src/deploy/functions/deploy.ts (uploadSourceV2), call runv2.uploadSource(...) when useApiOnly || v2Endpoints.some((e) => e.platform === "run") and return the resulting { bucket, object, generation } from cloudStorageSource.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions