> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

GitHub

GitHub integration actions allow workflows to trigger GitHub Actions workflows, manage pull requests, and create issues directly using your installed GitHub Ocean integration.

Prerequisites​

  • A GitHub Ocean integration installed in your Port organization.
  • Actions processing must be enabled on your integration:
    • Hosted by Port / UI / OAuth installations: actions processing is enabled automatically.
    • Self-hosted (Helm or Docker): actions processing is disabled by default and must be explicitly enabled. See Enable actions processing (self-hosted) below.
  • Your GitHub token or app must have the appropriate permissions:
    • Workflow actions: the workflow must exist in the target repository and accept workflow_dispatch events.
    • Pull request actions: write access to pull requests in the target repositories.
    • Issue actions: write access to issues in the target repositories.
  • To run GitHub actions as the user who triggered the Port workflow (not the GitHub App bot), enable identity propagation on the node. Self-hosted Ocean only.

Enable actions processing (self-hosted)​

If you installed the GitHub Ocean integration as hosted by Port (via the UI or OAuth), actions processing is enabled automatically and you can skip to Configuration.

For self-hosted deployments (Kubernetes/Helm or Docker), the actions processor is disabled by default. You need to enable it explicitly using the flags below, depending on how you deployed the integration:

Pass the following flags when installing or upgrading the Helm chart:

helm upgrade --install github-ocean port-labs/port-ocean \
--set actionsProcessor.enabled=true \
--set liveEvents.baseUrl=<YOUR_INTEGRATION_BASE_URL> \
# ... rest of your values
  • actionsProcessor.enabled=true - enables the actions processor so the integration can receive and execute GitHub Actions dispatch requests from Port.
  • liveEvents.baseUrl=<YOUR_INTEGRATION_BASE_URL> - sets OCEAN__BASE_URL, which is required when reportWorkflowStatus is enabled (the default). Port uses this URL to receive webhook events from GitHub and update the action run status in real time. The URL must be reachable from GitHub.

If you use a dedicated actions processor worker (actionsProcessor.worker.enabled=true), route this URL to the actions processor worker service. Otherwise, route it to the main integration service.

What is reportWorkflowStatus?

By default, Port automatically updates the action/automation run status in Port when the triggered GitHub workflow finishes. This requires GitHub to send a webhook event back to the integration. If the integration's base URL is not set, Port cannot receive this callback and the run status will not be updated automatically.

To disable this behavior, set reportWorkflowStatus: false in the invocationMethod of your action, or turn off the Report workflow status toggle in the UI.

If you disable automatic reporting, add a step in your GitHub workflow that uses port-labs/port-github-action@v1 with the PATCH_RUN operation to update the action run status in Port. See Port's GitHub action for configuration details.

Configuration​

All GitHub integration actions share the same node structure:

FieldTypeDescription
typestringRequired. Must be "INTEGRATION_ACTION".
installationIdstringRequired. Your GitHub integration installation ID.
integrationProviderstringRequired. Must be "github-ocean".
integrationInvocationTypeenumRequired. One of the values listed in available actions.
integrationActionExecutionPropertiesobjectRequired. Properties for the selected action.

Available actions​

Each action is selected with the integrationInvocationType field:

ActionInvocation typeDescription
Trigger a GitHub workflowdispatch_workflowDispatch a GitHub Actions workflow and optionally wait for its result
Create a pull requestcreate_pull_requestOpen a pull request between two branches
Update a pull requestupdate_pull_requestChange a pull request's title, description, state, or base branch
Close a pull requestclose_pull_requestClose a pull request without merging it
Merge a pull requestmerge_pull_requestMerge a pull request using a specified merge strategy
Submit a pull request reviewreview_pull_requestApprove, request changes, or comment on a pull request
Create a pull request commentcreate_pr_commentAdd a comment to a pull request
Edit a pull request commentedit_pr_commentEdit an existing pull request comment
Delete a pull request commentdelete_pr_commentDelete a pull request comment
Create an issuecreate_issueCreate a new issue in a repository
Edit an issueedit_issueUpdate an issue's title, description, state, labels, or assignees
Close an issueclose_issueClose an issue with a specified reason

The remaining sections describe the execution properties of each action.

Workflow actions​

Trigger a GitHub workflow​

Dispatches a GitHub Actions workflow. Set integrationInvocationType to "dispatch_workflow".

Execution properties

FieldTypeDescription
orgstringRequired. GitHub organization or user name (e.g., port-labs).
repostringRequired. Repository name (e.g., my-repo).
workflowstringRequired. Workflow filename (e.g., deploy.yml) or workflow ID.
workflowInputsobjectInput parameters to pass to the workflow.
reportWorkflowStatusbooleanWhether to report workflow status back to Port.

Basic example

Example (click to expand)

Trigger a GitHub Actions deployment workflow, passing environment and version from the trigger inputs:

{
"identifier": "trigger-github-workflow",
"title": "Trigger GitHub Deployment",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "dispatch_workflow",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"workflow": "deploy.yml",
"workflowInputs": {
"environment": "{{ .outputs.trigger.environment }}",
"version": "{{ .outputs.trigger.version }}"
}
}
}
}

Workflow inputs

Workflow inputs (click to expand)

Pass inputs to your GitHub Actions workflow. Values can be static or dynamically resolved from workflow outputs:

{
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "my-repo",
"workflow": "build-and-deploy.yml",
"workflowInputs": {
"environment": "{{ .outputs.trigger.environment }}",
"version": "{{ .outputs.trigger.version }}",
"dry_run": "{{ .outputs.trigger.dryRun | tostring }}"
}
}
}
String inputs

GitHub Actions workflow inputs are always strings. Use JQ functions like tostring to convert non-string values.

Status reporting

Status reporting (click to expand)

By default, Port monitors the triggered workflow and updates the workflow node status when it completes. To opt out:

{
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "my-repo",
"workflow": "deploy.yml",
"reportWorkflowStatus": false
}
}

When reportWorkflowStatus is false, the node is left in progress after the workflow is dispatched, and it is up to you to report its outcome back to Port (for example, by calling the Port API from a step in your workflow).

When reportWorkflowStatus is true (the default), Port monitors the GitHub Actions workflow run via webhook events and reports success or failure when it completes.

Live events requirement

Automatic workflow status updates require live events to be enabled on the integration. Live events are enabled automatically for integrations hosted by Port, but must be manually configured for self-hosted installations.

Pull request actions​

Manage a pull request​

Create, update, close, or merge a pull request.

Opens a new pull request in a GitHub repository. Set integrationInvocationType to "create_pull_request".

Execution properties

FieldTypeDescription
orgstringRequired. GitHub organization or user that owns the repository.
repostringRequired. Repository name.
titlestringRequired. Title of the pull request.
headstringRequired. Branch where your changes are implemented.
basestringRequired. Branch you want the changes pulled into.
bodystringDescription of the pull request.
draftbooleanWhether to create the pull request as a draft. Default: false.
Basic example (click to expand)

Open a pull request from a feature branch into main:

{
"identifier": "create-pull-request",
"title": "Open Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"title": "{{ .outputs.trigger.prTitle }}",
"head": "{{ .outputs.trigger.featureBranch }}",
"base": "main",
"body": "{{ .outputs.trigger.description }}",
"draft": false
}
}
}

Submit a pull request review​

Submits a review on a pull request: approve, request changes, or leave a comment. Set integrationInvocationType to "review_pull_request".

Execution properties

FieldTypeDescription
orgstringRequired. GitHub organization or user that owns the repository.
repostringRequired. Repository name.
prNumberstringRequired. The pull request number to review.
eventstringRequired. Review action: "APPROVE", "REQUEST_CHANGES", or "COMMENT".
bodystringReview comment text. Required when event is "REQUEST_CHANGES".
Review events
  • APPROVE - approves the pull request. The body field is optional.
  • REQUEST_CHANGES - requests changes. The body field is required and should describe what needs to change.
  • COMMENT - leaves a general review comment without approving or requesting changes.
Basic example (click to expand)

Submit an approval review on a pull request:

{
"identifier": "review-pull-request",
"title": "Review Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "review_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"prNumber": "{{ .outputs.trigger.prNumber }}",
"event": "APPROVE",
"body": "Looks good to me!"
}
}
}

Pull request comments​

Create, edit, or delete comments on a pull request.

Adds a comment to a pull request. Set integrationInvocationType to "create_pr_comment".

Execution properties

FieldTypeDescription
orgstringRequired. GitHub organization or user that owns the repository.
repostringRequired. Repository name.
prNumberstringRequired. The pull request number to comment on.
bodystringRequired. The comment text.
Basic example (click to expand)

Add a comment to a pull request:

{
"identifier": "create-pr-comment",
"title": "Comment on Pull Request",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_pr_comment",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"prNumber": "{{ .outputs.trigger.prNumber }}",
"body": "{{ .outputs.trigger.comment }}"
}
}
}

Issue actions​

Manage an issue​

Create, edit, or close an issue.

Creates a new issue in a GitHub repository. Set integrationInvocationType to "create_issue".

Execution properties

FieldTypeDescription
orgstringRequired. GitHub organization or user that owns the repository.
repostringRequired. Repository name.
titlestringRequired. Title of the issue.
bodystringDescription of the issue.
labelsarrayLabels to apply to the issue.
assigneesarrayGitHub usernames to assign to the issue.
Basic example (click to expand)

Create an issue with labels and an assignee:

{
"identifier": "create-issue",
"title": "Create Issue",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "your-installation-id",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_issue",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"title": "{{ .outputs.trigger.issueTitle }}",
"body": "{{ .outputs.trigger.description }}",
"labels": ["bug", "priority:high"],
"assignees": ["{{ .outputs.trigger.assignee }}"]
}
}
}

Complete workflow examples​

Deploy a service with GitHub Actions (click to expand)

A self-service deployment workflow that triggers GitHub Actions, waits for completion, and updates the service entity with deployment details:

{
"identifier": "deploy-with-github",
"title": "Deploy Service with GitHub Actions",
"icon": "Github",
"description": "Trigger a deployment using GitHub Actions",
"nodes": [
{
"identifier": "trigger",
"title": "Request Deployment",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"service": {
"type": "string",
"format": "entity",
"blueprint": "service",
"title": "Service"
},
"environment": {
"type": "string",
"title": "Environment",
"enum": ["staging", "production"]
},
"version": {
"type": "string",
"title": "Version",
"description": "Git tag or commit SHA"
}
},
"required": ["service", "environment", "version"]
}
}
},
{
"identifier": "trigger-deploy",
"title": "Trigger GitHub Deployment",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "gh-integration-123",
"integrationProvider": "github-ocean",
"integrationInvocationType": "dispatch_workflow",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.service }}",
"workflow": "deploy.yml",
"workflowInputs": {
"environment": "{{ .outputs.trigger.environment }}",
"version": "{{ .outputs.trigger.version }}"
},
"reportWorkflowStatus": true
}
}
},
{
"identifier": "update-entity",
"title": "Update Service Status",
"config": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "service",
"mapping": {
"identifier": "{{ .outputs.trigger.service }}",
"properties": {
"lastDeployedVersion": "{{ .outputs.trigger.version }}",
"lastDeployedEnvironment": "{{ .outputs.trigger.environment }}",
"lastDeployedAt": "{{ now | todateiso8601 }}"
}
}
}
}
],
"connections": [
{
"sourceIdentifier": "trigger",
"targetIdentifier": "trigger-deploy"
},
{
"sourceIdentifier": "trigger-deploy",
"targetIdentifier": "update-entity"
}
]
}
Open a pull request from a feature branch (click to expand)

A self-service workflow that opens a pull request from a feature branch:

{
"identifier": "create-github-pull-request-workflow",
"title": "Open a Pull Request",
"icon": "Github",
"description": "Open a pull request from a feature branch",
"nodes": [
{
"identifier": "trigger",
"title": "Request PR Creation",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"repository": {
"type": "string",
"title": "Repository"
},
"featureBranch": {
"type": "string",
"title": "Feature branch"
},
"prTitle": {
"type": "string",
"title": "PR title"
},
"description": {
"type": "string",
"title": "Description"
}
},
"required": ["repository", "featureBranch", "prTitle"]
}
}
},
{
"identifier": "create-github-pull-request",
"title": "Open Pull Request",
"icon": "Github",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "gh-integration-123",
"integrationProvider": "github-ocean",
"integrationInvocationType": "create_pull_request",
"integrationActionExecutionProperties": {
"org": "my-org",
"repo": "{{ .outputs.trigger.repository }}",
"title": "{{ .outputs.trigger.prTitle }}",
"head": "{{ .outputs.trigger.featureBranch }}",
"base": "main",
"body": "{{ .outputs.trigger.description }}"
}
}
}
],
"connections": [
{
"sourceIdentifier": "trigger",
"targetIdentifier": "create-github-pull-request"
}
]
}

Identity propagation​

Identity propagation lets a workflow integration action call the downstream platform as the user who triggered the run.

Availability

Identity propagation is only supported on self-hosted Ocean integrations.

How it works​

When a node run needs authentication, Port sends Ocean a short-lived OIDC token. Ocean checks its vault for a token stored for the triggering user. If none exists, the run pauses and prompts the user to authenticate through an OAuth flow hosted by Ocean. Once approved, Ocean stores the token in the user's vault entry, resumes the run, and executes the action with the user's own credentials.

The user sees a waiting for authentication state on the node, along with an Authenticate action in the workflow run page and in an Inbox notification.

Requirements on Ocean​

  • Actions processing enabled (OCEAN__ACTIONS_PROCESSOR__ENABLED=true, or Helm actionsProcessor.enabled=true).
  • Identity propagation enabled (OCEAN__IDENTITY_PROPAGATION__ENABLED=true, or Helm identityPropagation.enabled=true). Helm fails install or upgrade if this is true without actionsProcessor.enabled and a public liveEvents.baseUrl.
  • A publicly reachable base URL (OCEAN__BASE_URL, or Helm liveEvents.baseUrl). Ocean registers {baseUrl}/v1/oauth-broker/authorize on startup. If the URL isn't public, the OAuth flow cannot be completed.
  • An OAuth application with the downstream provider, using {baseUrl}/v1/oauth-broker/callback as the redirect URI. Provider-specific setup steps are in the Setup section below.
  • OAuth app credentials on the integration. Set identityOauthClientId and identityOauthClientSecret (and identityOauthTenantId for Azure DevOps) in Helm integration.config / integration.secrets, or as OCEAN__INTEGRATION__CONFIG__IDENTITY_OAUTH_* in Docker. Authorize and token URLs come from the integration's existing host or tenant settings.
  • A vault for storing tokens (see below). AWS Secrets Manager is supported out of the box.

Each Ocean process hosts one integration and one OAuth provider. If you run more than one supported integration, each is a separate Ocean deployment with its own OAuth application and vault entries.

Restart the integration after changing OCEAN__BASE_URL so it re-registers its broker URL. A resync alone doesn't do this.

Helm example (OAuth client values are integration-specific; see Setup):

identityPropagation:
enabled: true
actionsProcessor:
enabled: true
liveEvents:
baseUrl: https://ocean.example.com

The vault​

Ocean stores each user's downstream token in a vault, keyed by organization, actor, and integration. Default is AWS Secrets Manager:

OCEAN__IDENTITY_PROPAGATION__VAULT__TYPE="aws_secrets_manager"
OCEAN__IDENTITY_PROPAGATION__VAULT__SECRET_PREFIX="port/tokens"
OCEAN__IDENTITY_PROPAGATION__VAULT__AWS_REGION="<your-region>"

Helm equivalent: identityPropagation.vault.type, identityPropagation.vault.secretPrefix, and identityPropagation.vault.awsRegion. Prefer an IAM role on the pod over static awsAccessKeyId / awsSecretAccessKey.

That role needs secretsmanager:CreateSecret, secretsmanager:PutSecretValue, and secretsmanager:GetSecretValue on {secretPrefix}/* (default port/tokens/*). Ocean writes {secretPrefix}/{orgId}/{actorId}/{target} on the first successful OAuth callback, then updates the same secret later. Without those three actions the callback cannot store the token, and the failure comes from the vault client.

Bringing your own vault​

Ocean only ships an AWS Secrets Manager vault by default. To use a different store (HashiCorp Vault, GCP Secret Manager, your own database, etc.), write your own vault client:

  1. Import VaultClient and TokenRecord from port_ocean.identity_propagation.vault.base.

  2. Create a class that subclasses VaultClient and implements its two methods, read and write, against your store.

  3. In your integration's startup code, assign an instance of your class to ocean.app.vault_client. Ocean calls this instance instead of the built-in AWS client.

    from port_ocean.identity_propagation.vault.base import VaultClient, TokenRecord

    class MyVaultClient(VaultClient):
    async def read(self, org_id: str, actor_id: str, target: str) -> TokenRecord | None:
    ... # look up and return the stored record, or None if there isn't one

    async def write(self, org_id: str, actor_id: str, target: str, record: TokenRecord) -> None:
    ... # store the record

    ocean.app.vault_client = MyVaultClient()

    TokenRecord holds access_token, an optional refresh_token, and an optional expires_at.

Networking requirements​

  • OCEAN__BASE_URL (Helm liveEvents.baseUrl) must be reachable from the browsers of everyone who triggers workflows with identity propagation enabled.
  • The same URL must be reachable from the downstream provider, since it redirects the user's browser back there after approval.
  • After OAuth, Ocean redirects the browser to Port's app. Set Helm port.appUrl (OCEAN__PORT__APP_URL) when that URL cannot be derived from port.baseUrl (for example staging, where api. does not map to app.).

Setup​

You don't create a new app for this. Instead, configure the same GitHub App your GitHub integration already created on install:

  1. Go to your GitHub organization's Settings > Developer settings > GitHub Apps, and select that app.

  2. Under Identifying and authorizing users, select Add redirect URI and enter {baseUrl}/v1/oauth-broker/callback, where {baseUrl} is your OCEAN__BASE_URL (Helm liveEvents.baseUrl).

  3. Copy the Client ID and generate a Client secret.

  4. Put those values on the integration. Authorize and token URLs are derived from githubHost.

    identityPropagation:
    enabled: true
    actionsProcessor:
    enabled: true
    liveEvents:
    baseUrl: https://ocean.example.com
    integration:
    config:
    identityOauthClientId: "<client-id>"
    secrets:
    identityOauthClientSecret: "<client-secret>"

    Set enableIdentityPropagation: true on the node's configuration.

Limitations​

Run expiry: Runs that remain unprocessed for more than 3 hours are automatically expired and will not be executed.