Terrantula Actions (GitHub Actions)

An Action pairs a graph operation (create / update / transition an entity or relationship) with a trigger that does the real work against an external substrate. This page is the lookup reference for what each trigger does when an Action fires — the dispatch behavior, the flow, and the terminal states. For the full YAML field tables, see the Action schema.

INFO

Terrantula never runs terraform apply itself. Every substrate trigger either opens a pull request against your repo or asks a runner you control to plan/apply. The graph is a read-only projection of the resulting TF-derived state. Terrantula triggers and observes; your CI applies.

How an Action fires

When an Action is triggered (from the UI, the API, the CLI, or a cascade), the worker:

  1. Resolves the Action's parameters, recommendations, and any {{ secrets.* }} references in the trigger config.
  2. Interpolates the trigger fields against the run context (entity, parameters, recommendations, run — see Interpolation).
  3. Dispatches to the external substrate per the trigger.type.
  4. Stores substrate-specific identifiers (PR number, TFC run ID, …) in the ActionRun's metadata field.
  5. Transitions the ActionRun to running and the entity/relationship to its onTrigger state.

The ActionRun reaches a terminal state (succeeded / failed) when the substrate reports completion — by GitHub/Atlantis webhook, by polling, or by a callback. If nothing reports back, the reaper times the run out after the Action's timeout (default 60 minutes) and marks it failed.

Trigger types

TypeSubstrateWhat it does
pull-requestGitHubOpens a PR via the Git Data API; auto-completes on merge/close.
terraform-cloudTFC / HCP TerraformFires a run against a pre-existing workspace; polls to a terminal state.
atmos-workflowAtmosPOSTs to a customer-deployed runner that runs atmos workflow.
atlantisAtlantisOpens a PR (default) or calls Atlantis's API directly.
webhookGeneric HTTPCalls any URL with an interpolated payload; completion by callback.
noopnoneTransitions the run to succeeded immediately (cascade-only / in-Terrantula effects).

Substrate order follows the product commitment: Terraform first, Atmos as a peer substrate, OpenTofu second. All four substrate triggers are tier-1.


pull-request

Purpose. Open a GitHub pull request with file changes and wait for a human to merge or close it. The PR-based approval pattern is the core of the cross-team flow: a requesting team triggers the Action, the owning team gets a PR in their own repo and review queue, their existing pipeline applies, and Terrantula tracks the outcome.

Config. See the Action schema → pull-request for the full field table.

trigger:
  type: pull-request
  repo: my-org/infrastructure
  auth:
    type: token
    token: "{{ secrets.github-token }}"   # or use the GitHub App — see notes
  title: "Onboard {{ entity.properties.companyName }}"
  head: "terrantula/onboard-{{ entity.id }}"
  base: main
  files:
    - path: "tenants/{{ entity.id }}.yaml"
      content: |
        name: "{{ entity.properties.companyName }}"
  webhookSecret: "{{ secrets.github-webhook-secret }}"   # for auto-completion

Flow. The worker creates head from base via the Git Data API, commits all files, opens the PR, and stores { prNumber, prUrl, repo } in the ActionRun's metadata. On PR close:

  • Merged → ActionRun succeeded; entity/relationship transitions to onSuccess.
  • Closed without merge → ActionRun failed; transitions to onFailure.

Notes.

  • Auto-completion requires a GitHub webhook on the repo pointing at the per-action webhook route and the webhookSecret set — see Webhooks → PR-trigger webhook. Without it, the PR still opens but the run won't auto-complete.
  • Credentials. With the GitHub App linked to the project, omit auth.token and Terrantula mints an installation token. A static auth.token is the Sam-cohort escape hatch for GHE-Server / no-App setups.

terraform-cloud

Purpose. Fire a Terraform Cloud / HCP Terraform run against a pre-existing workspace. Terrantula never executes Terraform — TFC runs the plan/apply, Terrantula triggers and observes.

Config. See the Action schema → terraform-cloud for the full field table.

trigger:
  type: terraform-cloud
  organization: my-org
  workspaceName: tenant-onboard      # or workspaceId — exactly one
  apiToken: "{{ secrets.tfc-api-token }}"
  variables:                          # run-scoped, NON-sensitive only
    customer_id: "{{ parameters.customer_id }}"
  autoApply: false                    # default — plan-only
  waitForCompletion: true             # default — Terrantula polls

Flow. The worker resolves workspaceName to an ID, POSTs /api/v2/runs, stores { runId, runUrl, workspaceId, workspaceName, organization, status } in metadata, then polls GET /api/v2/runs/:id until a terminal status:

  • Success: applied, planned_and_finished, planned_and_saved, planned, policy_checked.
  • Failure: errored, discarded, canceled, force_canceled, policy_soft_failed.

Notes.

  • autoApply: false is plan-only. With the default, the entity transitions to onSuccess when the run reaches planned — the plan finished but the infrastructure has not yet been provisioned. Set autoApply: true if the entity should only transition once TFC reaches applied.
  • Run-scoped variables are cleartext in the TFC UI (sensitive: false). Never pass API keys/passwords here — configure those as workspace-level sensitive variables in TFC. Run-scoped variables are for routing data (tenant IDs, regions, plan tiers).
  • Terrantula does not create workspaces, upload config, or run apply. TFC pulls config from the workspace's VCS settings; configSource is informational.

atmos-workflow

Purpose. Invoke a named Atmos workflow on a runner you deploy. Atmos workflows mirror Terrantula Actions architecturally — both are named, parameterized invocations against a deployment target.

Config. See the Action schema → atmos-workflow for the full field table.

trigger:
  type: atmos-workflow
  workflow: provision-tenant
  stack: "tenant-{{ parameters.customer_id }}"
  runner:
    endpoint: https://atmos-runner.example.com/dispatch
    auth:
      type: bearer
      token: "{{ secrets.atmos-runner-token }}"
  variables:
    customer_id: "{{ parameters.customer_id }}"
  waitForCompletion: true

Flow. The trigger HTTP-POSTs a structured payload to runner.endpoint. The runner clones your Atmos repo, runs atmos workflow <name> -s <stack>, and POSTs back to the run's callback URL to signal completion.

Notes.

  • The runner is yours. Deploy the open-source reference terrantula-atmos-runner container, or a GitHub Actions / GitLab CI workflow template, and point the trigger at it. Terrantula never hosts the runner — this keeps the Atmos path runnable with zero SaaS dependencies.
  • SSRF guard. runner.endpoint is validated against the same internal-address blocklist as the Atlantis trigger.

atlantis

Purpose. Drive a customer-hosted Atlantis instance. Two modes.

Config. See the Action schema → atlantis for the full field table.

Pull-request mode (default). Terrantula opens a GitHub PR with the file changes; Atlantis picks it up via its own webhook subscription and runs plan/apply. Behaves like the pull-request trigger but is explicitly labeled for Atlantis; produces { mode: 'pull-request', prNumber, prUrl, repo } metadata. On merge, Terrantula's webhook transitions the run.

API-dispatch mode. Terrantula calls Atlantis's /api/plan or /api/apply endpoint directly (synchronous, no PR cycle), parses the project results, stores { mode: 'api-dispatch', command, projectResults, planOutput }, and POSTs the callback.

trigger:
  type: atlantis
  endpoint: https://atlantis.example.com   # customer-hosted; https:// required
  auth:
    type: token
    token: "{{ secrets.atlantis-token }}"  # X-Atlantis-Token header
  mode: api-dispatch
  repo: my-org/my-terraform-repo
  ref: main
  vcsType: Github
  project: "tenant-{{ parameters.customer_id }}"
  command: plan                            # 'plan' (default) or 'apply'

Notes.

  • Atlantis is always yours. Terrantula never hosts Atlantis or manages its atlantis.yaml — that stays in your repo (or is patched via the PR-trigger's file-patch operation). Even in api-dispatch mode, Atlantis runs the apply on its own infrastructure.
  • Auth is the X-Atlantis-Token header, set via Atlantis's --api-secret.
  • SSRF guard. endpoint requires https:// and is validated against the shared internal-address blocklist (loopback, link-local, RFC 1918, CGNAT, IPv6 ULA/multicast, IPv4-mapped IPv6).

Per-environment overrides

A single Action can override trigger fields per environment via envOverrides (different TFC workspaces / webhook URLs / repos in dev vs prod). Override fields are shallow-merged onto the base trigger at dispatch; the type must match the base trigger's type. See the Action schema → per-env overrides.