From 700c57f4f327282bd55e3752acda2958d54cf331 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Sun, 15 Feb 2026 10:24:20 +0100 Subject: [PATCH 1/6] Do start/end-change processing in the background (cli) (#3711) This is based on https://github.com/overmindtech/workspace/pull/3709 and combines all CLI changes from https://github.com/overmindtech/workspace/pull/3701 into a single commit. https://github.com/overmindtech/workspace/pull/3710 needs to be deployed before this can pass the e2e tests. --- > [!NOTE] > **Medium Risk** > Changes behavior of change lifecycle operations (start/end) and modifies worker retry/terminal handling, which can affect state transitions and job/flag correctness if edge cases are missed. > > **Overview** > **CLI start/end-change now runs in the background by default.** `start-change` and `end-change` switch from streaming RPCs to `StartChangeSimple`/`EndChangeSimple`, returning immediately and optionally polling `GetChange` when `--wait-for-snapshot` is set. > > **End-change UUID resolution is made race-safe.** The CLI stops client-side status checking for end-change (adds `getChangeUUID`) and relies on server-side atomic validation/queuing. > > **Snapshot worker failure semantics are unified.** Start/end snapshot workers now use a shared `snapshotWorkerRun` wrapper that treats validation/snapshot/DB errors (and panics) as retryable until the final attempt, then force-completes the status transition and clears in-progress flags; start-change also best-effort consumes any queued end-change on force-complete. GitHub composite actions gain a `wait-for-snapshot` input that forwards to the CLI. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 450bb313724a2f4aea5aa14a8de609750c6b7a99. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: c82af9fd0a6ec952c94cfec93847ec58209f69a7 --- end-change/action.yml | 12 +++++++++++- start-change/action.yml | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/end-change/action.yml b/end-change/action.yml index 3463575..4e10db2 100644 --- a/end-change/action.yml +++ b/end-change/action.yml @@ -18,6 +18,10 @@ inputs: app: description: "The Overmind instance to connect to. Defaults to `https://app.overmind.tech`" required: false + wait-for-snapshot: + description: "Wait for the snapshot to complete before returning. Defaults to false." + required: false + default: "false" runs: using: composite @@ -40,7 +44,13 @@ runs: app_arg="--app ${{ inputs.app }}" fi + wait_arg="" + if [ "${{ inputs.wait-for-snapshot }}" = "true" ]; then + wait_arg="--wait-for-snapshot" + fi + ./overmindtech/overmind changes end-change \ --ticket-link "$ticket_link" \ --log '${{ inputs.log }}' \ - $app_arg + $app_arg \ + $wait_arg diff --git a/start-change/action.yml b/start-change/action.yml index ce83367..8ff2b3d 100644 --- a/start-change/action.yml +++ b/start-change/action.yml @@ -18,6 +18,10 @@ inputs: app: description: "The Overmind instance to connect to. Defaults to `https://app.overmind.tech`" required: false + wait-for-snapshot: + description: "Wait for the snapshot to complete before returning. Defaults to false." + required: false + default: "false" runs: using: composite @@ -40,7 +44,13 @@ runs: app_arg="--app ${{ inputs.app }}" fi + wait_arg="" + if [ "${{ inputs.wait-for-snapshot }}" = "true" ]; then + wait_arg="--wait-for-snapshot" + fi + ./overmindtech/overmind changes start-change \ --ticket-link "$ticket_link" \ --log '${{ inputs.log }}' \ - $app_arg + $app_arg \ + $wait_arg From 941032cdfe7671a036ed3269365a698bac9224d8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:07:31 +0000 Subject: [PATCH 2/6] chore(deps): update github actions (major) (#4139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/cache](https://redirect.github.com/actions/cache) | action | major | `v4` → `v5` | | [actions/checkout](https://redirect.github.com/actions/checkout) | action | major | `v4` → `v6` | | [actions/upload-artifact](https://redirect.github.com/actions/upload-artifact) | action | major | `v6` → `v7` | | [actions/upload-artifact](https://redirect.github.com/actions/upload-artifact) | action | major | `v4` → `v7` | | [aws-actions/configure-aws-credentials](https://redirect.github.com/aws-actions/configure-aws-credentials) | action | major | `v5` → `v6` | | [crazy-max/ghaction-import-gpg](https://redirect.github.com/crazy-max/ghaction-import-gpg) | action | major | `v6` → `v7` | | [dawidd6/action-download-artifact](https://redirect.github.com/dawidd6/action-download-artifact) | action | major | `v12` → `v16` | | [docker/login-action](https://redirect.github.com/docker/login-action) | action | major | `v3` → `v4` | | [goreleaser/goreleaser-action](https://redirect.github.com/goreleaser/goreleaser-action) | action | major | `v6` → `v7` | | [hashicorp/setup-terraform](https://redirect.github.com/hashicorp/setup-terraform) | action | major | `v3` → `v4` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/370) for more information. --- ### Release Notes
actions/cache (actions/cache) ### [`v5`](https://redirect.github.com/actions/cache/compare/v4...v5) [Compare Source](https://redirect.github.com/actions/cache/compare/v4...v5)
actions/checkout (actions/checkout) ### [`v6`](https://redirect.github.com/actions/checkout/compare/v5...v6) [Compare Source](https://redirect.github.com/actions/checkout/compare/v5...v6) ### [`v5`](https://redirect.github.com/actions/checkout/compare/v4...v5) [Compare Source](https://redirect.github.com/actions/checkout/compare/v4...v5)
actions/upload-artifact (actions/upload-artifact) ### [`v7`](https://redirect.github.com/actions/upload-artifact/compare/v6...v7) [Compare Source](https://redirect.github.com/actions/upload-artifact/compare/v6...v7)
aws-actions/configure-aws-credentials (aws-actions/configure-aws-credentials) ### [`v6`](https://redirect.github.com/aws-actions/configure-aws-credentials/compare/v5...v6) [Compare Source](https://redirect.github.com/aws-actions/configure-aws-credentials/compare/v5...v6)
crazy-max/ghaction-import-gpg (crazy-max/ghaction-import-gpg) ### [`v7`](https://redirect.github.com/crazy-max/ghaction-import-gpg/compare/v6...v7) [Compare Source](https://redirect.github.com/crazy-max/ghaction-import-gpg/compare/v6...v7)
dawidd6/action-download-artifact (dawidd6/action-download-artifact) ### [`v16`](https://redirect.github.com/dawidd6/action-download-artifact/releases/tag/v16) [Compare Source](https://redirect.github.com/dawidd6/action-download-artifact/compare/v15...v16) #### What's Changed - build(deps): bump minimatch by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​374](https://redirect.github.com/dawidd6/action-download-artifact/pull/374) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​375](https://redirect.github.com/dawidd6/action-download-artifact/pull/375) **Full Changelog**: ### [`v15`](https://redirect.github.com/dawidd6/action-download-artifact/releases/tag/v15) [Compare Source](https://redirect.github.com/dawidd6/action-download-artifact/compare/v14...v15) #### What's Changed - build(deps): bump [@​actions/artifact](https://redirect.github.com/actions/artifact) from 6.0.0 to 6.1.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​369](https://redirect.github.com/dawidd6/action-download-artifact/pull/369) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​370](https://redirect.github.com/dawidd6/action-download-artifact/pull/370) - build(deps): bump fast-xml-parser from 5.3.4 to 5.3.6 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​371](https://redirect.github.com/dawidd6/action-download-artifact/pull/371) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​372](https://redirect.github.com/dawidd6/action-download-artifact/pull/372) **Full Changelog**: ### [`v14`](https://redirect.github.com/dawidd6/action-download-artifact/releases/tag/v14) [Compare Source](https://redirect.github.com/dawidd6/action-download-artifact/compare/v13...v14) ##### What's Changed - build(deps): bump fast-xml-parser from 5.3.3 to 5.3.4 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​367](https://redirect.github.com/dawidd6/action-download-artifact/pull/367) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​368](https://redirect.github.com/dawidd6/action-download-artifact/pull/368) **Full Changelog**: ### [`v13`](https://redirect.github.com/dawidd6/action-download-artifact/releases/tag/v13) [Compare Source](https://redirect.github.com/dawidd6/action-download-artifact/compare/v12...v13) #### What's Changed - build(deps): bump [@​actions/artifact](https://redirect.github.com/actions/artifact) from 5.0.1 to 5.0.2 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​350](https://redirect.github.com/dawidd6/action-download-artifact/pull/350) - build(deps): bump [@​actions/github](https://redirect.github.com/actions/github) from 6.0.1 to 7.0.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​348](https://redirect.github.com/dawidd6/action-download-artifact/pull/348) - build(deps): bump [@​actions/core](https://redirect.github.com/actions/core) from 2.0.1 to 2.0.2 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​349](https://redirect.github.com/dawidd6/action-download-artifact/pull/349) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​351](https://redirect.github.com/dawidd6/action-download-artifact/pull/351) - build(deps): bump lodash from 4.17.21 to 4.17.23 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​353](https://redirect.github.com/dawidd6/action-download-artifact/pull/353) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​354](https://redirect.github.com/dawidd6/action-download-artifact/pull/354) - build(deps): bump [@​actions/github](https://redirect.github.com/actions/github) from 7.0.0 to 8.0.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​355](https://redirect.github.com/dawidd6/action-download-artifact/pull/355) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​356](https://redirect.github.com/dawidd6/action-download-artifact/pull/356) - build(deps): bump [@​actions/core](https://redirect.github.com/actions/core) from 2.0.2 to 2.0.3 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​359](https://redirect.github.com/dawidd6/action-download-artifact/pull/359) - build(deps): bump [@​actions/artifact](https://redirect.github.com/actions/artifact) from 5.0.2 to 6.0.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​361](https://redirect.github.com/dawidd6/action-download-artifact/pull/361) - build(deps): bump [@​actions/core](https://redirect.github.com/actions/core) from 2.0.3 to 3.0.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​360](https://redirect.github.com/dawidd6/action-download-artifact/pull/360) - build(deps): bump [@​actions/github](https://redirect.github.com/actions/github) from 8.0.0 to 9.0.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​357](https://redirect.github.com/dawidd6/action-download-artifact/pull/357) - Convert from CommonJS to ESM by [@​Copilot](https://redirect.github.com/Copilot) in [#​362](https://redirect.github.com/dawidd6/action-download-artifact/pull/362) - Fix ES module imports for [@​actions](https://redirect.github.com/actions) packages by [@​Copilot](https://redirect.github.com/Copilot) in [#​365](https://redirect.github.com/dawidd6/action-download-artifact/pull/365) - node\_modules: update by [@​dawidd6](https://redirect.github.com/dawidd6) in [#​366](https://redirect.github.com/dawidd6/action-download-artifact/pull/366) #### New Contributors - [@​Copilot](https://redirect.github.com/Copilot) made their first contribution in [#​362](https://redirect.github.com/dawidd6/action-download-artifact/pull/362) **Full Changelog**:
docker/login-action (docker/login-action) ### [`v4`](https://redirect.github.com/docker/login-action/compare/v3...v4) [Compare Source](https://redirect.github.com/docker/login-action/compare/v3...v4)
goreleaser/goreleaser-action (goreleaser/goreleaser-action) ### [`v7`](https://redirect.github.com/goreleaser/goreleaser-action/compare/v6...v7) [Compare Source](https://redirect.github.com/goreleaser/goreleaser-action/compare/v6...v7)
hashicorp/setup-terraform (hashicorp/setup-terraform) ### [`v4`](https://redirect.github.com/hashicorp/setup-terraform/compare/v3...v4) [Compare Source](https://redirect.github.com/hashicorp/setup-terraform/compare/v3...v4)
--- ### Configuration 📅 **Schedule**: Branch creation - "before 10am on friday" in timezone Europe/London, Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/overmindtech/workspace). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> GitOrigin-RevId: bb72c8548df9e4f118d526ca829620e5b6bac39d --- .github/workflows/selftest.yml | 10 +++++----- submit-plan/action.yml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/selftest.yml b/.github/workflows/selftest.yml index 94ed391..e4f5442 100644 --- a/.github/workflows/selftest.yml +++ b/.github/workflows/selftest.yml @@ -11,7 +11,7 @@ jobs: URL: ${{ vars.URL }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: ./install-cli with: @@ -26,12 +26,12 @@ jobs: - name: Cache Terraform Providers id: cache-terraform - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ./testmodule/.terraform key: ${{ runner.os }}-${{ hashFiles('./testmodule/.terraform.lock.hcl') }} - - uses: hashicorp/setup-terraform@v3 + - uses: hashicorp/setup-terraform@v4 with: terraform_wrapper: false @@ -44,14 +44,14 @@ jobs: terraform show -json tfplan > tfplan.json - name: Upload Example GitHub Data - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: ${{ !env.ACT }} # skip during local actions testing with: name: github_event.json path: ${{ github.event_path }} - name: Upload Example Plan Data - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: ${{ !env.ACT }} # skip during local actions testing with: name: tfplan.json diff --git a/submit-plan/action.yml b/submit-plan/action.yml index 7cdb4ee..36ba30f 100644 --- a/submit-plan/action.yml +++ b/submit-plan/action.yml @@ -162,13 +162,13 @@ runs: number: ${{ inputs.number }} - name: Upload change-url as file - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: overmind-change-url.txt path: ./overmindtech/change-url - name: Upload ticket-link as file - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: overmind-ticket-link.txt path: ./overmindtech/ticket-link From 44ba72a17e84b31c3105be3528d6ec3363cf6df3 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Tue, 10 Mar 2026 11:53:59 +0100 Subject: [PATCH 3/6] [ENG-3049] Add CI workflow for deploy/meta (#4197) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add a GitHub Actions CI workflow for `deploy/meta/` Terraform, enabling automated plan on PRs and apply on merge - Migrate AWS providers from SSO profiles to cross-account `assume_role` for CI compatibility - Add GCP Workload Identity Federation pool in `ovm-infra` with cross-project IAM bindings ## Linear Ticket - **Ticket**: [ENG-3049](https://linear.app/overmind/issue/ENG-3049) — Phase 1: CI workflow for deploy/meta - **Purpose**: Automate meta Terraform plan/apply via CI, unblocking Phase 2 (meta notifications via Chatbot) - **Related**: [ENG-2905](https://linear.app/overmind/issue/ENG-2905) (project plan), [ENG-2906](https://linear.app/overmind/issue/ENG-2906) (plan approval) ## Changes ### Terraform (requires manual bootstrap apply before CI works) - **`deploy/meta/main.tf`**: New `terraform-meta` IAM role (OIDC-assumable, `AdministratorAccess`), root-level Google provider for `ovm-infra`, WIF pool + provider + IAM binding for meta CI - **`deploy/meta/deployenv/aws.tf`**: Provider changed from `profile = "sso-..."` to `assume_role` targeting `terraform-deploy`; added `AllowMetaCIRole` trust statement so `terraform-meta` can chain into target accounts - **`deploy/meta/deployenv/gcp.tf`**: Cross-project IAM binding granting the `ovm-infra` WIF identity admin access in each deployenv project - **`deploy/meta/deployenv/variables.tf`**: New `meta_gcp_project_number` variable for cross-project references - **`deploy/meta/citest.tf`**: Provider changed from `profile = "sso-ci-test"` to `assume_role`; passes `meta_gcp_project_number` to module ### CI Configuration - **`.github/workflows/terraform-meta.yml`**: New workflow with brain + execute jobs. Triggers on `deploy/meta/**` path changes. Includes Overmind integration (submit-plan, start/end-change, custom signal) to prod only, GCP WIF auth, and Slack notifications (start, success, failure, cancelled, plan status) - **`deploy/.github/env/op.meta.env`**: Non-sensitive 1Password references (`TERRAFORM_DEPLOY_ROLE`, `GCP_PROJECT_ID`, `GCP_PROJECT_NUMBER`) - **`deploy/.github/env/op.meta.secret`**: Sensitive 1Password references (`OVM_API_KEY_PROD`, `ADMIN_GITHUB_TOKEN`, Slack webhooks) ### Documentation - **`deploy/meta/README.md`**: Added CI workflow section; simplified manual process to only require `AWS_PROFILE=sso-infra` ## Bootstrap Requirement > **Important**: The first CI run on this PR will fail. The `terraform-meta` IAM role and provider migrations must be applied manually once before CI can take over. 1. `AWS_PROFILE=sso-infra gcloud auth application-default login && cd deploy/meta && terraform init && terraform apply` (four-eyes) 2. Store role ARN in 1Password: global vault → "Meta Deploy Role" → field "text" 3. Store ovm-infra project ID/number in 1Password: global vault → "Meta GCP Project" → fields "project_id" and "project_number" 4. After bootstrap, merge this PR — subsequent PRs will use CI ## Deviations from Approved Plan Implementation matches the approved plan — no material deviations. Made with [Cursor](https://cursor.com) --- > [!NOTE] > **High Risk** > Creates/changes CI-deploy IAM roles and trust relationships (including admin-level permissions) and enables automated Terraform `apply` on merge, so misconfiguration could impact production cloud resources. > > **Overview** > Adds a new `terraform-meta` GitHub Actions workflow that automatically runs Terraform `init/validate/plan` on PRs affecting `deploy/meta`, posts a sticky PR plan comment, uploads/downloads plan artifacts, and runs `apply` on merge (or via manual dispatch), with Slack and Overmind change notifications. > > Updates meta Terraform to support CI-based deployments by introducing a `terraform-meta` AWS IAM role (OIDC-assumable) and switching AWS providers from local SSO profiles to cross-account `assume_role`, including new trust allowing the meta CI role to assume target `terraform-deploy` roles. > > Adds/updates GCP Workload Identity Federation for the meta CI identity (new WIF pool/provider in `ovm-infra`, org-level IAM grants, and per-project cross-project admin bindings via a new `meta_gcp_project_number` input), bumps the Google provider lockfile, and adjusts the Drata module ref. Also extends `actions/submit-plan` to accept a configurable sticky comment header and adds 1Password-backed env/secret files for the workflow. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 63347e17fdeb5af8b5a008bc856fc553c8732074. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: 41226cc11e80d99ecdda0357f11c59dfe1ca798d --- submit-plan/action.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/submit-plan/action.yml b/submit-plan/action.yml index 36ba30f..24f25cd 100644 --- a/submit-plan/action.yml +++ b/submit-plan/action.yml @@ -35,6 +35,9 @@ inputs: tags: description: "A comma separated list of key=value tags to attach to the change" required: false + comment-header: + description: "Header for the sticky PR comment (used to distinguish multiple submit-plan calls on the same PR)" + default: change # ENG-1985, disabled until we decide how manual labels and manual tags should be handled. # labels: # description: "A comma separated list of name=color labels to attach to the change" @@ -157,7 +160,7 @@ runs: uses: marocchino/sticky-pull-request-comment@v2 if: ${{ steps.submit-plan.outputs.change-url != '' && inputs.fetch-change != 'false' }} with: - header: change + header: ${{ inputs.comment-header }} message: ${{ steps.submit-plan.outputs.message }} number: ${{ inputs.number }} From 79f64374063a37912e26331774acf958a7ffb83f Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 12 Mar 2026 16:17:52 +0100 Subject: [PATCH 4/6] Eng 3123 cli action comment wait (#4245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add `--comment` flag to CLI (`submit-plan`, `start-analysis`) and `--wait` flag to `get-change` to enable GitHub App PR commenting and control analysis polling - Add `comment` and `wait` inputs to the `submit-plan` composite action, with backward-compatible `fetch-change` deprecation - Migrate internal workflows (`terraform.yml`, `terraform-meta.yml`) to use the new inputs and disable legacy Slack plan notifications ## Linear Ticket - **Ticket**: [ENG-3123](https://linear.app/overmind/issue/ENG-3123/phase-4-cli-action-wire-comment-flag-auto-detect-and-skip-wait) — Phase 4: CLI + Action — Wire Comment Flag, Auto-Detect, and Skip Wait - **Project**: Multi-Plan Submission & GitHub App PR Commenting (Phase 4 of 5) ## Changes ### CLI (`cli/cmd/`) - `flags.go`: New `--comment` bool flag on `addAnalysisFlags`, requesting the GitHub App to post PR comments - `changes_submit_plan.go`: When `--comment` is set, outputs eval-able `CHANGE_URL` and `GITHUB_APP_ACTIVE` assignments instead of bare URL; passes `PostGithubComment` to `StartChangeAnalysis` RPC - `changes_start_analysis.go`: Same `--comment` behavior and `PostGithubComment` plumbing for the standalone `start-analysis` command - `changes_get_change.go`: Adds `--wait` flag (default `true`); skips `waitForChangeAnalysis` when `--wait=false`. Also fixes `MarkDeprecated` referencing wrong command (`submitPlanCmd` → `getChangeCmd`) - Housekeeping: replace `_ = MarkDeprecated`/`MarkHidden` with `cobra.CheckErr(...)` across 7 call sites ### Action (`actions/submit-plan/action.yml`) - New `comment` (default `"true"`) and `wait` (default `"false"`) inputs - `fetch-change` marked deprecated with backward-compatible shim - New `github-app-active` output; fixes `message` output (was incorrectly mapped to `change-url`) - When `comment=true`: tries `--comment` flag, falls back gracefully if CLI is older (`unknown flag` detection), and only fetches/posts sticky comment when the GitHub App is not active - Stderr isolation: redirects stderr to temp files (`submit-stderr.log`, `get-stderr.log`) instead of `2>&1` to prevent logrus output from polluting eval'd shell assignments or PR comment content ### Workflows (`.github/workflows/`) - `terraform.yml` and `terraform-meta.yml`: migrate from `fetch-change` to `comment`, add push-event guard, disable Slack plan notifications (GitHub App replaces them) ## Deviations from Approved Plan ### Additions not in the plan 1. **Stderr isolation in action shell logic** (`actions/submit-plan/action.yml`): The plan uses `eval "$(cli ...)"` directly. The implementation captures stdout to a variable with stderr redirected to temp files (`2>./overmindtech/submit-stderr.log`, `2>./overmindtech/get-stderr.log`), then evals the variable. This prevents logrus stderr lines (containing invalid bash identifiers like `change-url`) from breaking `eval`, and prevents log noise from leaking into PR comment content. 2. **Backward compatibility fallback for older CLIs** (`actions/submit-plan/action.yml`): The plan assumes the CLI supports `--comment` and `--wait`. The implementation adds fallback: if the CLI returns "unknown flag" (detected via the stderr temp file), it falls back to the legacy code path and logs a `::notice::`. This enables rolling out the action change before all CLI versions support the new flags. 3. **Push-event guard in workflows** (`.github/workflows/terraform.yml`, `terraform-meta.yml`): The plan removes `fetch-change` without adding an equivalent guard. The implementation passes `comment: ${{ github.event.number != '' }}` instead of unconditional `comment: true`, preventing comment logic from running on push events where there's no PR number. ### Minor approach changes 4. **Sticky comment condition**: The plan checks `inputs.comment != 'false'`. The implementation checks `steps.submit-plan.outputs.message != ''` — more robust since `message` is only populated when the change was actually fetched. 5. **`fetch-change` deprecation mapping**: The plan maps both `true` → `comment: true` and `false` → `comment: false`. The implementation only remaps the `false` case (setting `OVM_COMMENT='false'`), since `comment` already defaults to `"true"`. ### Omissions from the plan 6. **Part 8 — Linear issue for Slack notification feature**: The plan calls for creating a Linear issue titled "Investigate Slack notification feature for change analysis results". This was **not created** and should be filed separately. ## Test Plan - [x] Flag registration tests for `--comment` on `submit-plan` and `start-analysis` - [x] Flag registration test for `--wait` on `get-change` (default `true`) - [ ] Verify `submit-plan` action with `comment: true` on a PR event (GitHub App active path) - [ ] Verify `submit-plan` action with `comment: true` when GitHub App is not installed (sticky comment fallback) - [ ] Verify `submit-plan` action with older CLI that doesn't support `--comment` (graceful fallback) - [ ] Verify `comment: false` skips all PR commenting logic - [ ] Verify `wait: true` blocks until analysis completes and populates `message` output > [!NOTE] > **Medium Risk** > Changes GitHub Actions and CLI behavior around when to wait for Overmind analysis and where results are posted; misconfiguration could lead to missing plan feedback or altered CI timing. Touches deployment workflows but not Terraform execution logic itself. > > **Overview** > Routes Terraform plan reporting away from Slack and toward PR comments, wiring workflows to pass a new `comment` input to `actions/submit-plan` (and disabling the plan-to-Slack steps). > > Updates the `submit-plan` composite action and Overmind CLI to support `comment`/`wait` controls (deprecating `fetch-change`), including conditional fetching of analysis results, GitHub App vs sticky-comment handling, and new CLI flags/outputs (`--comment`, `get-change --wait`). Also tightens flag handling by checking errors when hiding/deprecating Cobra flags and adds targeted tests for the new flags. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1690417e01470b73fe9bd371b2eb1f878895d32d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). GitOrigin-RevId: a0fb20e395e0f0ffb62e32a3970c48dff980e184 --- submit-plan/action.yml | 126 ++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 27 deletions(-) diff --git a/submit-plan/action.yml b/submit-plan/action.yml index 24f25cd..ba30c11 100644 --- a/submit-plan/action.yml +++ b/submit-plan/action.yml @@ -23,9 +23,15 @@ inputs: log: description: The log level for the job default: info + comment: + description: "Post analysis results as a PR comment. Uses the Overmind GitHub App when installed (async, no CI wait), otherwise falls back to a sticky PR comment." + default: "true" + wait: + description: "Block until analysis completes and make results available as the `message` step output. Useful for gating deployments or including results in Slack messages." + default: "false" fetch-change: - description: Whether or not to fetch the change after submitting it. Set this to 'false' to avoid waiting for risk calculation when no human review is required. - default: true + description: "[Deprecated: use 'comment' and 'wait' instead] Whether or not to fetch the change after submitting it." + required: false number: description: "Pull request number to report results back." default: ${{ github.event.number }} @@ -50,7 +56,11 @@ outputs: message: description: "A markdown formatted message describing the current state of the change" - value: ${{ steps.submit-plan.outputs.change-url }} + value: ${{ steps.submit-plan.outputs.message }} + + github-app-active: + description: "Whether the GitHub App is handling PR commenting for this change" + value: ${{ steps.submit-plan.outputs.github-app-active }} runs: using: composite @@ -66,6 +76,16 @@ runs: declare -a args declare -a chg_args + # Resolve deprecated fetch-change to comment/wait + OVM_COMMENT='${{ inputs.comment }}' + OVM_WAIT='${{ inputs.wait }}' + if [ -n '${{ inputs.fetch-change }}' ]; then + echo "::warning::The 'fetch-change' input is deprecated. Use 'comment' and 'wait' instead." + if [ '${{ inputs.fetch-change }}' = 'false' ]; then + OVM_COMMENT='false' + fi + fi + # figure out the git change in this event if [ ${{ github.event_name }} = pull_request ]; then base="$(jq -r .pull_request.base.sha < ${{github.event_path}} )" @@ -74,16 +94,6 @@ runs: elif [ ${{ github.event_name }} = push ]; then base="$(jq -r .before < ${{github.event_path}} )" if [ "$base" = "0000000000000000000000000000000000000000" ]; then - # new branch was pushed, default to the repo's default branch as - # base for the diff - # - # Note that this is only the second-worst choice here, as this will - # show what's on the default branch, but not in this push as getting - # removed, even though a merge would keep it. To avoid _that_, we'd - # need to use the `merge-base` between the default branch and the - # current branch, but that would inversely _hide_ changes that are - # on the default branch but not in this push, making it easier to - # miss things for folks with a push-based workflow. base="${{github.event.repository.default_branch}}" prefix="origin/" fi @@ -130,25 +140,84 @@ runs: chg_args+=("--app=${{ inputs.app }}") fi - ./overmindtech/overmind changes submit-plan \ - --title "$title" \ - --description "$description" \ - --ticket-link "$ticket_link" \ - "${args[@]}" \ - '${{ inputs.plan-json }}' \ - > ./overmindtech/change-url + # Submit the plan. When comment is enabled, try --comment for eval-able output. + # Falls back to the old (no --comment) path if the CLI doesn't support it yet. + GITHUB_APP_ACTIVE=false + if [ "$OVM_COMMENT" = "true" ]; then + set +e + SUBMIT_OUTPUT=$(./overmindtech/overmind changes submit-plan \ + --comment \ + --title "$title" \ + --description "$description" \ + --ticket-link "$ticket_link" \ + "${args[@]}" \ + '${{ inputs.plan-json }}' 2>./overmindtech/submit-stderr.log) + SUBMIT_RC=$? + set -e + + if [ $SUBMIT_RC -eq 0 ]; then + eval "$SUBMIT_OUTPUT" + elif grep -q "unknown flag" ./overmindtech/submit-stderr.log 2>/dev/null; then + echo "::notice::CLI does not support --comment; falling back to legacy mode" + CHANGE_URL=$(./overmindtech/overmind changes submit-plan \ + --title "$title" \ + --description "$description" \ + --ticket-link "$ticket_link" \ + "${args[@]}" \ + '${{ inputs.plan-json }}') + else + cat ./overmindtech/submit-stderr.log >&2 + exit $SUBMIT_RC + fi + else + CHANGE_URL=$(./overmindtech/overmind changes submit-plan \ + --title "$title" \ + --description "$description" \ + --ticket-link "$ticket_link" \ + "${args[@]}" \ + '${{ inputs.plan-json }}') + fi + + echo "$CHANGE_URL" > ./overmindtech/change-url echo "ticket-link=${{ github.event.pull_request.html_url }}" >> $GITHUB_OUTPUT echo "${{ github.event.pull_request.html_url }}" >> ./overmindtech/ticket-link - echo "change-url=$(< ./overmindtech/change-url)" >> $GITHUB_OUTPUT + echo "change-url=$CHANGE_URL" >> $GITHUB_OUTPUT + echo "github-app-active=${GITHUB_APP_ACTIVE:-false}" >> $GITHUB_OUTPUT + + # Decide whether to fetch the change summary + should_fetch=false + if [ "$OVM_WAIT" = "true" ]; then + should_fetch=true + elif [ "${GITHUB_APP_ACTIVE:-false}" != "true" ] && [ "$OVM_COMMENT" = "true" ]; then + should_fetch=true + fi - if [ ${{ inputs.fetch-change }} != "false" ]; then - ./overmindtech/overmind changes get-change \ - --change "$(< ./overmindtech/change-url)" \ + if [ "$should_fetch" = "true" ]; then + set +e + GET_OUTPUT=$(./overmindtech/overmind changes get-change \ + --change "$CHANGE_URL" \ + --wait \ --format markdown \ --log '${{ inputs.log }}' \ - "${chg_args[@]}" \ - > ./overmindtech/message + "${chg_args[@]}" 2>./overmindtech/get-stderr.log) + GET_RC=$? + set -e + + if [ $GET_RC -eq 0 ]; then + echo "$GET_OUTPUT" > ./overmindtech/message + elif grep -q "unknown flag" ./overmindtech/get-stderr.log 2>/dev/null; then + echo "::notice::CLI does not support --wait on get-change; falling back to legacy mode" + ./overmindtech/overmind changes get-change \ + --change "$CHANGE_URL" \ + --format markdown \ + --log '${{ inputs.log }}' \ + "${chg_args[@]}" \ + > ./overmindtech/message + else + cat ./overmindtech/get-stderr.log >&2 + exit $GET_RC + fi DELIMITER="$(uuidgen)" echo "message<<$DELIMITER" >> $GITHUB_OUTPUT @@ -158,7 +227,10 @@ runs: - name: Post change message as sticky comment uses: marocchino/sticky-pull-request-comment@v2 - if: ${{ steps.submit-plan.outputs.change-url != '' && inputs.fetch-change != 'false' }} + if: >- + ${{ steps.submit-plan.outputs.change-url != '' + && steps.submit-plan.outputs.message != '' + && steps.submit-plan.outputs.github-app-active != 'true' }} with: header: ${{ inputs.comment-header }} message: ${{ steps.submit-plan.outputs.message }} From 572a39c9649eba237d8441b5b04641ef1bb67e83 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 12 Mar 2026 17:20:42 +0100 Subject: [PATCH 5/6] docs: add CLI command reference, multi-plan workflows, and GitHub App PR commenting (#4248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - New CLI command reference page covering all `overmind changes` subcommands (`submit-plan`, `start-analysis`, `get-change`, `start-change`, `end-change`) - Updated integration docs (Atlantis, GitHub Actions, GitHub App, custom integrations) with multi-plan workflow examples and GitHub App PR commenting capability - Updated `actions/README.md` with inputs/outputs tables and multi-plan CLI examples ## Changes Phase 5 (documentation) of the [Multi-Plan Submission + GitHub App PR Commenting](https://www.notion.so/overmindtech/Project-Plan-Multi-Plan-Submission-GitHub-App-PR-Commenting-320fb60360db8182a2c1dbd74cb5dfc5) project. All docs are customer-facing and follow terminology from `docs/domain-glossary.md`. - **New: `docs.overmind.tech/docs/cli/commands.md`** — Full CLI command reference for the `overmind changes` command group with flag tables, usage examples for single-plan and multi-plan workflows, and deployment lifecycle commands - **`docs.overmind.tech/docs/integrations/atlantis.md`** — Added "Parallel Planning (Multi-Project)" section with `atlantis.yaml` and `repos.yaml` post-workflow hook examples; updated "Waiting for Analysis Results" with GitHub App `--comment` as Option 1 - **`docs.overmind.tech/docs/integrations/github_app.md`** — New "PR Commenting" section covering async behavior, Actions/Atlantis integration, and `pull_requests:write` permissions; updated frontmatter, intro, and requirements - **`docs.overmind.tech/docs/integrations/github_actions.md`** — Expanded "Enhanced with GitHub App" with auto-detection behavior; added "Action Inputs" and "Action Outputs" tables with `fetch-change` deprecation notice - **`docs.overmind.tech/docs/integrations/build_your_own.md`** — Expanded from a 35-line stub to a full guide with single-plan, multi-plan, fetching results, and deployment lifecycle sections - **`actions/README.md`** — Added inputs/outputs tables, updated "Not using GitHub?" with `--comment` and multi-plan CLI examples, added GitHub App auto-detection note ## Deviations from Approved Plan Comparing against [Phase 5 plan](https://github.com/overmindtech/workspace/blob/dev/docs/plans/phase_5_documentation_5d9f3d95.plan.md): - **Part 2 — Atlantis basic setup not updated inline**: The plan calls for adding `--comment` directly to the basic setup YAML block. Instead, `--comment` is introduced as "Option 1: GitHub App (recommended)" in the "Waiting for Analysis Results" subsection. Same information, different structural placement — arguably clearer since it keeps the basic setup simple and presents `--comment` where users are deciding how to get results. - **Part 4 — "Complete Example Workflow" not updated**: The plan asks to add `comment` and `wait` inputs to the example workflow in `github_actions.md`. The existing complete example was left as-is; the new inputs are documented in the "Action Inputs" table and demonstrated in the "Using outputs in subsequent steps" snippet instead. - **Part 7 — Quality checks**: The plan calls for running `markdownlint`, `cspell`, and `lychee` on all changed files. It is not evident from the commit that these were run. Reviewer should verify or request a follow-up pass. All other parts (1, 3, 5, 6) match the approved plan with no material deviations. Co-authored-by: Cursor Agent GitOrigin-RevId: 6e39e8a8fb83f108365f0c70f33de254d5f66a8b --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 53ac687..c970552 100644 --- a/README.md +++ b/README.md @@ -25,20 +25,29 @@ Use this GitHub Action to automatically submit each PR's changes to [Overmind](h
Not using GitHub? - Currently we only have an action for GitHub, but don't fear! We have a CLI that you can use to integrate your own CI tooling: + We have a CLI that you can use to integrate your own CI tooling: 1. Download the CLI from here: 2. Set the `OVM_API_KEY` environment variable to your API Key - 3. Add a step to your pipeline to create a change: + 3. Submit a plan: ```shell ./overmind changes submit-plan \ - --title 'Pull request title goes here' \ - --description 'PR description goes here' \ + --comment \ --ticket-link 'link to PR goes here' \ - --plan-json 'path/to/plan.json' + tfplan.json ``` + For parallel planning workflows (multiple plans per change), use `--no-start` on each plan and `start-analysis` to trigger analysis once: + + ```shell + ./overmind changes submit-plan --no-start --ticket-link "$PR_URL" plan1.json + ./overmind changes submit-plan --no-start --ticket-link "$PR_URL" plan2.json + ./overmind changes start-analysis --comment --ticket-link "$PR_URL" + ``` + + See the [custom integrations docs](https://docs.overmind.tech/integrations/build_your_own) for more details. +

@@ -56,16 +65,41 @@ The `install` action installs the [`overmind`](https://github.com/overmindtech/c github-api-url: https://ghe.company.com/api/v3 # API for GitHub Enterprise Server (optional) ``` -The `submit-plan` action takes a JSON-formatted terraform plan, creates a Overmind Change for it, and runs Impact Analysis. +The `submit-plan` action takes a JSON-formatted terraform plan, creates an Overmind Change for it, and runs Impact Analysis. When the [Overmind GitHub App](https://docs.overmind.tech/integrations/github_app) is installed, the action exits immediately and the App posts results asynchronously as a PR comment. Without the App, it falls back to polling and posting a sticky comment. ```yaml - uses: overmindtech/actions/submit-plan@main id: submit-plan with: - ovm-api-key: ${{ secrets.OVM_API_KEY }} # Generated within Overmind - plan-json: ./tfplan.json # Location of the plan in JSON format + ovm-api-key: ${{ secrets.OVM_API_KEY }} + plan-json: ./tfplan.json ``` +## Inputs + +| Input | Default | Description | +| --- | --- | --- | +| `ovm-api-key` | (required) | Overmind API key. | +| `plan-json` | `tfplan.json` | Path to JSON plan file(s). Space-separated for multiple files. | +| `plan-output` | `tfplan.output` | Path to rendered plan output (`terraform plan \| tee FILE`). | +| `comment` | `"true"` | Post results as a PR comment. Uses GitHub App when installed, falls back to sticky comment. | +| `wait` | `"false"` | Block until analysis completes and populate the `message` output. | +| `tags` | | Comma-separated key=value tags. | +| `comment-header` | `change` | Sticky comment header (use different values for multiple plans on same PR). | +| `app` | | Overmind instance URL (Enterprise on-prem). | +| `number` | PR number | Pull request number. | +| `log` | `info` | Log level. | + +> **Deprecated:** `fetch-change` is deprecated. Use `comment` and `wait` instead. + +## Outputs + +| Output | Description | +| --- | --- | +| `change-url` | URL of the created change. | +| `message` | Markdown summary (populated when `wait: true` or sticky comment fallback). | +| `github-app-active` | `"true"` when the GitHub App is posting the PR comment. | + ## Pre-Mortem Example Copy this workflow to `.github/workflows/overmind.yml` to run `terraform init`, `terraform plan` and submit the planned changes to Overmind. From cbfff9746935b9a71bf5161e4edf4d8cc86deb30 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 12 Mar 2026 17:38:43 +0100 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20address=20PR=20review=20--=20restore?= =?UTF-8?q?=20comments,=20fix=20stdin=20examples,=20fix=20a=E2=80=A6=20(#4?= =?UTF-8?q?249)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …uth docs - Restore inline comments on submit-plan usage snippet in actions/README - Replace pipe-to-stdin examples with file path arguments (submit-plan does not support - for stdin) - Fix CLI commands page auth statement to mention interactive OAuth alongside API key auth --- > [!NOTE] > **Low Risk** > Documentation-only changes that update examples and wording; no runtime or API behavior is modified. > > **Overview** > Updates docs to match actual `submit-plan` usage: examples now pass JSON plan file paths (and show generating `tfplan.json`) instead of piping to stdin, including in Atlantis and custom integration guides. > > Clarifies authentication guidance by distinguishing CI `OVM_API_KEY` usage from interactive OAuth, and restores/expands inline comments in the GitHub Actions `submit-plan` snippet for input descriptions. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f4fcd63e31f759487e7c8bd1fe57301742f20544. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). Co-authored-by: Cursor Agent GitOrigin-RevId: 2c6a55541c494a3396bb0c99ead85f4537f518a0 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c970552..f3c729f 100644 --- a/README.md +++ b/README.md @@ -71,8 +71,8 @@ The `submit-plan` action takes a JSON-formatted terraform plan, creates an Overm - uses: overmindtech/actions/submit-plan@main id: submit-plan with: - ovm-api-key: ${{ secrets.OVM_API_KEY }} - plan-json: ./tfplan.json + ovm-api-key: ${{ secrets.OVM_API_KEY }} # Generated within Overmind + plan-json: ./tfplan.json # Location of the plan in JSON format ``` ## Inputs