Skip to content

ci: workflow efficiency and external-contributor automation - #1897

Merged
LucasSantana-Dev merged 6 commits into
mainfrom
ci/workflow-efficiency
Jul 27, 2026
Merged

LucasSantana-Dev merged 6 commits into
mainfrom
ci/workflow-efficiency

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented Jul 27, 2026 •

Copy link
Copy Markdown
Owner

Summary

CI workflow efficiency refactor plus external-contributor automation. 24 workflows audited; dead weight removed, micro-workflows folded, duplication consolidated, deploy logic extracted to testable scripts.

External contributors

  • external-pr-notify.yml: Discord alert on external PR open/reopen/ready + daily digest of open external PRs
  • fork-ci-autoapprove.yml: auto-approves queued CI runs for returning contributors and CI_AUTO_APPROVE_AUTHORS allowlist; first-timers get a comment + Discord ping
  • pr-agent.yml: switched to pull_request_target so fork PRs actually get AI review (fork pull_request runs get no secrets); fixed concurrency group

Efficiency refactor (ADR: decisions/2026-07-27-ci-workflow-efficiency.md)

  • Deleted: vercel-deploy-watch.yml (dead; watched non-repo projects on a 15-min cron), Socket.dev no-op step, advisory TruffleHog step (secretlint + GitGuardian remain the blocking layer)
  • Folded into ci.yml: path-portability, madge (job named exactly madge / packages/bot, preserving the required check context), discord-player major-pin guard; deleted the 3 source workflows
  • Consolidated: labeler + pr-size into pr-labels.yml (fork-safe); mutation.yml 3 jobs into 1 matrix job; bundle-size dropped informational compressed-size job (kept size-limit gate); docker build retry duplication into composite action
  • deploy.yml 763 to 360 lines: webhook trigger, origin derivation, status polling, OAuth smokes extracted to scripts/deploy/*.sh (shellcheck-clean, mock-server tested); deploy.yml + deploy-staging.yml gained the checkout step they now need
  • Noise: renovate-health exits 0 when the tracking issue already exists; auto-update cron 15min to hourly; quality.yml no longer double-lints

Safety

  • All 6 required check contexts preserved by construction (verified against ruleset 12822499); no ruleset change needed
  • Everything that executes PR code stays on pull_request (GitHub-hosted runners, no secrets, read-only token); pull_request_target workflows never check out PR code
  • Full actionlint + YAML parse + shellcheck sweep clean

Test plan

  • actionlint clean on all 26 workflow files
  • shellcheck + bash -n clean on 4 new deploy scripts; mock-server functional tests (retry, backoff, error classification)
  • First live CI run on this PR exercises the folded madge/path-portability/pin-guard jobs
  • First release after merge exercises the extracted deploy scripts

Summary by cubic

Streamlined CI by consolidating workflows, removing dead jobs, and adding automation so external contributors’ fork PRs are visible and unblocked. Deploy logic is extracted into testable scripts; required checks and safety guarantees remain intact.

  • New Features

    • external-pr-notify.yml: Discord alert on external PR open/reopen/ready, plus daily digest.
    • fork-ci-autoapprove.yml: auto-approves queued CI for trusted external authors; first-timers get a comment.
    • pr-agent.yml: switched to pull_request_target so fork PRs receive reviews; fixed concurrency grouping to key by PR number.
    • pr-labels.yml: unified path-based and size labeling in one fork-safe workflow.
  • Refactors

    • Folded path-portability.yml, madge.yml, and the discord-player pin guard into ci.yml (installs ripgrep/jq); removed queueresolver-canary.yml.
    • Converted three mutation jobs into a single matrix job; kept per-package caches/artifacts.
    • Removed dead/noisy items: vercel-deploy-watch.yml, Socket.dev no-op, advisory TruffleHog step; renovate-health.yml now exits 0 when its tracking issue exists; auto-update cron moved to hourly; quality.yml no longer double-lints.
    • Simplified bundle-size.yml by dropping the informational compressed-size job (kept size-limit gate).
    • Added Docker build service composite action (.github/actions/docker-build-service) to dedupe Docker Buildx setup and retries.
    • Cut deploy.yml from ~763 to ~360 lines; extracted webhook trigger, origin derivation, status polling, and OAuth smokes to scripts/deploy/*.sh; added checkout to deploy.yml and deploy-staging.yml.
    • Safety: preserved all required check contexts; PR code continues to run only under pull_request with no secrets; pull_request_target jobs never check out PR code; actionlint/YAML/shellcheck are clean.

Written for commit 071ba3b. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added notifications and daily digests for eligible external pull requests.
    • Added automatic approval handling for trusted fork contributions.
    • Added stronger CI checks for path portability, dependency compatibility, and circular dependencies.
    • Added automated OAuth and deployment readiness checks.
  • Improvements

    • Streamlined CI, mutation testing, Docker builds, labeling, and deployment workflows.
    • Reduced redundant monitoring and build jobs to improve workflow efficiency.
    • Improved deployment retries, status validation, and failure diagnostics.
  • Documentation

    • Expanded CI/CD guidance, contributor workflow details, and deployment troubleshooting instructions.

@LucasSantana-Dev
LucasSantana-Dev enabled auto-merge (squash) July 27, 2026 18:20
@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR consolidates CI workflows and gates, adds external pull-request automation, extracts deployment logic into reusable scripts, updates workflow scheduling and monitoring behavior, and documents the revised CI/CD structure.

Changes

CI and pull-request automation

Layer / File(s) Summary
CI gates and build orchestration
.github/actions/docker-build-service/action.yml, .github/workflows/ci.yml, .github/workflows/bundle-size.yml, .github/workflows/mutation.yml, .github/workflows/quality.yml, .github/workflows/renovate-health.yml, .github/workflows/auto-update-pr-branches.yml, .github/workflows/madge.yml, .github/workflows/path-portability.yml, .github/workflows/vercel-deploy-watch.yml, decisions/*, docs/CI_CD.md
Adds consolidated path, dependency, and circularity checks; extracts Docker builds into a composite action; matrixes mutation tests; removes redundant jobs and scanning workflows; adjusts scheduling, linting, and Renovate status handling; and records the refactor.
External PR automation and labeling
.github/workflows/external-pr-notify.yml, .github/workflows/fork-ci-autoapprove.yml, .github/workflows/pr-agent.yml, .github/workflows/pr-labels.yml, .github/workflows/labeler.yml, .github/workflows/pr-size.yml, docs/CI_CD.md
Adds external-PR notifications, daily digests, trusted fork CI approval, and unified labeling while moving automation to pull_request_target where applicable.

Deployment script extraction

Layer / File(s) Summary
Deployment helpers and workflow wiring
scripts/deploy/*, .github/workflows/deploy.yml, .github/workflows/deploy-staging.yml, docs/CI_CD.md
Moves webhook normalization, retries, OAuth validation, and homelab status polling into scripts; updates deployment workflows to check out the repository and invoke those scripts; and updates deployment troubleshooting documentation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DeployWorkflow
  participant TriggerWebhook
  participant Homelab
  participant GitHubStatus
  participant OAuthSmoke
  DeployWorkflow->>TriggerWebhook: trigger deployment
  TriggerWebhook->>Homelab: POST webhook request
  DeployWorkflow->>GitHubStatus: poll homelab-deploy status
  DeployWorkflow->>OAuthSmoke: run OAuth smoke checks
  OAuthSmoke->>Homelab: validate auth endpoints
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the two main themes: CI workflow efficiency refactors and external-contributor automation.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/workflow-efficiency

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Warnings
⚠️

Big PR — 1898 lines changed across 19 files. Consider splitting into smaller, reviewable chunks.

Generated by 🚫 dangerJS against 071ba3b

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (6)
scripts/deploy/trigger-deploy-webhook.sh (2)

25-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

try_webhook_url re-splits a payload the retry helper already parsed.

call_webhook_with_retry computes http/body, discards them, echoes the raw response, and try_webhook_url splits it again — then re-joins in reverse order for the caller to split a third time. Returning the code via a status/global (or having the retry helper emit code\nbody directly) would remove two of the three parse passes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/deploy/trigger-deploy-webhook.sh` around lines 25 - 59, Refactor the
response handoff between call_webhook_with_retry and try_webhook_url so the
parsed HTTP code and body are emitted in the caller’s expected order directly,
avoiding repeated tail/sed splitting and rejoining. Preserve retry decisions and
the existing final code/body output contract.

8-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fail with an explicit message when required env is missing.

With set -u, an unset WEBHOOK_SECRET/DEPLOY_SHA aborts inside call_webhook with a bare "unbound variable", after the script already printed "Triggering deploy webhook". The other extracted scripts use ${VAR:?...}; match that here.

♻️ Proposed refactor
+: "${WEBHOOK_URL:?WEBHOOK_URL is required}"
+: "${WEBHOOK_SECRET:?WEBHOOK_SECRET is required}"
+: "${DEPLOY_SHA:?DEPLOY_SHA is required}"
+
 echo "==> Triggering deploy webhook..."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/deploy/trigger-deploy-webhook.sh` around lines 8 - 12, Update the
deploy webhook flow around call_webhook and the DEPLOY_SHA usage to validate
required WEBHOOK_SECRET and DEPLOY_SHA environment variables explicitly with
parameter-expansion checks, producing clear variable-specific errors before
printing “Triggering deploy webhook” or invoking curl. Match the existing
${VAR:?} validation style used by the other extracted scripts.
scripts/deploy/derive-webhook-origin.sh (1)

13-21: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Wrap new URL() in try/catch for a clean failure message.

Invalid DEPLOY_WEBHOOK_URL currently surfaces as a raw Node stack trace in the deploy log. trigger-deploy-webhook.sh already handles this case gracefully; mirroring it here keeps diagnostics consistent.

♻️ Proposed refactor
     const raw = (process.env.ORIGIN_INPUT_URL ?? "").trim();
     if (!raw) {
         console.error("derive-webhook-origin.sh: empty URL");
         process.exit(1);
     }
-    const u = new URL(raw);
+    let u;
+    try {
+        u = new URL(raw);
+    } catch (error) {
+        console.error(`derive-webhook-origin.sh: invalid URL: ${error.message}`);
+        process.exit(1);
+    }
     console.log(`${u.protocol}//${u.host}`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/deploy/derive-webhook-origin.sh` around lines 13 - 21, Wrap the URL
construction in the inline Node script used by derive-webhook-origin.sh with
try/catch, preserving the existing empty-input validation and origin output for
valid URLs. On invalid input, catch the parsing error and emit a concise
contextual error message before exiting with failure, matching
trigger-deploy-webhook.sh’s graceful handling.
scripts/deploy/oauth-smoke.sh (1)

160-166: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use one temp file plus a trap instead of per-attempt mktemp/rm.

Three cleanup sites for the same file; an early set -e abort still leaks it.

Also applies to: 210-216

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/deploy/oauth-smoke.sh` around lines 160 - 166, Update the OAuth
redirect contract checks around the repeated curl attempts to create one
temporary headers file before the loop and register a trap that removes it on
exit, including set -e failures. Reuse that file for each attempt, remove the
per-attempt mktemp and rm calls, and apply the same cleanup approach to the
later check around the referenced second block.
.github/workflows/ci.yml (2)

145-165: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pass discord-player versions via env: instead of inline ${{ }} interpolation.

The extracted pinned/installed outputs are already constrained to \d+\.\d+\.\d+ by the grep -oP extraction, so the static-analysis template-injection flags (lines 157, 158, 161, 162, 165) aren't currently exploitable. Still, routing these values through env: rather than inline ${{ }} in the run: block is the standard hardening pattern and removes the injection shape entirely, independent of any future change to the extraction regex.

🔒 Proposed fix
             - name: Detect discord-player major bump beyond pinned
+              env:
+                  PINNED: ${{ steps.discord_player.outputs.pinned }}
+                  INSTALLED: ${{ steps.discord_player.outputs.installed }}
               run: |
-                  PINNED_MAJOR=$(echo "${{ steps.discord_player.outputs.pinned }}" | cut -d. -f1)
-                  INSTALLED_MAJOR=$(echo "${{ steps.discord_player.outputs.installed }}" | cut -d. -f1)
+                  PINNED_MAJOR=$(echo "$PINNED" | cut -d. -f1)
+                  INSTALLED_MAJOR=$(echo "$INSTALLED" | cut -d. -f1)
                   if [ "$INSTALLED_MAJOR" -gt "$PINNED_MAJOR" ]; then
                       echo "ERROR: discord-player MAJOR bump detected"
-                      echo "Pinned: ${{ steps.discord_player.outputs.pinned }} (major: $PINNED_MAJOR)"
-                      echo "Installed: ${{ steps.discord_player.outputs.installed }} (major: $INSTALLED_MAJOR)"
+                      echo "Pinned: $PINNED (major: $PINNED_MAJOR)"
+                      echo "Installed: $INSTALLED (major: $INSTALLED_MAJOR)"
                       exit 1
                   fi
-                  echo "discord-player version compatible (pinned: ${{ steps.discord_player.outputs.pinned }}, installed: ${{ steps.discord_player.outputs.installed }})"
+                  echo "discord-player version compatible (pinned: $PINNED, installed: $INSTALLED)"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 145 - 165, Update the “Detect
discord-player major bump beyond pinned” step to pass the discord-player outputs
through an env: mapping, then reference those environment variables inside the
shell script instead of inline ${{ steps.discord_player.outputs.* }}
interpolation. Use the environment values consistently for major extraction,
error messages, and the compatibility message while preserving the existing
comparison and failure behavior.

Source: Linters/SAST tools


236-294: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pin madge to an exact version used by this hard-gate job.

npm install --no-save madge@^7 --ignore-scripts installs madge outside the lockfile with an unpinned major range, so an unreviewed madge/transitive update can change the circular-dependency check output or behavior. Use an exact patch version instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 236 - 294, Update the “Install madge”
step in the madge job to install madge using an exact reviewed patch version
instead of the ^7 range. Keep the existing --no-save and --ignore-scripts flags
unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/deploy.yml:
- Around line 46-47: Disable credential persistence in the Checkout steps by
setting persist-credentials to false in .github/workflows/deploy.yml lines 46-47
and .github/workflows/deploy-staging.yml lines 38-39. In the staging workflow,
also consider pinning the checkout ref to the PR base SHA as requested.

In @.github/workflows/external-pr-notify.yml:
- Around line 51-56: Update both Discord POST fetch calls in the workflow to use
an AbortController with a short bounded timeout, passing its signal to fetch and
clearing the timeout after completion. Preserve the existing POST payload and
response error handling while ensuring stalled webhooks are aborted before the
workflow-level timeout.
- Around line 39-42: Bound the fully constructed Discord embed title in the
webhook payload before assigning it to embeds[0].title. Update the title
expression in the payload creation block to truncate the combined action, PR
number, and pr.title value to Discord’s allowed embed-title length, preserving
the existing title content when it is within the limit.

In @.github/workflows/pr-agent.yml:
- Around line 17-19: Update the concurrency group expression in the workflow to
use the pull request number for pull_request_target events and the issue number
for issue_comment events before falling back to github.ref. Preserve the
existing workflow prefix so comment-triggered runs are isolated per PR.

In `@docs/CI_CD.md`:
- Around line 51-61: The CI/CD Overview in docs/CI_CD.md is outdated relative to
the current workflow. Update its branch triggers and job descriptions to match
ci.yml, including the per-package checks and Quality Gates, and remove the
obsolete E2E claim unless you clearly identify its current location or fallback.

In `@scripts/deploy/oauth-smoke.sh`:
- Around line 117-145: Update the inline Node.js validation in the
expected_values assignment so invalid JSON and missing auth fields write their
diagnostic messages to stderr instead of stdout. Preserve the nonzero exits and
allow the existing auth_config_client_id/expected_redirect_uri guard to report
the failure.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 145-165: Update the “Detect discord-player major bump beyond
pinned” step to pass the discord-player outputs through an env: mapping, then
reference those environment variables inside the shell script instead of inline
${{ steps.discord_player.outputs.* }} interpolation. Use the environment values
consistently for major extraction, error messages, and the compatibility message
while preserving the existing comparison and failure behavior.
- Around line 236-294: Update the “Install madge” step in the madge job to
install madge using an exact reviewed patch version instead of the ^7 range.
Keep the existing --no-save and --ignore-scripts flags unchanged.

In `@scripts/deploy/derive-webhook-origin.sh`:
- Around line 13-21: Wrap the URL construction in the inline Node script used by
derive-webhook-origin.sh with try/catch, preserving the existing empty-input
validation and origin output for valid URLs. On invalid input, catch the parsing
error and emit a concise contextual error message before exiting with failure,
matching trigger-deploy-webhook.sh’s graceful handling.

In `@scripts/deploy/oauth-smoke.sh`:
- Around line 160-166: Update the OAuth redirect contract checks around the
repeated curl attempts to create one temporary headers file before the loop and
register a trap that removes it on exit, including set -e failures. Reuse that
file for each attempt, remove the per-attempt mktemp and rm calls, and apply the
same cleanup approach to the later check around the referenced second block.

In `@scripts/deploy/trigger-deploy-webhook.sh`:
- Around line 25-59: Refactor the response handoff between
call_webhook_with_retry and try_webhook_url so the parsed HTTP code and body are
emitted in the caller’s expected order directly, avoiding repeated tail/sed
splitting and rejoining. Preserve retry decisions and the existing final
code/body output contract.
- Around line 8-12: Update the deploy webhook flow around call_webhook and the
DEPLOY_SHA usage to validate required WEBHOOK_SECRET and DEPLOY_SHA environment
variables explicitly with parameter-expansion checks, producing clear
variable-specific errors before printing “Triggering deploy webhook” or invoking
curl. Match the existing ${VAR:?} validation style used by the other extracted
scripts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a0b7126a-646d-4249-8de4-129551ce7045

📥 Commits

Reviewing files that changed from the base of the PR and between 0528f66 and 61a5926.

📒 Files selected for processing (24)
  • .github/actions/docker-build-service/action.yml
  • .github/workflows/auto-update-pr-branches.yml
  • .github/workflows/bundle-size.yml
  • .github/workflows/ci.yml
  • .github/workflows/deploy-staging.yml
  • .github/workflows/deploy.yml
  • .github/workflows/external-pr-notify.yml
  • .github/workflows/fork-ci-autoapprove.yml
  • .github/workflows/labeler.yml
  • .github/workflows/madge.yml
  • .github/workflows/mutation.yml
  • .github/workflows/path-portability.yml
  • .github/workflows/pr-agent.yml
  • .github/workflows/pr-labels.yml
  • .github/workflows/quality.yml
  • .github/workflows/queueresolver-canary.yml
  • .github/workflows/renovate-health.yml
  • .github/workflows/vercel-deploy-watch.yml
  • decisions/2026-07-27-ci-workflow-efficiency.md
  • docs/CI_CD.md
  • scripts/deploy/derive-webhook-origin.sh
  • scripts/deploy/oauth-smoke.sh
  • scripts/deploy/trigger-deploy-webhook.sh
  • scripts/deploy/wait-homelab-status.sh
💤 Files with no reviewable changes (5)
  • .github/workflows/madge.yml
  • .github/workflows/vercel-deploy-watch.yml
  • .github/workflows/labeler.yml
  • .github/workflows/path-portability.yml
  • .github/workflows/queueresolver-canary.yml

Comment thread .github/workflows/deploy.yml
Comment thread .github/workflows/external-pr-notify.yml
Comment thread .github/workflows/external-pr-notify.yml Outdated
Comment thread .github/workflows/pr-agent.yml
Comment thread docs/CI_CD.md
Comment thread scripts/deploy/oauth-smoke.sh

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 24 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/workflows/fork-ci-autoapprove.yml
Comment thread scripts/deploy/oauth-smoke.sh
Comment thread .github/workflows/pr-agent.yml
Comment thread .github/workflows/ci.yml
Comment thread scripts/deploy/oauth-smoke.sh
Comment thread scripts/deploy/wait-homelab-status.sh
Comment thread .github/workflows/external-pr-notify.yml
Comment thread .github/workflows/external-pr-notify.yml
Comment thread docs/CI_CD.md
Comment thread scripts/deploy/oauth-smoke.sh

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: Auto-approval blocked by 14 unresolved issues from previous reviews.

Re-trigger cubic

@sonarqubecloud

Copy link
Copy Markdown

@LucasSantana-Dev
LucasSantana-Dev merged commit 41b48e2 into main Jul 27, 2026
45 checks passed
@LucasSantana-Dev
LucasSantana-Dev deleted the ci/workflow-efficiency branch July 27, 2026 19:02
LucasSantana-Dev added a commit that referenced this pull request Jul 30, 2026
## Summary

Follow-up to #1890. The v2.37.0 deploy failed, auto-rolled back to
v2.36.1, and nobody noticed for four days because a rolled-back deploy
read like a generic red check. This PR makes the rollback state
explicit:

- **Rollback-aware failure notification**: restores a `Notify failure`
step (`if: failure()`) in `deploy.yml`, backed by new
`scripts/deploy/notify-deploy-failure.sh`. On any failed deploy it
queries `/api/health/version` and annotates the run with the SHA
production actually serves: "auto-rollback restored service on `<sha>`"
vs. a generic failure, or "failure is in a post-deploy check" when
production does run the expected SHA.
- **Loud failure when production ends up older than the release**: the
script compares the running SHA against the deploy target via the GitHub
compare API; when the running SHA is strictly older (behind_by=0,
ahead_by>0) it emits `PRODUCTION IS BEHIND THE RELEASE: <sha> is N
commit(s) older than <tag>`. The `Validate deployed version` step's
final error now also names the last observed production SHA instead of a
bare mismatch.
- **Pollable deployed SHA**: `/api/health` now includes `commitSha`
(from the `COMMIT_SHA` env var already baked into the image via the
Dockerfile ARG/ENV, same source as `/api/health/version`), so a
scheduled check can alert when the running SHA drifts from the latest
tag.

Note: the `Notify failure` step referenced in the issue had been removed
in #1897; this restores it in rollback-aware form.

## Verification

- `npx jest tests/unit/routes/health.test.ts
tests/integration/routes/health.test.ts` in packages/backend: 2 suites,
20 tests passed (includes 2 new `/api/health` commitSha tests).
- `npm run type:check` (backend): clean; full monorepo type:check also
ran via pre-commit hook and passed.
- `eslint src/routes/health.ts`: clean (test file is ignored by the repo
eslint config, as before).
- `bash -n scripts/deploy/notify-deploy-failure.sh`: OK; deploy.yml
parses as valid YAML.
- Script branch behavior exercised locally with stubbed curl/gh:
rollback case, post-deploy-check case, and unreachable-health case all
emit the intended annotations and exit 0.

Closes #1892

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Make rolled-back deploys obvious in CI and surface the live commit SHA
so silent rollbacks don’t read like generic failures. Failed deploys now
say when production auto-rolled back, which SHA is serving, and when the
failure happened before rollout.

- **Bug Fixes**
- Restore a rollback-aware "Notify failure" step in deploy.yml using
scripts/deploy/notify-deploy-failure.sh. It reads /api/health/version to
annotate the run with the live commitSha, distinguishes auto-rollback
vs. post-deploy checks, adds a clear pre-deploy failure message when no
SHA is resolved, treats HTTP errors as unreachable, and warns when
production is behind the release.
- Expose commitSha on /api/health and /api/health/version (from
COMMIT_SHA) and add tests. The "Validate deployed version" step now
prints the expected and last-seen production SHA with a clear hint when
they differ.

<sup>Written for commit 07ab6ae.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/LucasSantana-Dev/Lucky/pull/1922?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Health checks now include a deployed commit identifier when available.
* Deployment failure notifications now distinguish pre-deployment
failures from post-deployment verification failures.
* **Bug Fixes**
* Improved “validate deployed version” timeout reporting by showing the
last served commit identifier (when detected) and clarifying rollback
vs. flaky checks.
* Deployment failure diagnostics better differentiate between
unreachable health checks and missing commit info.
* **Tests**
* Added unit test coverage for `/api/health` with `COMMIT_SHA` set and
unset.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant