1. Docs
  2. Integrations
  3. Version Control
  4. Custom VCS

Custom VCS

    Custom VCS integrations let you connect any Git or Mercurial version control system to Pulumi Deployments, including self-hosted and third-party servers. You configure webhooks on your VCS server to notify Pulumi Cloud when commits are pushed, and Pulumi automatically triggers deployments for matching stacks.

    Unlike the first-party GitHub, GitLab, and Azure DevOps integrations, Custom VCS uses ESC environments for credential management and requires manual webhook configuration. It supports push-to-deploy but does not support pull request comments, commit status checks, or review stacks.

    Neo, Pulumi’s AI assistant, can clone and push to Git and Mercurial repositories registered with a Custom VCS integration using the credentials from the integration’s ESC environment. Neo cannot open pull requests or create new repositories on Custom VCS servers at this time. Those operations require VCS-specific APIs only available through native integrations.

    Prerequisites

    Configure the integration

    To set up a Custom VCS integration, you must be an org admin in Pulumi Cloud.
    1. Sign in to your Pulumi account.
    2. Navigate to Management > Version control.
    3. Select Add integration and choose Custom VCS.
    4. Enter a Name for the integration (e.g., “My Git Server”). Names must be unique within your organization.
    5. Enter a Base URL — the URL prefix for your repositories (e.g., https://git.example.com/myorg). Repository names are appended to this URL to form clone URLs.
    6. Select the ESC environment containing your VCS credentials, in project/envName format (e.g., vcs-creds/git-prod).
    7. Select Save.

    By default, Custom VCS integrations are created with a VCS type of git. To configure a Mercurial integration, create the integration via the Pulumi Cloud REST API with vcsType set to hg.

    After saving, Pulumi displays a webhook URL and webhook secret.

    Copy the webhook secret immediately. It is only displayed once. If you lose it, you can regenerate it from the integration detail page, but you will need to update your VCS server’s webhook configuration with the new secret.

    Configure credentials in ESC

    Custom VCS integrations use an ESC environment to store VCS credentials. The same credential structure works for both Git and Mercurial integrations. Create an environment with one of the following authentication methods:

    Personal access token

    values:
      personalAccessToken:
        fn::secret: "your-token-here"
    

    SSH key

    values:
      sshPrivateKey:
        fn::secret: |
          -----BEGIN OPENSSH PRIVATE KEY-----
          ...
          -----END OPENSSH PRIVATE KEY-----
      sshPassword:
        fn::secret: "optional-passphrase"
    

    Basic auth

    values:
      username: "deploy-bot"
      password:
        fn::secret: "your-password"
    

    Credentials are resolved at deployment time using the access permissions of the user who configured the integration. If that user loses access to the ESC environment, deployments will fail with an authentication error.

    Add repositories

    Custom VCS integrations do not auto-discover repositories from your VCS server. You must add each repository manually.

    1. Navigate to Management > Version control and select your Custom VCS integration.
    2. Select Add repository.
    3. Enter the repository name or path (e.g., infra-prod or team/infra-prod).
    4. Optionally enter a display name for the repository.

    The repository name is joined with the integration’s base URL to form the clone URL. For example, a base URL of https://git.example.com/myorg and a repository name of infra-prod produces the clone URL https://git.example.com/myorg/infra-prod.

    To remove a repository, select the repository from the integration detail page and choose Remove.

    Configure webhooks

    After creating the integration and adding repositories, configure your VCS server to send webhook notifications to Pulumi Cloud.

    Webhook URL

    Configure your VCS server to send POST requests to:

    https://api.pulumi.com/workflow/generic-vcs
    

    Required headers

    Your webhook requests must include the following headers:

    HeaderDescriptionExample
    X-Generic-VCS-Integration-IDYour integration UUID (shown on the integration detail page)a1b2c3d4-e5f6-7890-abcd-ef1234567890
    X-Generic-VCS-SignatureHMAC-SHA256 signature of the request bodyv1=abc123def456...
    Content-TypeMust be application/jsonapplication/json

    Payload format

    The request body must be a JSON object with the following fields:

    {
      "event": "push",
      "commit": "abc123def456789...",
      "branch": "main",
      "repoUrl": "https://git.example.com/myorg/infra-prod",
      "sender": "deploy-bot",
      "changedFiles": ["infra/main.go", "Pulumi.yaml"]
    }
    
    FieldTypeRequiredDescription
    eventstringYesEvent type. Only push events trigger deployments.
    commitstringYesFull commit SHA (Git) or changeset ID (Mercurial)
    branchstringYesBranch name that was pushed to
    repoUrlstringYesFull repository URL (must match a configured repository)
    senderstringNoIdentifier for the user who pushed
    changedFilesstring[]NoFile paths changed in this push. Enables path filtering. If omitted, path filters are skipped and all pushes trigger deployments.

    HMAC signing

    Pulumi verifies webhook authenticity using HMAC-SHA256 signatures. To sign a request:

    1. Compute HMAC-SHA256(webhook_secret, raw_request_body) using the webhook secret provided during integration setup.
    2. Hex-encode the result.
    3. Set the header: X-Generic-VCS-Signature: v1=<hex-encoded-hmac>.

    The v1 prefix identifies the signing algorithm version.

    Most VCS systems use their own native webhook payload format. You may need a lightweight transformer — such as a serverless function or CI pipeline step — to convert your VCS server’s push events into the payload format above.

    Deployment settings

    Configure deployment behavior for Custom VCS-backed stacks under Stack > Settings > Deploy.

    SettingDescription
    Push to deployAutomatically deploy when commits are pushed to the configured branch
    Path filtersOnly trigger deployments when changed files match specified glob patterns (e.g., infrastructure/**). Requires the webhook payload to include the changedFiles field.

    Selecting a repository and branch

    1. Choose the Custom VCS integration (if multiple are configured).
    2. Select a repository from the dropdown. This list shows the repositories you have manually configured on the integration.
    3. Enter the target branch name.
    Unlike native integrations, Custom VCS does not auto-discover branches. You must type the branch name manually.

    Comparison with native integrations

    Custom VCS provides webhook-driven push-to-deploy but does not include the deeper VCS platform features available with native integrations.

    CapabilityNative integrationsCustom VCS
    Push-to-deployYesYes (via webhook)
    PR/MR previewsYesNo
    Commit status checksYesNo
    PR commentsYesNo
    Review stacksYesNo
    Auto-discover reposYesNo (manual)
    Branch listingYesNo (manual entry)
    Path filteringYesYes (requires changedFiles in webhook)
    Credential managementOAuth/app tokensESC environment
    Mercurial supportNoYes
    Neo clone/push to reposYesYes (Git and Mercurial)
    Neo pull request creationYesNo
    Neo repository creationYesNo

    Troubleshooting

    IssueResolution
    Webhook returns 401 UnauthorizedVerify your HMAC signature computation. Ensure you are signing the raw request body with the correct webhook secret and using HMAC-SHA256. Check that the v1= prefix is included.
    Deployments not triggeringCheck that repoUrl in your webhook payload matches a configured repository URL. Verify the branch matches your deployment settings. Confirm event is set to push and deploy on push is enabled for the stack.
    Clone fails with authentication errorVerify credentials in your ESC environment. Check that the configuring user still has access to the ESC environment.
    Integration shows broken credentialsThe ESC environment may have been deleted or the configuring user may have lost access. Update the ESC environment reference or have an admin reconfigure the integration.
    Path filters not workingPath filtering requires the changedFiles field in your webhook payload. If omitted, all pushes trigger deployments regardless of path filter settings.