Skip to content

Commit aa17c4d

Browse files
authored
chore(ci): deploy the dashboard agent dormant, drop the reviewer gate, add a ref input (#4710)
## Problem Every merge to main touching the agent queued a gated `staging`+`prod` deploy that sat `pending` on a reviewer approval nobody grants routinely. Because the gated runs never completed, they never drained the concurrency queue and cancelled each other, so the Actions tab filled with never-completing runs and the agent only ever actually deployed via a manual dispatch + approval. The reviewer gate bought nothing here: the agent deploys with `--skip-promotion`, so a deploy lands **dormant** and nothing goes live until the consuming webapp flips `DASHBOARD_AGENT_VERSION`. Promotion is already a deliberate act (the env-var flip); gating the dormant deploy on top of that just created the pile-up. ## Change - **Remove the reviewer gate** by dropping the required-reviewers rule on the `dashboard-agent-*` environments (repo-settings change, done). The `environment:` key **stays** so the per-environment scoped deploy token still resolves — no secret migration. - **`workflow_dispatch` `ref` input** — deploy a specific commit SHA, branch, or tag; defaults to the ref the run launches from. Checkout uses `github.event.inputs.ref || github.sha`. - **Require the ref to be an ancestor of `main`.** Constrains which commit gets deployed to merged code only. A push is always main's tip (passes trivially); a dispatched unmerged ref is rejected before the deploy step. Because an explicit `ref:` checkout doesn't create remote-tracking branches, `origin/main` is fetched explicitly before `git merge-base --is-ancestor`. - **`cancel-in-progress: false`** (kept). Cancelling the runner wouldn't stop the remote build (it finishes server-side), and a superseding concurrent deploy would race the same project's indexer. With the gate gone, deploys are short, so a brief queue can't pile up. - `max-parallel: 1` stays (parallel deploys of the same project race at the indexer). ## Owner actions (repo settings — not in the diff) 1. **Remove required-reviewers** on `dashboard-agent-staging` and `dashboard-agent-prod` — done. 2. **Add a deployment branch policy** on both environments restricting deployments to `main`. This is the authoritative token guard: `workflow_dispatch` runs the workflow file from the selected ref, so the in-file ancestor check alone can't protect `TRIGGER_ACCESS_TOKEN` (a branch could edit the check out). GitHub enforces the branch policy server-side against `GITHUB_REF` regardless of file contents. With it in place, the workflow only runs (and the token is only exposed) when dispatched from `main`, and the in-file check then constrains the independent `ref` input to merged commits. ## Pile-up root cause The stacking was caused by the **reviewer gate** (runs waited forever, so the queue never drained), not by `cancel-in-progress`. Removing the gate is what fixes it; `cancel-in-progress` stays `false`.
1 parent 967dedc commit aa17c4d

1 file changed

Lines changed: 51 additions & 4 deletions

File tree

.github/workflows/dashboard-agent-deploy.yml

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,19 @@ name: "🤖 Deploy dashboard agent"
33
# Deploys the @internal/dashboard-agent chat.agent to its Trigger.dev project
44
# with --skip-promotion, so a deploy never becomes "current" on its own. The
55
# consuming app cuts over by pinning DASHBOARD_AGENT_VERSION to the new version.
6-
# Runs a leg per environment (staging + prod), each gated by its own environment;
7-
# a push to main that touches the agent or its store triggers both. Version
8-
# numbers are per-environment, so pin each environment to its own leg's version.
6+
# Runs a leg per environment (staging + prod); a push to main that touches the
7+
# agent or its store deploys both. Version numbers are per-environment, so pin
8+
# each environment to its own leg's version.
9+
#
10+
# The deploy lands dormant, so it doesn't need a reviewer gate: nothing goes live
11+
# until DASHBOARD_AGENT_VERSION is flipped. The `environment:` below is kept only
12+
# to scope the deploy token per environment; its required-reviewers rule is
13+
# removed in repo settings so pushes deploy unattended. workflow_dispatch takes an
14+
# optional ref (SHA, branch, or tag) to deploy a specific commit instead of head.
15+
#
16+
# The deployed ref must be an ancestor of main, so only reviewed, merged code ever
17+
# runs with the deploy token (the checked-out build + trigger.config.ts execute
18+
# with it). A push is always on main; a dispatched ref is checked before deploy.
919

1020
on:
1121
push:
@@ -14,6 +24,11 @@ on:
1424
- "internal-packages/dashboard-agent/**"
1525
- "internal-packages/dashboard-agent-db/**"
1626
workflow_dispatch:
27+
inputs:
28+
ref:
29+
description: "Commit SHA, branch, or tag to deploy. Defaults to the ref the workflow runs from."
30+
required: false
31+
type: string
1732

1833
permissions: {}
1934

@@ -27,9 +42,15 @@ jobs:
2742
max-parallel: 1
2843
matrix:
2944
environment: [staging, prod]
30-
# Per-environment reviewer gate + source of the scoped deploy PAT.
45+
# Kept to scope the deploy token per environment. The required-reviewers rule
46+
# on these environments is removed in repo settings, so this no longer gates.
3147
environment: dashboard-agent-${{ matrix.environment }}
3248
concurrency:
49+
# Queue a superseding deploy behind an in-flight one; do NOT cancel it.
50+
# Cancelling the runner wouldn't stop the remote build (it finishes
51+
# server-side), and a second concurrent deploy of the same project would
52+
# race the indexer. Deploys are short now the gate is gone, so a brief queue
53+
# is fine and can't pile up.
3354
group: dashboard-agent-deploy-${{ matrix.environment }}
3455
cancel-in-progress: false
3556
permissions:
@@ -41,8 +62,34 @@ jobs:
4162
- name: Checkout
4263
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
4364
with:
65+
# push: the pushed commit. workflow_dispatch: the input ref if given,
66+
# otherwise the head of the ref the run was launched from.
67+
ref: ${{ github.event.inputs.ref || github.sha }}
68+
# Full history so the ancestor-of-main check below can find a merge base.
69+
fetch-depth: 0
4470
persist-credentials: false
4571

72+
- name: Require the ref to be an ancestor of main
73+
# The deploy token runs the checked-out code, so refuse anything that
74+
# hasn't landed on main. A push is main's tip (ancestor of itself); this
75+
# only ever rejects a dispatched, unmerged ref.
76+
#
77+
# NOTE: this in-file check only constrains WHICH commit is deployed. It
78+
# can't protect the token on its own, because workflow_dispatch runs the
79+
# workflow file from the selected ref. The real guard is the deployment
80+
# branch policy on the dashboard-agent-* environments (main only), set in
81+
# repo settings, which GitHub enforces server-side against GITHUB_REF.
82+
run: |
83+
set -euo pipefail
84+
# An explicit `ref:` checkout doesn't create remote-tracking branches,
85+
# so fetch main before comparing against it.
86+
git fetch --no-tags --quiet origin +refs/heads/main:refs/remotes/origin/main
87+
if ! git merge-base --is-ancestor HEAD origin/main; then
88+
echo "::error::Refusing to deploy $(git rev-parse HEAD): not an ancestor of origin/main. Only merged code can be deployed."
89+
exit 1
90+
fi
91+
echo "$(git rev-parse --short HEAD) is an ancestor of origin/main"
92+
4693
- name: Setup pnpm
4794
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
4895
with:

0 commit comments

Comments
 (0)