Configure GCP Cloud Build Triggers

The gcp:cloudbuild/trigger:Trigger resource, part of the Pulumi GCP provider, defines automated build triggers that respond to repository events, Pub/Sub messages, or webhook requests. This guide focuses on five capabilities: repository branch monitoring with build files, inline build definitions, event-driven triggers via Pub/Sub and webhooks, Cloud Build v2 connections, and custom service account configuration.

Triggers reference repositories, Pub/Sub topics, Secret Manager secrets, and service accounts that must exist separately. The examples are intentionally small. Combine them with your own repository connections, IAM roles, and event sources.

Trigger builds from repository branches with a build file

Most CI/CD pipelines monitor a repository branch and execute builds when code changes, reading build instructions from a YAML file in the repository.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const filename_trigger = new gcp.cloudbuild.Trigger("filename-trigger", {
    location: "us-central1",
    triggerTemplate: {
        branchName: "main",
        repoName: "my-repo",
    },
    substitutions: {
        _FOO: "bar",
        _BAZ: "qux",
    },
    filename: "cloudbuild.yaml",
});
import pulumi
import pulumi_gcp as gcp

filename_trigger = gcp.cloudbuild.Trigger("filename-trigger",
    location="us-central1",
    trigger_template={
        "branch_name": "main",
        "repo_name": "my-repo",
    },
    substitutions={
        "_FOO": "bar",
        "_BAZ": "qux",
    },
    filename="cloudbuild.yaml")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudbuild.NewTrigger(ctx, "filename-trigger", &cloudbuild.TriggerArgs{
			Location: pulumi.String("us-central1"),
			TriggerTemplate: &cloudbuild.TriggerTriggerTemplateArgs{
				BranchName: pulumi.String("main"),
				RepoName:   pulumi.String("my-repo"),
			},
			Substitutions: pulumi.StringMap{
				"_FOO": pulumi.String("bar"),
				"_BAZ": pulumi.String("qux"),
			},
			Filename: pulumi.String("cloudbuild.yaml"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var filename_trigger = new Gcp.CloudBuild.Trigger("filename-trigger", new()
    {
        Location = "us-central1",
        TriggerTemplate = new Gcp.CloudBuild.Inputs.TriggerTriggerTemplateArgs
        {
            BranchName = "main",
            RepoName = "my-repo",
        },
        Substitutions = 
        {
            { "_FOO", "bar" },
            { "_BAZ", "qux" },
        },
        Filename = "cloudbuild.yaml",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudbuild.Trigger;
import com.pulumi.gcp.cloudbuild.TriggerArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerTriggerTemplateArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var filename_trigger = new Trigger("filename-trigger", TriggerArgs.builder()
            .location("us-central1")
            .triggerTemplate(TriggerTriggerTemplateArgs.builder()
                .branchName("main")
                .repoName("my-repo")
                .build())
            .substitutions(Map.ofEntries(
                Map.entry("_FOO", "bar"),
                Map.entry("_BAZ", "qux")
            ))
            .filename("cloudbuild.yaml")
            .build());

    }
}
resources:
  filename-trigger:
    type: gcp:cloudbuild:Trigger
    properties:
      location: us-central1
      triggerTemplate:
        branchName: main
        repoName: my-repo
      substitutions:
        _FOO: bar
        _BAZ: qux
      filename: cloudbuild.yaml

The triggerTemplate property defines which repository and branch to monitor. The branchName field accepts regular expressions (here, “main” matches exactly). When commits land on the matching branch, Cloud Build reads the filename property to locate build instructions. The substitutions property passes key-value pairs into the build as environment variables.

Define build steps inline without a repository file

Some workflows define build logic directly in the trigger rather than reading from a repository file, enabling centralized build management.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const build_trigger = new gcp.cloudbuild.Trigger("build-trigger", {
    name: "my-trigger",
    location: "global",
    triggerTemplate: {
        branchName: "main",
        repoName: "my-repo",
    },
    build: {
        steps: [
            {
                name: "gcr.io/cloud-builders/gcloud",
                args: [
                    "storage",
                    "cp",
                    "gs://mybucket/remotefile.zip",
                    "localfile.zip",
                ],
                timeout: "120s",
                secretEnvs: ["MY_SECRET"],
            },
            {
                name: "ubuntu",
                script: "echo hello",
            },
        ],
        source: {
            storageSource: {
                bucket: "mybucket",
                object: "source_code.tar.gz",
            },
        },
        tags: [
            "build",
            "newFeature",
        ],
        substitutions: {
            _FOO: "bar",
            _BAZ: "qux",
        },
        queueTtl: "20s",
        logsBucket: "gs://mybucket/logs",
        secrets: [{
            kmsKeyName: "projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name",
            secretEnv: {
                PASSWORD: "ZW5jcnlwdGVkLXBhc3N3b3JkCg==",
            },
        }],
        availableSecrets: {
            secretManagers: [{
                env: "MY_SECRET",
                versionName: "projects/myProject/secrets/mySecret/versions/latest",
            }],
        },
        artifacts: {
            images: ["gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA"],
            objects: {
                location: "gs://bucket/path/to/somewhere/",
                paths: ["path"],
            },
            npmPackages: [{
                packagePath: "package.json",
                repository: "https://us-west1-npm.pkg.dev/myProject/quickstart-nodejs-repo",
            }],
            pythonPackages: [{
                paths: ["dist/*"],
                repository: "https://us-west1-python.pkg.dev/myProject/quickstart-python-repo",
            }],
            mavenArtifacts: [{
                repository: "https://us-west1-maven.pkg.dev/myProject/quickstart-java-repo",
                path: "/workspace/my-app/target/my-app-1.0.SNAPSHOT.jar",
                artifactId: "my-app",
                groupId: "com.mycompany.app",
                version: "1.0",
            }],
        },
        options: {
            sourceProvenanceHashes: ["MD5"],
            requestedVerifyOption: "VERIFIED",
            machineType: "N1_HIGHCPU_8",
            diskSizeGb: 100,
            substitutionOption: "ALLOW_LOOSE",
            dynamicSubstitutions: true,
            logStreamingOption: "STREAM_OFF",
            workerPool: "pool",
            logging: "LEGACY",
            envs: ["ekey = evalue"],
            secretEnvs: ["secretenv = svalue"],
            volumes: [{
                name: "v1",
                path: "v1",
            }],
        },
    },
});
import pulumi
import pulumi_gcp as gcp

build_trigger = gcp.cloudbuild.Trigger("build-trigger",
    name="my-trigger",
    location="global",
    trigger_template={
        "branch_name": "main",
        "repo_name": "my-repo",
    },
    build={
        "steps": [
            {
                "name": "gcr.io/cloud-builders/gcloud",
                "args": [
                    "storage",
                    "cp",
                    "gs://mybucket/remotefile.zip",
                    "localfile.zip",
                ],
                "timeout": "120s",
                "secret_envs": ["MY_SECRET"],
            },
            {
                "name": "ubuntu",
                "script": "echo hello",
            },
        ],
        "source": {
            "storage_source": {
                "bucket": "mybucket",
                "object": "source_code.tar.gz",
            },
        },
        "tags": [
            "build",
            "newFeature",
        ],
        "substitutions": {
            "_FOO": "bar",
            "_BAZ": "qux",
        },
        "queue_ttl": "20s",
        "logs_bucket": "gs://mybucket/logs",
        "secrets": [{
            "kms_key_name": "projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name",
            "secret_env": {
                "PASSWORD": "ZW5jcnlwdGVkLXBhc3N3b3JkCg==",
            },
        }],
        "available_secrets": {
            "secret_managers": [{
                "env": "MY_SECRET",
                "version_name": "projects/myProject/secrets/mySecret/versions/latest",
            }],
        },
        "artifacts": {
            "images": ["gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA"],
            "objects": {
                "location": "gs://bucket/path/to/somewhere/",
                "paths": ["path"],
            },
            "npm_packages": [{
                "package_path": "package.json",
                "repository": "https://us-west1-npm.pkg.dev/myProject/quickstart-nodejs-repo",
            }],
            "python_packages": [{
                "paths": ["dist/*"],
                "repository": "https://us-west1-python.pkg.dev/myProject/quickstart-python-repo",
            }],
            "maven_artifacts": [{
                "repository": "https://us-west1-maven.pkg.dev/myProject/quickstart-java-repo",
                "path": "/workspace/my-app/target/my-app-1.0.SNAPSHOT.jar",
                "artifact_id": "my-app",
                "group_id": "com.mycompany.app",
                "version": "1.0",
            }],
        },
        "options": {
            "source_provenance_hashes": ["MD5"],
            "requested_verify_option": "VERIFIED",
            "machine_type": "N1_HIGHCPU_8",
            "disk_size_gb": 100,
            "substitution_option": "ALLOW_LOOSE",
            "dynamic_substitutions": True,
            "log_streaming_option": "STREAM_OFF",
            "worker_pool": "pool",
            "logging": "LEGACY",
            "envs": ["ekey = evalue"],
            "secret_envs": ["secretenv = svalue"],
            "volumes": [{
                "name": "v1",
                "path": "v1",
            }],
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudbuild.NewTrigger(ctx, "build-trigger", &cloudbuild.TriggerArgs{
			Name:     pulumi.String("my-trigger"),
			Location: pulumi.String("global"),
			TriggerTemplate: &cloudbuild.TriggerTriggerTemplateArgs{
				BranchName: pulumi.String("main"),
				RepoName:   pulumi.String("my-repo"),
			},
			Build: &cloudbuild.TriggerBuildArgs{
				Steps: cloudbuild.TriggerBuildStepArray{
					&cloudbuild.TriggerBuildStepArgs{
						Name: pulumi.String("gcr.io/cloud-builders/gcloud"),
						Args: pulumi.StringArray{
							pulumi.String("storage"),
							pulumi.String("cp"),
							pulumi.String("gs://mybucket/remotefile.zip"),
							pulumi.String("localfile.zip"),
						},
						Timeout: pulumi.String("120s"),
						SecretEnvs: pulumi.StringArray{
							pulumi.String("MY_SECRET"),
						},
					},
					&cloudbuild.TriggerBuildStepArgs{
						Name:   pulumi.String("ubuntu"),
						Script: pulumi.String("echo hello"),
					},
				},
				Source: &cloudbuild.TriggerBuildSourceArgs{
					StorageSource: &cloudbuild.TriggerBuildSourceStorageSourceArgs{
						Bucket: pulumi.String("mybucket"),
						Object: pulumi.String("source_code.tar.gz"),
					},
				},
				Tags: pulumi.StringArray{
					pulumi.String("build"),
					pulumi.String("newFeature"),
				},
				Substitutions: pulumi.StringMap{
					"_FOO": pulumi.String("bar"),
					"_BAZ": pulumi.String("qux"),
				},
				QueueTtl:   pulumi.String("20s"),
				LogsBucket: pulumi.String("gs://mybucket/logs"),
				Secrets: cloudbuild.TriggerBuildSecretArray{
					&cloudbuild.TriggerBuildSecretArgs{
						KmsKeyName: pulumi.String("projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name"),
						SecretEnv: pulumi.StringMap{
							"PASSWORD": pulumi.String("ZW5jcnlwdGVkLXBhc3N3b3JkCg=="),
						},
					},
				},
				AvailableSecrets: &cloudbuild.TriggerBuildAvailableSecretsArgs{
					SecretManagers: cloudbuild.TriggerBuildAvailableSecretsSecretManagerArray{
						&cloudbuild.TriggerBuildAvailableSecretsSecretManagerArgs{
							Env:         pulumi.String("MY_SECRET"),
							VersionName: pulumi.String("projects/myProject/secrets/mySecret/versions/latest"),
						},
					},
				},
				Artifacts: &cloudbuild.TriggerBuildArtifactsArgs{
					Images: pulumi.StringArray{
						pulumi.String("gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA"),
					},
					Objects: &cloudbuild.TriggerBuildArtifactsObjectsArgs{
						Location: pulumi.String("gs://bucket/path/to/somewhere/"),
						Paths: pulumi.StringArray{
							pulumi.String("path"),
						},
					},
					NpmPackages: cloudbuild.TriggerBuildArtifactsNpmPackageArray{
						&cloudbuild.TriggerBuildArtifactsNpmPackageArgs{
							PackagePath: pulumi.String("package.json"),
							Repository:  pulumi.String("https://us-west1-npm.pkg.dev/myProject/quickstart-nodejs-repo"),
						},
					},
					PythonPackages: cloudbuild.TriggerBuildArtifactsPythonPackageArray{
						&cloudbuild.TriggerBuildArtifactsPythonPackageArgs{
							Paths: pulumi.StringArray{
								pulumi.String("dist/*"),
							},
							Repository: pulumi.String("https://us-west1-python.pkg.dev/myProject/quickstart-python-repo"),
						},
					},
					MavenArtifacts: cloudbuild.TriggerBuildArtifactsMavenArtifactArray{
						&cloudbuild.TriggerBuildArtifactsMavenArtifactArgs{
							Repository: pulumi.String("https://us-west1-maven.pkg.dev/myProject/quickstart-java-repo"),
							Path:       pulumi.String("/workspace/my-app/target/my-app-1.0.SNAPSHOT.jar"),
							ArtifactId: pulumi.String("my-app"),
							GroupId:    pulumi.String("com.mycompany.app"),
							Version:    pulumi.String("1.0"),
						},
					},
				},
				Options: &cloudbuild.TriggerBuildOptionsArgs{
					SourceProvenanceHashes: pulumi.StringArray{
						pulumi.String("MD5"),
					},
					RequestedVerifyOption: pulumi.String("VERIFIED"),
					MachineType:           pulumi.String("N1_HIGHCPU_8"),
					DiskSizeGb:            pulumi.Int(100),
					SubstitutionOption:    pulumi.String("ALLOW_LOOSE"),
					DynamicSubstitutions:  pulumi.Bool(true),
					LogStreamingOption:    pulumi.String("STREAM_OFF"),
					WorkerPool:            pulumi.String("pool"),
					Logging:               pulumi.String("LEGACY"),
					Envs: pulumi.StringArray{
						pulumi.String("ekey = evalue"),
					},
					SecretEnvs: pulumi.StringArray{
						pulumi.String("secretenv = svalue"),
					},
					Volumes: cloudbuild.TriggerBuildOptionsVolumeArray{
						&cloudbuild.TriggerBuildOptionsVolumeArgs{
							Name: pulumi.String("v1"),
							Path: pulumi.String("v1"),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var build_trigger = new Gcp.CloudBuild.Trigger("build-trigger", new()
    {
        Name = "my-trigger",
        Location = "global",
        TriggerTemplate = new Gcp.CloudBuild.Inputs.TriggerTriggerTemplateArgs
        {
            BranchName = "main",
            RepoName = "my-repo",
        },
        Build = new Gcp.CloudBuild.Inputs.TriggerBuildArgs
        {
            Steps = new[]
            {
                new Gcp.CloudBuild.Inputs.TriggerBuildStepArgs
                {
                    Name = "gcr.io/cloud-builders/gcloud",
                    Args = new[]
                    {
                        "storage",
                        "cp",
                        "gs://mybucket/remotefile.zip",
                        "localfile.zip",
                    },
                    Timeout = "120s",
                    SecretEnvs = new[]
                    {
                        "MY_SECRET",
                    },
                },
                new Gcp.CloudBuild.Inputs.TriggerBuildStepArgs
                {
                    Name = "ubuntu",
                    Script = "echo hello",
                },
            },
            Source = new Gcp.CloudBuild.Inputs.TriggerBuildSourceArgs
            {
                StorageSource = new Gcp.CloudBuild.Inputs.TriggerBuildSourceStorageSourceArgs
                {
                    Bucket = "mybucket",
                    Object = "source_code.tar.gz",
                },
            },
            Tags = new[]
            {
                "build",
                "newFeature",
            },
            Substitutions = 
            {
                { "_FOO", "bar" },
                { "_BAZ", "qux" },
            },
            QueueTtl = "20s",
            LogsBucket = "gs://mybucket/logs",
            Secrets = new[]
            {
                new Gcp.CloudBuild.Inputs.TriggerBuildSecretArgs
                {
                    KmsKeyName = "projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name",
                    SecretEnv = 
                    {
                        { "PASSWORD", "ZW5jcnlwdGVkLXBhc3N3b3JkCg==" },
                    },
                },
            },
            AvailableSecrets = new Gcp.CloudBuild.Inputs.TriggerBuildAvailableSecretsArgs
            {
                SecretManagers = new[]
                {
                    new Gcp.CloudBuild.Inputs.TriggerBuildAvailableSecretsSecretManagerArgs
                    {
                        Env = "MY_SECRET",
                        VersionName = "projects/myProject/secrets/mySecret/versions/latest",
                    },
                },
            },
            Artifacts = new Gcp.CloudBuild.Inputs.TriggerBuildArtifactsArgs
            {
                Images = new[]
                {
                    "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA",
                },
                Objects = new Gcp.CloudBuild.Inputs.TriggerBuildArtifactsObjectsArgs
                {
                    Location = "gs://bucket/path/to/somewhere/",
                    Paths = new[]
                    {
                        "path",
                    },
                },
                NpmPackages = new[]
                {
                    new Gcp.CloudBuild.Inputs.TriggerBuildArtifactsNpmPackageArgs
                    {
                        PackagePath = "package.json",
                        Repository = "https://us-west1-npm.pkg.dev/myProject/quickstart-nodejs-repo",
                    },
                },
                PythonPackages = new[]
                {
                    new Gcp.CloudBuild.Inputs.TriggerBuildArtifactsPythonPackageArgs
                    {
                        Paths = new[]
                        {
                            "dist/*",
                        },
                        Repository = "https://us-west1-python.pkg.dev/myProject/quickstart-python-repo",
                    },
                },
                MavenArtifacts = new[]
                {
                    new Gcp.CloudBuild.Inputs.TriggerBuildArtifactsMavenArtifactArgs
                    {
                        Repository = "https://us-west1-maven.pkg.dev/myProject/quickstart-java-repo",
                        Path = "/workspace/my-app/target/my-app-1.0.SNAPSHOT.jar",
                        ArtifactId = "my-app",
                        GroupId = "com.mycompany.app",
                        Version = "1.0",
                    },
                },
            },
            Options = new Gcp.CloudBuild.Inputs.TriggerBuildOptionsArgs
            {
                SourceProvenanceHashes = new[]
                {
                    "MD5",
                },
                RequestedVerifyOption = "VERIFIED",
                MachineType = "N1_HIGHCPU_8",
                DiskSizeGb = 100,
                SubstitutionOption = "ALLOW_LOOSE",
                DynamicSubstitutions = true,
                LogStreamingOption = "STREAM_OFF",
                WorkerPool = "pool",
                Logging = "LEGACY",
                Envs = new[]
                {
                    "ekey = evalue",
                },
                SecretEnvs = new[]
                {
                    "secretenv = svalue",
                },
                Volumes = new[]
                {
                    new Gcp.CloudBuild.Inputs.TriggerBuildOptionsVolumeArgs
                    {
                        Name = "v1",
                        Path = "v1",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudbuild.Trigger;
import com.pulumi.gcp.cloudbuild.TriggerArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerTriggerTemplateArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerBuildArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerBuildSourceArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerBuildSourceStorageSourceArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerBuildAvailableSecretsArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerBuildArtifactsArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerBuildArtifactsObjectsArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerBuildOptionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var build_trigger = new Trigger("build-trigger", TriggerArgs.builder()
            .name("my-trigger")
            .location("global")
            .triggerTemplate(TriggerTriggerTemplateArgs.builder()
                .branchName("main")
                .repoName("my-repo")
                .build())
            .build(TriggerBuildArgs.builder()
                .steps(                
                    TriggerBuildStepArgs.builder()
                        .name("gcr.io/cloud-builders/gcloud")
                        .args(                        
                            "storage",
                            "cp",
                            "gs://mybucket/remotefile.zip",
                            "localfile.zip")
                        .timeout("120s")
                        .secretEnvs("MY_SECRET")
                        .build(),
                    TriggerBuildStepArgs.builder()
                        .name("ubuntu")
                        .script("echo hello")
                        .build())
                .source(TriggerBuildSourceArgs.builder()
                    .storageSource(TriggerBuildSourceStorageSourceArgs.builder()
                        .bucket("mybucket")
                        .object("source_code.tar.gz")
                        .build())
                    .build())
                .tags(                
                    "build",
                    "newFeature")
                .substitutions(Map.ofEntries(
                    Map.entry("_FOO", "bar"),
                    Map.entry("_BAZ", "qux")
                ))
                .queueTtl("20s")
                .logsBucket("gs://mybucket/logs")
                .secrets(TriggerBuildSecretArgs.builder()
                    .kmsKeyName("projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name")
                    .secretEnv(Map.of("PASSWORD", "ZW5jcnlwdGVkLXBhc3N3b3JkCg=="))
                    .build())
                .availableSecrets(TriggerBuildAvailableSecretsArgs.builder()
                    .secretManagers(TriggerBuildAvailableSecretsSecretManagerArgs.builder()
                        .env("MY_SECRET")
                        .versionName("projects/myProject/secrets/mySecret/versions/latest")
                        .build())
                    .build())
                .artifacts(TriggerBuildArtifactsArgs.builder()
                    .images("gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA")
                    .objects(TriggerBuildArtifactsObjectsArgs.builder()
                        .location("gs://bucket/path/to/somewhere/")
                        .paths("path")
                        .build())
                    .npmPackages(TriggerBuildArtifactsNpmPackageArgs.builder()
                        .packagePath("package.json")
                        .repository("https://us-west1-npm.pkg.dev/myProject/quickstart-nodejs-repo")
                        .build())
                    .pythonPackages(TriggerBuildArtifactsPythonPackageArgs.builder()
                        .paths("dist/*")
                        .repository("https://us-west1-python.pkg.dev/myProject/quickstart-python-repo")
                        .build())
                    .mavenArtifacts(TriggerBuildArtifactsMavenArtifactArgs.builder()
                        .repository("https://us-west1-maven.pkg.dev/myProject/quickstart-java-repo")
                        .path("/workspace/my-app/target/my-app-1.0.SNAPSHOT.jar")
                        .artifactId("my-app")
                        .groupId("com.mycompany.app")
                        .version("1.0")
                        .build())
                    .build())
                .options(TriggerBuildOptionsArgs.builder()
                    .sourceProvenanceHashes("MD5")
                    .requestedVerifyOption("VERIFIED")
                    .machineType("N1_HIGHCPU_8")
                    .diskSizeGb(100)
                    .substitutionOption("ALLOW_LOOSE")
                    .dynamicSubstitutions(true)
                    .logStreamingOption("STREAM_OFF")
                    .workerPool("pool")
                    .logging("LEGACY")
                    .envs("ekey = evalue")
                    .secretEnvs("secretenv = svalue")
                    .volumes(TriggerBuildOptionsVolumeArgs.builder()
                        .name("v1")
                        .path("v1")
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  build-trigger:
    type: gcp:cloudbuild:Trigger
    properties:
      name: my-trigger
      location: global
      triggerTemplate:
        branchName: main
        repoName: my-repo
      build:
        steps:
          - name: gcr.io/cloud-builders/gcloud
            args:
              - storage
              - cp
              - gs://mybucket/remotefile.zip
              - localfile.zip
            timeout: 120s
            secretEnvs:
              - MY_SECRET
          - name: ubuntu
            script: echo hello
        source:
          storageSource:
            bucket: mybucket
            object: source_code.tar.gz
        tags:
          - build
          - newFeature
        substitutions:
          _FOO: bar
          _BAZ: qux
        queueTtl: 20s
        logsBucket: gs://mybucket/logs
        secrets:
          - kmsKeyName: projects/myProject/locations/global/keyRings/keyring-name/cryptoKeys/key-name
            secretEnv:
              PASSWORD: ZW5jcnlwdGVkLXBhc3N3b3JkCg==
        availableSecrets:
          secretManagers:
            - env: MY_SECRET
              versionName: projects/myProject/secrets/mySecret/versions/latest
        artifacts:
          images:
            - gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA
          objects:
            location: gs://bucket/path/to/somewhere/
            paths:
              - path
          npmPackages:
            - packagePath: package.json
              repository: https://us-west1-npm.pkg.dev/myProject/quickstart-nodejs-repo
          pythonPackages:
            - paths:
                - dist/*
              repository: https://us-west1-python.pkg.dev/myProject/quickstart-python-repo
          mavenArtifacts:
            - repository: https://us-west1-maven.pkg.dev/myProject/quickstart-java-repo
              path: /workspace/my-app/target/my-app-1.0.SNAPSHOT.jar
              artifactId: my-app
              groupId: com.mycompany.app
              version: '1.0'
        options:
          sourceProvenanceHashes:
            - MD5
          requestedVerifyOption: VERIFIED
          machineType: N1_HIGHCPU_8
          diskSizeGb: 100
          substitutionOption: ALLOW_LOOSE
          dynamicSubstitutions: true
          logStreamingOption: STREAM_OFF
          workerPool: pool
          logging: LEGACY
          envs:
            - ekey = evalue
          secretEnvs:
            - secretenv = svalue
          volumes:
            - name: v1
              path: v1

The build property contains the complete build definition. The steps array defines each build operation: the name specifies a container image, args provides command arguments, and timeout limits execution time. The source property points to a Cloud Storage object containing source code. The secrets and availableSecrets properties integrate with KMS and Secret Manager for encrypted values. The artifacts property specifies where to publish build outputs (container images, language packages, or arbitrary objects).

Trigger builds from Pub/Sub messages

Event-driven architectures use Pub/Sub to coordinate builds across services, allowing external systems to trigger builds by publishing messages.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const mytopic = new gcp.pubsub.Topic("mytopic", {name: "my-topic"});
const pubsub_config_trigger = new gcp.cloudbuild.Trigger("pubsub-config-trigger", {
    location: "us-central1",
    name: "pubsub-trigger",
    description: "acceptance test example pubsub build trigger",
    pubsubConfig: {
        topic: mytopic.id,
    },
    sourceToBuild: {
        uri: "https://hashicorp/terraform-provider-google-beta",
        ref: "refs/heads/main",
        repoType: "GITHUB",
    },
    gitFileSource: {
        path: "cloudbuild.yaml",
        uri: "https://hashicorp/terraform-provider-google-beta",
        revision: "refs/heads/main",
        repoType: "GITHUB",
    },
    substitutions: {
        _ACTION: "$(body.message.data.action)",
    },
    filter: "_ACTION.matches('INSERT')",
});
import pulumi
import pulumi_gcp as gcp

mytopic = gcp.pubsub.Topic("mytopic", name="my-topic")
pubsub_config_trigger = gcp.cloudbuild.Trigger("pubsub-config-trigger",
    location="us-central1",
    name="pubsub-trigger",
    description="acceptance test example pubsub build trigger",
    pubsub_config={
        "topic": mytopic.id,
    },
    source_to_build={
        "uri": "https://hashicorp/terraform-provider-google-beta",
        "ref": "refs/heads/main",
        "repo_type": "GITHUB",
    },
    git_file_source={
        "path": "cloudbuild.yaml",
        "uri": "https://hashicorp/terraform-provider-google-beta",
        "revision": "refs/heads/main",
        "repo_type": "GITHUB",
    },
    substitutions={
        "_ACTION": "$(body.message.data.action)",
    },
    filter="_ACTION.matches('INSERT')")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/pubsub"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		mytopic, err := pubsub.NewTopic(ctx, "mytopic", &pubsub.TopicArgs{
			Name: pulumi.String("my-topic"),
		})
		if err != nil {
			return err
		}
		_, err = cloudbuild.NewTrigger(ctx, "pubsub-config-trigger", &cloudbuild.TriggerArgs{
			Location:    pulumi.String("us-central1"),
			Name:        pulumi.String("pubsub-trigger"),
			Description: pulumi.String("acceptance test example pubsub build trigger"),
			PubsubConfig: &cloudbuild.TriggerPubsubConfigArgs{
				Topic: mytopic.ID(),
			},
			SourceToBuild: &cloudbuild.TriggerSourceToBuildArgs{
				Uri:      pulumi.String("https://hashicorp/terraform-provider-google-beta"),
				Ref:      pulumi.String("refs/heads/main"),
				RepoType: pulumi.String("GITHUB"),
			},
			GitFileSource: &cloudbuild.TriggerGitFileSourceArgs{
				Path:     pulumi.String("cloudbuild.yaml"),
				Uri:      pulumi.String("https://hashicorp/terraform-provider-google-beta"),
				Revision: pulumi.String("refs/heads/main"),
				RepoType: pulumi.String("GITHUB"),
			},
			Substitutions: pulumi.StringMap{
				"_ACTION": pulumi.String("$(body.message.data.action)"),
			},
			Filter: pulumi.String("_ACTION.matches('INSERT')"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var mytopic = new Gcp.PubSub.Topic("mytopic", new()
    {
        Name = "my-topic",
    });

    var pubsub_config_trigger = new Gcp.CloudBuild.Trigger("pubsub-config-trigger", new()
    {
        Location = "us-central1",
        Name = "pubsub-trigger",
        Description = "acceptance test example pubsub build trigger",
        PubsubConfig = new Gcp.CloudBuild.Inputs.TriggerPubsubConfigArgs
        {
            Topic = mytopic.Id,
        },
        SourceToBuild = new Gcp.CloudBuild.Inputs.TriggerSourceToBuildArgs
        {
            Uri = "https://hashicorp/terraform-provider-google-beta",
            Ref = "refs/heads/main",
            RepoType = "GITHUB",
        },
        GitFileSource = new Gcp.CloudBuild.Inputs.TriggerGitFileSourceArgs
        {
            Path = "cloudbuild.yaml",
            Uri = "https://hashicorp/terraform-provider-google-beta",
            Revision = "refs/heads/main",
            RepoType = "GITHUB",
        },
        Substitutions = 
        {
            { "_ACTION", "$(body.message.data.action)" },
        },
        Filter = "_ACTION.matches('INSERT')",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
import com.pulumi.gcp.cloudbuild.Trigger;
import com.pulumi.gcp.cloudbuild.TriggerArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerPubsubConfigArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerSourceToBuildArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerGitFileSourceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var mytopic = new Topic("mytopic", TopicArgs.builder()
            .name("my-topic")
            .build());

        var pubsub_config_trigger = new Trigger("pubsub-config-trigger", TriggerArgs.builder()
            .location("us-central1")
            .name("pubsub-trigger")
            .description("acceptance test example pubsub build trigger")
            .pubsubConfig(TriggerPubsubConfigArgs.builder()
                .topic(mytopic.id())
                .build())
            .sourceToBuild(TriggerSourceToBuildArgs.builder()
                .uri("https://hashicorp/terraform-provider-google-beta")
                .ref("refs/heads/main")
                .repoType("GITHUB")
                .build())
            .gitFileSource(TriggerGitFileSourceArgs.builder()
                .path("cloudbuild.yaml")
                .uri("https://hashicorp/terraform-provider-google-beta")
                .revision("refs/heads/main")
                .repoType("GITHUB")
                .build())
            .substitutions(Map.of("_ACTION", "$(body.message.data.action)"))
            .filter("_ACTION.matches('INSERT')")
            .build());

    }
}
resources:
  mytopic:
    type: gcp:pubsub:Topic
    properties:
      name: my-topic
  pubsub-config-trigger:
    type: gcp:cloudbuild:Trigger
    properties:
      location: us-central1
      name: pubsub-trigger
      description: acceptance test example pubsub build trigger
      pubsubConfig:
        topic: ${mytopic.id}
      sourceToBuild:
        uri: https://hashicorp/terraform-provider-google-beta
        ref: refs/heads/main
        repoType: GITHUB
      gitFileSource:
        path: cloudbuild.yaml
        uri: https://hashicorp/terraform-provider-google-beta
        revision: refs/heads/main
        repoType: GITHUB
      substitutions:
        _ACTION: $(body.message.data.action)
      filter: _ACTION.matches('INSERT')

The pubsubConfig property connects the trigger to a Pub/Sub topic. When messages arrive, Cloud Build evaluates the filter expression against message attributes. The sourceToBuild property specifies which repository and ref to build. The gitFileSource property locates the build file within that repository. The substitutions property extracts values from the Pub/Sub message body using JSONPath expressions like $(body.message.data.action).

Connect to repositories via Cloud Build v2 connections

Cloud Build v2 connections provide a unified way to authenticate with GitHub, GitLab, and other Git providers, replacing legacy trigger templates.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const my_connection = new gcp.cloudbuildv2.Connection("my-connection", {
    location: "us-central1",
    name: "my-connection",
    githubConfig: {
        appInstallationId: 123123,
        authorizerCredential: {
            oauthTokenSecretVersion: "projects/my-project/secrets/github-pat-secret/versions/latest",
        },
    },
});
const my_repository = new gcp.cloudbuildv2.Repository("my-repository", {
    name: "my-repo",
    parentConnection: my_connection.id,
    remoteUri: "https://github.com/myuser/my-repo.git",
});
const repo_trigger = new gcp.cloudbuild.Trigger("repo-trigger", {
    location: "us-central1",
    repositoryEventConfig: {
        repository: my_repository.id,
        push: {
            branch: "feature-.*",
        },
    },
    filename: "cloudbuild.yaml",
});
import pulumi
import pulumi_gcp as gcp

my_connection = gcp.cloudbuildv2.Connection("my-connection",
    location="us-central1",
    name="my-connection",
    github_config={
        "app_installation_id": 123123,
        "authorizer_credential": {
            "oauth_token_secret_version": "projects/my-project/secrets/github-pat-secret/versions/latest",
        },
    })
my_repository = gcp.cloudbuildv2.Repository("my-repository",
    name="my-repo",
    parent_connection=my_connection.id,
    remote_uri="https://github.com/myuser/my-repo.git")
repo_trigger = gcp.cloudbuild.Trigger("repo-trigger",
    location="us-central1",
    repository_event_config={
        "repository": my_repository.id,
        "push": {
            "branch": "feature-.*",
        },
    },
    filename="cloudbuild.yaml")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuildv2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		my_connection, err := cloudbuildv2.NewConnection(ctx, "my-connection", &cloudbuildv2.ConnectionArgs{
			Location: pulumi.String("us-central1"),
			Name:     pulumi.String("my-connection"),
			GithubConfig: &cloudbuildv2.ConnectionGithubConfigArgs{
				AppInstallationId: pulumi.Int(123123),
				AuthorizerCredential: &cloudbuildv2.ConnectionGithubConfigAuthorizerCredentialArgs{
					OauthTokenSecretVersion: pulumi.String("projects/my-project/secrets/github-pat-secret/versions/latest"),
				},
			},
		})
		if err != nil {
			return err
		}
		my_repository, err := cloudbuildv2.NewRepository(ctx, "my-repository", &cloudbuildv2.RepositoryArgs{
			Name:             pulumi.String("my-repo"),
			ParentConnection: my_connection.ID(),
			RemoteUri:        pulumi.String("https://github.com/myuser/my-repo.git"),
		})
		if err != nil {
			return err
		}
		_, err = cloudbuild.NewTrigger(ctx, "repo-trigger", &cloudbuild.TriggerArgs{
			Location: pulumi.String("us-central1"),
			RepositoryEventConfig: &cloudbuild.TriggerRepositoryEventConfigArgs{
				Repository: my_repository.ID(),
				Push: &cloudbuild.TriggerRepositoryEventConfigPushArgs{
					Branch: pulumi.String("feature-.*"),
				},
			},
			Filename: pulumi.String("cloudbuild.yaml"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var my_connection = new Gcp.CloudBuildV2.Connection("my-connection", new()
    {
        Location = "us-central1",
        Name = "my-connection",
        GithubConfig = new Gcp.CloudBuildV2.Inputs.ConnectionGithubConfigArgs
        {
            AppInstallationId = 123123,
            AuthorizerCredential = new Gcp.CloudBuildV2.Inputs.ConnectionGithubConfigAuthorizerCredentialArgs
            {
                OauthTokenSecretVersion = "projects/my-project/secrets/github-pat-secret/versions/latest",
            },
        },
    });

    var my_repository = new Gcp.CloudBuildV2.Repository("my-repository", new()
    {
        Name = "my-repo",
        ParentConnection = my_connection.Id,
        RemoteUri = "https://github.com/myuser/my-repo.git",
    });

    var repo_trigger = new Gcp.CloudBuild.Trigger("repo-trigger", new()
    {
        Location = "us-central1",
        RepositoryEventConfig = new Gcp.CloudBuild.Inputs.TriggerRepositoryEventConfigArgs
        {
            Repository = my_repository.Id,
            Push = new Gcp.CloudBuild.Inputs.TriggerRepositoryEventConfigPushArgs
            {
                Branch = "feature-.*",
            },
        },
        Filename = "cloudbuild.yaml",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudbuildv2.Connection;
import com.pulumi.gcp.cloudbuildv2.ConnectionArgs;
import com.pulumi.gcp.cloudbuildv2.inputs.ConnectionGithubConfigArgs;
import com.pulumi.gcp.cloudbuildv2.inputs.ConnectionGithubConfigAuthorizerCredentialArgs;
import com.pulumi.gcp.cloudbuildv2.Repository;
import com.pulumi.gcp.cloudbuildv2.RepositoryArgs;
import com.pulumi.gcp.cloudbuild.Trigger;
import com.pulumi.gcp.cloudbuild.TriggerArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerRepositoryEventConfigArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerRepositoryEventConfigPushArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var my_connection = new Connection("my-connection", ConnectionArgs.builder()
            .location("us-central1")
            .name("my-connection")
            .githubConfig(ConnectionGithubConfigArgs.builder()
                .appInstallationId(123123)
                .authorizerCredential(ConnectionGithubConfigAuthorizerCredentialArgs.builder()
                    .oauthTokenSecretVersion("projects/my-project/secrets/github-pat-secret/versions/latest")
                    .build())
                .build())
            .build());

        var my_repository = new Repository("my-repository", RepositoryArgs.builder()
            .name("my-repo")
            .parentConnection(my_connection.id())
            .remoteUri("https://github.com/myuser/my-repo.git")
            .build());

        var repo_trigger = new Trigger("repo-trigger", TriggerArgs.builder()
            .location("us-central1")
            .repositoryEventConfig(TriggerRepositoryEventConfigArgs.builder()
                .repository(my_repository.id())
                .push(TriggerRepositoryEventConfigPushArgs.builder()
                    .branch("feature-.*")
                    .build())
                .build())
            .filename("cloudbuild.yaml")
            .build());

    }
}
resources:
  my-connection:
    type: gcp:cloudbuildv2:Connection
    properties:
      location: us-central1
      name: my-connection
      githubConfig:
        appInstallationId: 123123
        authorizerCredential:
          oauthTokenSecretVersion: projects/my-project/secrets/github-pat-secret/versions/latest
  my-repository:
    type: gcp:cloudbuildv2:Repository
    properties:
      name: my-repo
      parentConnection: ${["my-connection"].id}
      remoteUri: https://github.com/myuser/my-repo.git
  repo-trigger:
    type: gcp:cloudbuild:Trigger
    properties:
      location: us-central1
      repositoryEventConfig:
        repository: ${["my-repository"].id}
        push:
          branch: feature-.*
      filename: cloudbuild.yaml

The repositoryEventConfig property uses a Cloud Build v2 Repository resource, which itself references a Connection. The push property defines branch patterns using regular expressions. This approach centralizes authentication in the Connection resource rather than duplicating credentials across triggers.

Run builds with a custom service account

Production builds often need specific IAM permissions beyond the default Cloud Build service account.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const project = gcp.organizations.getProject({});
const cloudbuildServiceAccount = new gcp.serviceaccount.Account("cloudbuild_service_account", {accountId: "cloud-sa"});
const actAs = new gcp.projects.IAMMember("act_as", {
    project: project.then(project => project.projectId),
    role: "roles/iam.serviceAccountUser",
    member: pulumi.interpolate`serviceAccount:${cloudbuildServiceAccount.email}`,
});
const logsWriter = new gcp.projects.IAMMember("logs_writer", {
    project: project.then(project => project.projectId),
    role: "roles/logging.logWriter",
    member: pulumi.interpolate`serviceAccount:${cloudbuildServiceAccount.email}`,
});
const service_account_trigger = new gcp.cloudbuild.Trigger("service-account-trigger", {
    triggerTemplate: {
        branchName: "main",
        repoName: "my-repo",
    },
    serviceAccount: cloudbuildServiceAccount.id,
    filename: "cloudbuild.yaml",
}, {
    dependsOn: [
        actAs,
        logsWriter,
    ],
});
import pulumi
import pulumi_gcp as gcp

project = gcp.organizations.get_project()
cloudbuild_service_account = gcp.serviceaccount.Account("cloudbuild_service_account", account_id="cloud-sa")
act_as = gcp.projects.IAMMember("act_as",
    project=project.project_id,
    role="roles/iam.serviceAccountUser",
    member=cloudbuild_service_account.email.apply(lambda email: f"serviceAccount:{email}"))
logs_writer = gcp.projects.IAMMember("logs_writer",
    project=project.project_id,
    role="roles/logging.logWriter",
    member=cloudbuild_service_account.email.apply(lambda email: f"serviceAccount:{email}"))
service_account_trigger = gcp.cloudbuild.Trigger("service-account-trigger",
    trigger_template={
        "branch_name": "main",
        "repo_name": "my-repo",
    },
    service_account=cloudbuild_service_account.id,
    filename="cloudbuild.yaml",
    opts = pulumi.ResourceOptions(depends_on=[
            act_as,
            logs_writer,
        ]))
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/serviceaccount"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		cloudbuildServiceAccount, err := serviceaccount.NewAccount(ctx, "cloudbuild_service_account", &serviceaccount.AccountArgs{
			AccountId: pulumi.String("cloud-sa"),
		})
		if err != nil {
			return err
		}
		actAs, err := projects.NewIAMMember(ctx, "act_as", &projects.IAMMemberArgs{
			Project: pulumi.String(project.ProjectId),
			Role:    pulumi.String("roles/iam.serviceAccountUser"),
			Member: cloudbuildServiceAccount.Email.ApplyT(func(email string) (string, error) {
				return fmt.Sprintf("serviceAccount:%v", email), nil
			}).(pulumi.StringOutput),
		})
		if err != nil {
			return err
		}
		logsWriter, err := projects.NewIAMMember(ctx, "logs_writer", &projects.IAMMemberArgs{
			Project: pulumi.String(project.ProjectId),
			Role:    pulumi.String("roles/logging.logWriter"),
			Member: cloudbuildServiceAccount.Email.ApplyT(func(email string) (string, error) {
				return fmt.Sprintf("serviceAccount:%v", email), nil
			}).(pulumi.StringOutput),
		})
		if err != nil {
			return err
		}
		_, err = cloudbuild.NewTrigger(ctx, "service-account-trigger", &cloudbuild.TriggerArgs{
			TriggerTemplate: &cloudbuild.TriggerTriggerTemplateArgs{
				BranchName: pulumi.String("main"),
				RepoName:   pulumi.String("my-repo"),
			},
			ServiceAccount: cloudbuildServiceAccount.ID(),
			Filename:       pulumi.String("cloudbuild.yaml"),
		}, pulumi.DependsOn([]pulumi.Resource{
			actAs,
			logsWriter,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var project = Gcp.Organizations.GetProject.Invoke();

    var cloudbuildServiceAccount = new Gcp.ServiceAccount.Account("cloudbuild_service_account", new()
    {
        AccountId = "cloud-sa",
    });

    var actAs = new Gcp.Projects.IAMMember("act_as", new()
    {
        Project = project.Apply(getProjectResult => getProjectResult.ProjectId),
        Role = "roles/iam.serviceAccountUser",
        Member = cloudbuildServiceAccount.Email.Apply(email => $"serviceAccount:{email}"),
    });

    var logsWriter = new Gcp.Projects.IAMMember("logs_writer", new()
    {
        Project = project.Apply(getProjectResult => getProjectResult.ProjectId),
        Role = "roles/logging.logWriter",
        Member = cloudbuildServiceAccount.Email.Apply(email => $"serviceAccount:{email}"),
    });

    var service_account_trigger = new Gcp.CloudBuild.Trigger("service-account-trigger", new()
    {
        TriggerTemplate = new Gcp.CloudBuild.Inputs.TriggerTriggerTemplateArgs
        {
            BranchName = "main",
            RepoName = "my-repo",
        },
        ServiceAccount = cloudbuildServiceAccount.Id,
        Filename = "cloudbuild.yaml",
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            actAs,
            logsWriter,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.serviceaccount.Account;
import com.pulumi.gcp.serviceaccount.AccountArgs;
import com.pulumi.gcp.projects.IAMMember;
import com.pulumi.gcp.projects.IAMMemberArgs;
import com.pulumi.gcp.cloudbuild.Trigger;
import com.pulumi.gcp.cloudbuild.TriggerArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerTriggerTemplateArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var cloudbuildServiceAccount = new Account("cloudbuildServiceAccount", AccountArgs.builder()
            .accountId("cloud-sa")
            .build());

        var actAs = new IAMMember("actAs", IAMMemberArgs.builder()
            .project(project.projectId())
            .role("roles/iam.serviceAccountUser")
            .member(cloudbuildServiceAccount.email().applyValue(_email -> String.format("serviceAccount:%s", _email)))
            .build());

        var logsWriter = new IAMMember("logsWriter", IAMMemberArgs.builder()
            .project(project.projectId())
            .role("roles/logging.logWriter")
            .member(cloudbuildServiceAccount.email().applyValue(_email -> String.format("serviceAccount:%s", _email)))
            .build());

        var service_account_trigger = new Trigger("service-account-trigger", TriggerArgs.builder()
            .triggerTemplate(TriggerTriggerTemplateArgs.builder()
                .branchName("main")
                .repoName("my-repo")
                .build())
            .serviceAccount(cloudbuildServiceAccount.id())
            .filename("cloudbuild.yaml")
            .build(), CustomResourceOptions.builder()
                .dependsOn(                
                    actAs,
                    logsWriter)
                .build());

    }
}
resources:
  service-account-trigger:
    type: gcp:cloudbuild:Trigger
    properties:
      triggerTemplate:
        branchName: main
        repoName: my-repo
      serviceAccount: ${cloudbuildServiceAccount.id}
      filename: cloudbuild.yaml
    options:
      dependsOn:
        - ${actAs}
        - ${logsWriter}
  cloudbuildServiceAccount:
    type: gcp:serviceaccount:Account
    name: cloudbuild_service_account
    properties:
      accountId: cloud-sa
  actAs:
    type: gcp:projects:IAMMember
    name: act_as
    properties:
      project: ${project.projectId}
      role: roles/iam.serviceAccountUser
      member: serviceAccount:${cloudbuildServiceAccount.email}
  logsWriter:
    type: gcp:projects:IAMMember
    name: logs_writer
    properties:
      project: ${project.projectId}
      role: roles/logging.logWriter
      member: serviceAccount:${cloudbuildServiceAccount.email}
variables:
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The serviceAccount property specifies which identity runs the build. The IAMMember resources grant necessary roles: roles/iam.serviceAccountUser allows Cloud Build to impersonate the account, and roles/logging.logWriter enables log output. The dependsOn ensures IAM bindings exist before creating the trigger.

Accept webhook requests with secret validation

External systems can trigger builds via HTTP webhooks, with Secret Manager providing the shared secret for request validation.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const webhookTriggerSecretKey = new gcp.secretmanager.Secret("webhook_trigger_secret_key", {
    secretId: "webhook-trigger-secret-key",
    replication: {
        userManaged: {
            replicas: [{
                location: "us-central1",
            }],
        },
    },
});
const webhookTriggerSecretKeyData = new gcp.secretmanager.SecretVersion("webhook_trigger_secret_key_data", {
    secret: webhookTriggerSecretKey.id,
    secretData: "secretkeygoeshere",
});
const project = gcp.organizations.getProject({});
const secretAccessor = project.then(project => gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/secretmanager.secretAccessor",
        members: [`serviceAccount:service-${project.number}@gcp-sa-cloudbuild.iam.gserviceaccount.com`],
    }],
}));
const policy = new gcp.secretmanager.SecretIamPolicy("policy", {
    project: webhookTriggerSecretKey.project,
    secretId: webhookTriggerSecretKey.secretId,
    policyData: secretAccessor.then(secretAccessor => secretAccessor.policyData),
});
const webhook_config_trigger = new gcp.cloudbuild.Trigger("webhook-config-trigger", {
    name: "webhook-trigger",
    description: "acceptance test example webhook build trigger",
    webhookConfig: {
        secret: webhookTriggerSecretKeyData.id,
    },
    sourceToBuild: {
        uri: "https://hashicorp/terraform-provider-google-beta",
        ref: "refs/heads/main",
        repoType: "GITHUB",
    },
    gitFileSource: {
        path: "cloudbuild.yaml",
        uri: "https://hashicorp/terraform-provider-google-beta",
        revision: "refs/heads/main",
        repoType: "GITHUB",
    },
});
import pulumi
import pulumi_gcp as gcp

webhook_trigger_secret_key = gcp.secretmanager.Secret("webhook_trigger_secret_key",
    secret_id="webhook-trigger-secret-key",
    replication={
        "user_managed": {
            "replicas": [{
                "location": "us-central1",
            }],
        },
    })
webhook_trigger_secret_key_data = gcp.secretmanager.SecretVersion("webhook_trigger_secret_key_data",
    secret=webhook_trigger_secret_key.id,
    secret_data="secretkeygoeshere")
project = gcp.organizations.get_project()
secret_accessor = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/secretmanager.secretAccessor",
    "members": [f"serviceAccount:service-{project.number}@gcp-sa-cloudbuild.iam.gserviceaccount.com"],
}])
policy = gcp.secretmanager.SecretIamPolicy("policy",
    project=webhook_trigger_secret_key.project,
    secret_id=webhook_trigger_secret_key.secret_id,
    policy_data=secret_accessor.policy_data)
webhook_config_trigger = gcp.cloudbuild.Trigger("webhook-config-trigger",
    name="webhook-trigger",
    description="acceptance test example webhook build trigger",
    webhook_config={
        "secret": webhook_trigger_secret_key_data.id,
    },
    source_to_build={
        "uri": "https://hashicorp/terraform-provider-google-beta",
        "ref": "refs/heads/main",
        "repo_type": "GITHUB",
    },
    git_file_source={
        "path": "cloudbuild.yaml",
        "uri": "https://hashicorp/terraform-provider-google-beta",
        "revision": "refs/heads/main",
        "repo_type": "GITHUB",
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		webhookTriggerSecretKey, err := secretmanager.NewSecret(ctx, "webhook_trigger_secret_key", &secretmanager.SecretArgs{
			SecretId: pulumi.String("webhook-trigger-secret-key"),
			Replication: &secretmanager.SecretReplicationArgs{
				UserManaged: &secretmanager.SecretReplicationUserManagedArgs{
					Replicas: secretmanager.SecretReplicationUserManagedReplicaArray{
						&secretmanager.SecretReplicationUserManagedReplicaArgs{
							Location: pulumi.String("us-central1"),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		webhookTriggerSecretKeyData, err := secretmanager.NewSecretVersion(ctx, "webhook_trigger_secret_key_data", &secretmanager.SecretVersionArgs{
			Secret:     webhookTriggerSecretKey.ID(),
			SecretData: pulumi.String("secretkeygoeshere"),
		})
		if err != nil {
			return err
		}
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		secretAccessor, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/secretmanager.secretAccessor",
					Members: []string{
						fmt.Sprintf("serviceAccount:service-%v@gcp-sa-cloudbuild.iam.gserviceaccount.com", project.Number),
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = secretmanager.NewSecretIamPolicy(ctx, "policy", &secretmanager.SecretIamPolicyArgs{
			Project:    webhookTriggerSecretKey.Project,
			SecretId:   webhookTriggerSecretKey.SecretId,
			PolicyData: pulumi.String(secretAccessor.PolicyData),
		})
		if err != nil {
			return err
		}
		_, err = cloudbuild.NewTrigger(ctx, "webhook-config-trigger", &cloudbuild.TriggerArgs{
			Name:        pulumi.String("webhook-trigger"),
			Description: pulumi.String("acceptance test example webhook build trigger"),
			WebhookConfig: &cloudbuild.TriggerWebhookConfigArgs{
				Secret: webhookTriggerSecretKeyData.ID(),
			},
			SourceToBuild: &cloudbuild.TriggerSourceToBuildArgs{
				Uri:      pulumi.String("https://hashicorp/terraform-provider-google-beta"),
				Ref:      pulumi.String("refs/heads/main"),
				RepoType: pulumi.String("GITHUB"),
			},
			GitFileSource: &cloudbuild.TriggerGitFileSourceArgs{
				Path:     pulumi.String("cloudbuild.yaml"),
				Uri:      pulumi.String("https://hashicorp/terraform-provider-google-beta"),
				Revision: pulumi.String("refs/heads/main"),
				RepoType: pulumi.String("GITHUB"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var webhookTriggerSecretKey = new Gcp.SecretManager.Secret("webhook_trigger_secret_key", new()
    {
        SecretId = "webhook-trigger-secret-key",
        Replication = new Gcp.SecretManager.Inputs.SecretReplicationArgs
        {
            UserManaged = new Gcp.SecretManager.Inputs.SecretReplicationUserManagedArgs
            {
                Replicas = new[]
                {
                    new Gcp.SecretManager.Inputs.SecretReplicationUserManagedReplicaArgs
                    {
                        Location = "us-central1",
                    },
                },
            },
        },
    });

    var webhookTriggerSecretKeyData = new Gcp.SecretManager.SecretVersion("webhook_trigger_secret_key_data", new()
    {
        Secret = webhookTriggerSecretKey.Id,
        SecretData = "secretkeygoeshere",
    });

    var project = Gcp.Organizations.GetProject.Invoke();

    var secretAccessor = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/secretmanager.secretAccessor",
                Members = new[]
                {
                    $"serviceAccount:service-{project.Apply(getProjectResult => getProjectResult.Number)}@gcp-sa-cloudbuild.iam.gserviceaccount.com",
                },
            },
        },
    });

    var policy = new Gcp.SecretManager.SecretIamPolicy("policy", new()
    {
        Project = webhookTriggerSecretKey.Project,
        SecretId = webhookTriggerSecretKey.SecretId,
        PolicyData = secretAccessor.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData),
    });

    var webhook_config_trigger = new Gcp.CloudBuild.Trigger("webhook-config-trigger", new()
    {
        Name = "webhook-trigger",
        Description = "acceptance test example webhook build trigger",
        WebhookConfig = new Gcp.CloudBuild.Inputs.TriggerWebhookConfigArgs
        {
            Secret = webhookTriggerSecretKeyData.Id,
        },
        SourceToBuild = new Gcp.CloudBuild.Inputs.TriggerSourceToBuildArgs
        {
            Uri = "https://hashicorp/terraform-provider-google-beta",
            Ref = "refs/heads/main",
            RepoType = "GITHUB",
        },
        GitFileSource = new Gcp.CloudBuild.Inputs.TriggerGitFileSourceArgs
        {
            Path = "cloudbuild.yaml",
            Uri = "https://hashicorp/terraform-provider-google-beta",
            Revision = "refs/heads/main",
            RepoType = "GITHUB",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.Secret;
import com.pulumi.gcp.secretmanager.SecretArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationUserManagedArgs;
import com.pulumi.gcp.secretmanager.SecretVersion;
import com.pulumi.gcp.secretmanager.SecretVersionArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.secretmanager.SecretIamPolicy;
import com.pulumi.gcp.secretmanager.SecretIamPolicyArgs;
import com.pulumi.gcp.cloudbuild.Trigger;
import com.pulumi.gcp.cloudbuild.TriggerArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerWebhookConfigArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerSourceToBuildArgs;
import com.pulumi.gcp.cloudbuild.inputs.TriggerGitFileSourceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var webhookTriggerSecretKey = new Secret("webhookTriggerSecretKey", SecretArgs.builder()
            .secretId("webhook-trigger-secret-key")
            .replication(SecretReplicationArgs.builder()
                .userManaged(SecretReplicationUserManagedArgs.builder()
                    .replicas(SecretReplicationUserManagedReplicaArgs.builder()
                        .location("us-central1")
                        .build())
                    .build())
                .build())
            .build());

        var webhookTriggerSecretKeyData = new SecretVersion("webhookTriggerSecretKeyData", SecretVersionArgs.builder()
            .secret(webhookTriggerSecretKey.id())
            .secretData("secretkeygoeshere")
            .build());

        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        final var secretAccessor = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/secretmanager.secretAccessor")
                .members(String.format("serviceAccount:service-%s@gcp-sa-cloudbuild.iam.gserviceaccount.com", project.number()))
                .build())
            .build());

        var policy = new SecretIamPolicy("policy", SecretIamPolicyArgs.builder()
            .project(webhookTriggerSecretKey.project())
            .secretId(webhookTriggerSecretKey.secretId())
            .policyData(secretAccessor.policyData())
            .build());

        var webhook_config_trigger = new Trigger("webhook-config-trigger", TriggerArgs.builder()
            .name("webhook-trigger")
            .description("acceptance test example webhook build trigger")
            .webhookConfig(TriggerWebhookConfigArgs.builder()
                .secret(webhookTriggerSecretKeyData.id())
                .build())
            .sourceToBuild(TriggerSourceToBuildArgs.builder()
                .uri("https://hashicorp/terraform-provider-google-beta")
                .ref("refs/heads/main")
                .repoType("GITHUB")
                .build())
            .gitFileSource(TriggerGitFileSourceArgs.builder()
                .path("cloudbuild.yaml")
                .uri("https://hashicorp/terraform-provider-google-beta")
                .revision("refs/heads/main")
                .repoType("GITHUB")
                .build())
            .build());

    }
}
resources:
  webhookTriggerSecretKey:
    type: gcp:secretmanager:Secret
    name: webhook_trigger_secret_key
    properties:
      secretId: webhook-trigger-secret-key
      replication:
        userManaged:
          replicas:
            - location: us-central1
  webhookTriggerSecretKeyData:
    type: gcp:secretmanager:SecretVersion
    name: webhook_trigger_secret_key_data
    properties:
      secret: ${webhookTriggerSecretKey.id}
      secretData: secretkeygoeshere
  policy:
    type: gcp:secretmanager:SecretIamPolicy
    properties:
      project: ${webhookTriggerSecretKey.project}
      secretId: ${webhookTriggerSecretKey.secretId}
      policyData: ${secretAccessor.policyData}
  webhook-config-trigger:
    type: gcp:cloudbuild:Trigger
    properties:
      name: webhook-trigger
      description: acceptance test example webhook build trigger
      webhookConfig:
        secret: ${webhookTriggerSecretKeyData.id}
      sourceToBuild:
        uri: https://hashicorp/terraform-provider-google-beta
        ref: refs/heads/main
        repoType: GITHUB
      gitFileSource:
        path: cloudbuild.yaml
        uri: https://hashicorp/terraform-provider-google-beta
        revision: refs/heads/main
        repoType: GITHUB
variables:
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}
  secretAccessor:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/secretmanager.secretAccessor
            members:
              - serviceAccount:service-${project.number}@gcp-sa-cloudbuild.iam.gserviceaccount.com

The webhookConfig property references a Secret Manager secret version containing the shared secret. Cloud Build validates incoming webhook requests against this secret. The SecretIamPolicy grants the Cloud Build service account permission to read the secret. The sourceToBuild and gitFileSource properties specify which repository and build file to use when the webhook fires.

Beyond these examples

These snippets focus on specific trigger-level features: repository event sources, inline build definitions and repository-based build files, and service account configuration and secret management. They’re intentionally minimal rather than full CI/CD pipelines.

The examples may reference pre-existing infrastructure such as Cloud Source Repositories or external Git repositories, Pub/Sub topics for event-driven triggers, Secret Manager secrets and KMS keys, service accounts with appropriate IAM roles, and Cloud Build v2 connections for modern Git integrations. They focus on configuring the trigger rather than provisioning the surrounding infrastructure.

To keep things focused, common trigger patterns are omitted, including:

  • Manual approval workflows (approvalConfig)
  • File path filtering (includedFiles, ignoredFiles)
  • Build log integration with GitHub (includeBuildLogs)
  • Bitbucket Server and GitHub Enterprise configurations
  • Developer Connect event configurations
  • Build failure handling (allowFailure, allowExitCodes)

These omissions are intentional: the goal is to illustrate how each trigger feature is wired, not provide drop-in CI/CD modules. See the Cloud Build Trigger resource reference for all available configuration options.

Let's configure GCP Cloud Build Triggers

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Trigger Sources & Configuration
What trigger sources are available and can I use multiple?
You must choose exactly one trigger source: triggerTemplate, github, pubsubConfig, webhookConfig, sourceToBuild, repositoryEventConfig, bitbucketServerTriggerConfig, or developerConnectEventConfig. These are mutually exclusive and cannot be combined.
When should I use filename vs gitFileSource for my build configuration?
Use filename only with triggerTemplate or github triggers. For Pub/Sub, Webhook, or Manual triggers, you must use gitFileSource.path instead to specify the build configuration file.
What's the difference between triggerTemplate and repositoryEventConfig?
triggerTemplate is the legacy configuration for Cloud Source Repositories, while repositoryEventConfig is the newer approach that works with Cloud Build v2 repositories (GitHub, GitLab, etc.) created via gcp.cloudbuildv2.Repository.
What's the default location for triggers?
Triggers default to the “global” location if not specified. Note that location is immutable after creation, so choose carefully.
Service Accounts & Permissions
What IAM permissions does a custom service account need?
Custom service accounts require roles/iam.serviceAccountUser and roles/logging.logWriter roles. Grant these permissions before creating the trigger using dependsOn to ensure proper ordering.
How do I retrieve the Cloud Build service account email?
Use the gcp.projects.ServiceIdentity resource to retrieve the Cloud Build service account email used in jobs.
What service account is used if I don't specify one?
If no serviceAccount is set, the standard Cloud Build service account ([PROJECT_NUM]@system.gserviceaccount.com) is used for all operations.
Build Definition & Execution
How do I define the build steps?
You have two options: use filename to reference a cloudbuild.yaml file, or use build to define steps inline. You cannot use both simultaneously.
Can I prevent a build step from failing the entire build?
Yes, use allowFailure: true on the step to continue execution even if it fails, or use allowExitCodes to specify which exit codes (e.g., [1, 3]) should be treated as success.
How do I use substitutions in my build?
Define substitutions as key-value pairs. User-defined substitutions must start with an underscore (e.g., _FOO, _BAZ). Built-in substitutions like $PROJECT_ID, $REPO_NAME, and $COMMIT_SHA are also available.
Advanced Features
How do I set up a webhook trigger?
Create a Secret Manager secret with your webhook key, grant roles/secretmanager.secretAccessor to the Cloud Build service account (service-[PROJECT_NUM]@gcp-sa-cloudbuild.iam.gserviceaccount.com), then reference the secret version in webhookConfig.secret.
How do I filter which file changes trigger a build?
Use ignoredFiles and includedFiles with file glob patterns (supporting **). If a file change matches ignoredFiles, it won’t trigger a build. If includedFiles is set, at least one changed file must match to trigger a build.
How do I require manual approval before builds run?
Configure approvalConfig with approvalRequired: true. Any user with a Cloud Build Approver role for the project can then approve builds before they execute.

Using a different cloud?

Explore integration guides for other cloud providers: