Skip to content

Split CI/CD workflows for ENSNode and ENSDb Playground deployments#2338

Draft
tk-o wants to merge 4 commits into
mainfrom
feat/ensdb-playground-deployment-prod-switch
Draft

Split CI/CD workflows for ENSNode and ENSDb Playground deployments#2338
tk-o wants to merge 4 commits into
mainfrom
feat/ensdb-playground-deployment-prod-switch

Conversation

@tk-o

@tk-o tk-o commented Jun 29, 2026

Copy link
Copy Markdown
Member

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • The ENSNode deployment can have the production workload switched between all cloud environments (blue, green, yellow).
  • The ENSDb Playground deployment can have the production workload switched between just blue environment and green environment.
  • The promote_vercel_deployment.sh script has been updated to allow sourcing the ENSNode version independently from the platform (Railway, Render) that the current production deployment runs on.

Why

  • The ENSNode deployment should be operated independently from the ENSDb Playground deployment.

Testing


Notes for Reviewer (Optional)

  • Currently, switching the ENSNode production workload to the yellow env will not automatically promote ENSAdmin app and ENSKit React Example app. The script promoting selected app deployments is tied to Railway platform and will not work for the yellow env (hosted on Render.com).
  • This PR requires ENSApi v1.17.0 deployed to production as the updated promote_vercel_deployment.sh script needs to use data model introduced in the v1.17.0.

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

Copilot AI review requested due to automatic review settings June 29, 2026 19:20
@changeset-bot

changeset-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: fd46b96

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment Jun 30, 2026 1:39pm
enskit-react-example.ensnode.io Ready Ready Preview, Comment Jun 30, 2026 1:39pm
ensnode.io Ready Ready Preview, Comment Jun 30, 2026 1:39pm
ensrainbow.io Ready Ready Preview, Comment Jun 30, 2026 1:39pm

@tk-o

tk-o commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

@greptile review

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Replaces Railway-based deployment inspection with ENSNode indexing-status API querying in the Vercel promotion action and script. Adds yellow environment support to the ENSNode switch workflow, removes Railway secrets, extracts ENSDb Playground Traefik routing into a new dedicated deploy_switch_ensdb_playground_environment.yml workflow.

Changes

Vercel Promotion: Railway → ENSNode Environment

Layer / File(s) Summary
promote_vercel_deployment action contract and script
.github/actions/promote_vercel_deployment/action.yml, .github/actions/promote_vercel_deployment/promote_vercel_deployment.sh
Action inputs drop railway_token/railway_environment_id and add ensnode_environment; env wiring passes ENSNODE_ENVIRONMENT. Script removes Railway GraphQL flow and replaces it with ENSNODE_ENVIRONMENT validation (green|blue|yellow) and an ENSNode indexing-status API curl/jq call to derive ENSINDEXER_IMAGE.

ENSNode + ENSDb Playground Workflow Updates

Layer / File(s) Summary
ENSNode switch workflow: yellow env, Railway removal, routing cleanup
.github/workflows/deploy_switch_ensnode_environment.yml
Adds yellow to workflow_dispatch options, drops RAILWAY_TOKEN from job env, updates SLACK_TITLE case statement to cover green/blue/yellow and exit 1 on unknown, removes ensdb-playground Traefik Redis SET, and updates Vercel promotion calls to pass ensnode_environment instead of Railway inputs.
New ENSDb Playground environment switch workflow
.github/workflows/deploy_switch_ensdb_playground_environment.yml
New workflow_dispatch workflow with green/blue target choice, job env setup, checkout, SLACK_TITLE computation with exit 1 on unknown, Redis-based Traefik routing update for ensdb-playground-router, and Slack notification.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as deploy_switch_ensnode_environment
  participant Action as promote_vercel_deployment
  participant ENSNodeAPI as ENSNode /indexing-status
  participant Skopeo as skopeo inspect
  participant Vercel as Vercel API

  Workflow->>Action: ensnode_environment=green|blue|yellow
  Action->>ENSNodeAPI: GET /indexing-status
  ENSNodeAPI-->>Action: ensIndexer version
  Action->>Skopeo: inspect ENSINDEXER_IMAGE
  Skopeo-->>Action: commit SHA
  Action->>Vercel: find deployment by SHA
  Vercel-->>Action: deployment matched
  Action->>Vercel: promote to production
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

  • namehash/ensnode#1587: Both PRs modify the ENSNode environment switch workflow's Redis/Traefik routing step — this PR removes the ensdb-playground router/service mapping while that PR adds v2-sepolia mappings.
  • namehash/ensnode#1722: Both PRs modify deploy_switch_ensnode_environment.yml to extend env-switch handling and Slack messaging.
  • namehash/ensnode#2321: This PR removes the ensdb-playground Traefik router/service Redis mapping from deploy_switch_ensnode_environment.yml while that PR adds the same mapping.

Poem

🐇 Hoppity hop, away with the rails,
No more Railway tokens or GraphQL trails!
ENSNode's own API shows the way,
Green, blue, and yellow all join the fray.
A playground workflow now stands on its own —
Every environment gets a burrow to call home! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title is concise and accurately reflects the main change: splitting deployment workflows for ENSNode and ENSDb Playground.
Description check ✅ Passed The description follows the required template and includes the summary, why, testing, notes, and blocking checklist sections.
✨ 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 feat/ensdb-playground-deployment-prod-switch

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR splits the “switch production environment” workflow so ENSNode routing can be switched independently of ENSDb Playground routing, and expands ENSNode’s switcher to support a third (yellow) environment.

Changes:

  • Add yellow as a selectable target environment for ENSNode switching, and remove ENSDb Playground routing from the ENSNode switch workflow.
  • Introduce a new, dedicated workflow to switch ENSDb Playground routing between blue/green.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
.github/workflows/deploy_switch_ensnode_environment.yml Adds yellow option + ENSNode-specific Slack titles; removes ENSDb Playground router switching from this workflow.
.github/workflows/deploy_switch_ensdb_playground_environment.yml New workflow to switch only the ENSDb Playground Traefik router between blue and green.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/deploy_switch_ensdb_playground_environment.yml
Comment thread .github/workflows/deploy_switch_ensnode_environment.yml
Comment thread .github/workflows/deploy_switch_ensdb_playground_environment.yml
@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR splits the previously unified environment-switch workflow into two independent workflows — one for ENSNode and one for ENSDb Playground — and replaces the Railway GraphQL API version lookup with a direct call to the ENSNode indexing-status HTTP endpoint.

  • New deploy_switch_ensdb_playground_environment.yml: handles only the ensdb-playground-router Traefik key, supports green/blue targets, sends a Slack notification on completion.
  • Updated deploy_switch_ensnode_environment.yml: adds yellow as a third routing target, removes ENSDb Playground routing, drops RAILWAY_TOKEN; the two Promote steps run unconditionally for all three targets including yellow (Render-hosted), which the PR notes explicitly acknowledge may fail for that environment.
  • Updated promote_vercel_deployment.sh: the Railway GraphQL call is replaced by curl https://api.alpha.ENV.ensnode.io/api/indexing-status | jq .stackInfo.ensIndexer.versionInfo.ensIndexer; environment validation and null/empty checks are correctly in place.

Confidence Score: 4/5

Safe to merge with awareness that triggering a yellow switch will leave the Promote steps in a broken state until a guard is added.

The two Promote steps in the ENSNode workflow run unconditionally for all three targets. When yellow is selected, the promote script calls https://api.alpha.yellow.ensnode.io/api/indexing-status — if that endpoint is unreachable (yellow runs on Render.com and may not be wired up), curl exits non-zero and the workflow fails after Traefik routing has already been switched, leaving no Slack notification and a failed run status. The author's own notes acknowledge this limitation. Green and blue paths are unaffected and the overall refactor is clean.

deploy_switch_ensnode_environment.yml — the unconditional Promote steps at lines 98–112 need a condition to skip or gracefully handle the yellow target.

Important Files Changed

Filename Overview
.github/actions/promote_vercel_deployment/action.yml Replaces railway_token + railway_environment_id inputs with a single ensnode_environment input; description text updated to match.
.github/actions/promote_vercel_deployment/promote_vercel_deployment.sh Replaces Railway GraphQL API lookup with a direct call to the ENSNode indexing-status HTTP endpoint; validates environment name before use; correct null/empty checks retained.
.github/workflows/deploy_switch_ensdb_playground_environment.yml New workflow splitting ENSDb Playground routing out of the ENSNode workflow; contains a misleading skopeo comment copy-pasted from the ENSNode workflow that does not apply here.
.github/workflows/deploy_switch_ensnode_environment.yml Adds yellow as a third routing target, removes ENSDb Playground routing (moved to its own workflow), and drops RAILWAY_TOKEN; Promote steps run unconditionally for all three targets including yellow (Render-hosted), which will fail when yellow's indexing-status endpoint is not reachable.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[workflow_dispatch] --> B{target}

    B -->|green / blue / yellow| C[Switch ENSNode Environment]
    B -->|green / blue| D[Switch ENSDb Playground Environment]

    C --> C1[Calculate env vars / SLACK_TITLE]
    C1 --> C2[Switch Traefik Routing\nAlpha / Mainnet / Sepolia / ENSRainbow]
    C2 --> C3[Promote ENSAdmin Vercel Deployment]
    C3 --> C4[Promote Example App Vercel Deployment]
    C4 --> C5[Send Slack Notification]

    D --> D1[Calculate env vars / SLACK_TITLE]
    D1 --> D2[Switch Traefik Routing\nensdb-playground-router]
    D2 --> D3[Send Slack Notification]

    C3 & C4 --> P[promote_vercel_deployment action]
    P --> P1[curl ENSNode indexing-status endpoint\nhttps://api.alpha.ENV.ensnode.io/api/indexing-status]
    P1 --> P2[Extract version → construct image tag]
    P2 --> P3[skopeo inspect → get commit SHA]
    P3 --> P4[Vercel API: find deployment by SHA]
    P4 --> P5[Vercel API: promote to production]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[workflow_dispatch] --> B{target}

    B -->|green / blue / yellow| C[Switch ENSNode Environment]
    B -->|green / blue| D[Switch ENSDb Playground Environment]

    C --> C1[Calculate env vars / SLACK_TITLE]
    C1 --> C2[Switch Traefik Routing\nAlpha / Mainnet / Sepolia / ENSRainbow]
    C2 --> C3[Promote ENSAdmin Vercel Deployment]
    C3 --> C4[Promote Example App Vercel Deployment]
    C4 --> C5[Send Slack Notification]

    D --> D1[Calculate env vars / SLACK_TITLE]
    D1 --> D2[Switch Traefik Routing\nensdb-playground-router]
    D2 --> D3[Send Slack Notification]

    C3 & C4 --> P[promote_vercel_deployment action]
    P --> P1[curl ENSNode indexing-status endpoint\nhttps://api.alpha.ENV.ensnode.io/api/indexing-status]
    P1 --> P2[Extract version → construct image tag]
    P2 --> P3[skopeo inspect → get commit SHA]
    P3 --> P4[Vercel API: find deployment by SHA]
    P4 --> P5[Vercel API: promote to production]
Loading

Reviews (2): Last reviewed commit: "Apply AI PR feedback" | Re-trigger Greptile

Comment thread .github/workflows/deploy_switch_ensdb_playground_environment.yml Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment thread .github/workflows/deploy_switch_ensnode_environment.yml
Comment thread .github/actions/promote_vercel_deployment/promote_vercel_deployment.sh Outdated
Comment thread .github/workflows/deploy_switch_ensdb_playground_environment.yml
fi
--fail \
--url "$INDEXING_STATUS_URL" | \
jq -r '.stackInfo.ensIndexer.versionInfo.ensIndexer')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

promote_vercel_deployment.sh reconstructs the ENSIndexer image tag from the reported semver version (ensindexer:<version>), which does not exist for release-candidate/preview deployments, so skopeo inspect fails — and because the promote steps run after the irreversible Traefik routing switch, the workflow aborts with production already moved to the new backend but the frontend left un-promoted.

Fix on Vercel

@tk-o

tk-o commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

@greptile review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/deploy_switch_ensnode_environment.yml (1)

19-22: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Serialize production environment switches.

This job mutates shared production routing and promotes Vercel deployments; concurrent manual runs can interleave those operations and leave routing/promotions split across targets. Add job-level concurrency with queuing, not cancellation.

Proposed fix
   switch-environment:
     # NOTE: this needs to run on GH runner because of some obscure skopeo permissions thing
     runs-on: ubuntu-latest
     name: Switch Environment to ${{ inputs.target }}
+    concurrency:
+      group: deploy-switch-ensnode-environment
+      cancel-in-progress: false
     env:
🤖 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/deploy_switch_ensnode_environment.yml around lines 19 -
22, Add job-level concurrency to the switch-environment job so only one
production environment switch runs at a time, and configure it to queue rather
than cancel in-progress or pending runs. Update the switch-environment job in
the workflow that uses the ubuntu-latest runner and the “Switch Environment to
${{ inputs.target }}” name, using a stable concurrency group for this
workflow/job so concurrent manual triggers serialize cleanly.

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/actions/promote_vercel_deployment/promote_vercel_deployment.sh:
- Around line 41-48: The ENSNode indexing-status fetch in
promote_vercel_deployment.sh is unbounded and can hang the promotion job if the
endpoint stalls. Update the curl call used to populate ENSNODE_VERSION with
explicit connection and total timeouts, plus a small retry budget, while keeping
the existing INDEXING_STATUS_URL and jq parsing flow intact. Use the existing
promote_vercel_deployment.sh request block as the place to apply the
timeout/retry settings so the workflow fails fast instead of waiting for the
full job timeout.

In @.github/workflows/deploy_switch_ensdb_playground_environment.yml:
- Around line 6-20: The manual environment switch workflow can race because
multiple dispatches of switch-environment mutate the same Traefik routing key at
once. Add a workflow-level deployment lock using the workflow’s concurrency
controls so only one run can execute or queue at a time, and apply it to the
deploy_switch_ensdb_playground_environment workflow around the existing
workflow_dispatch/job setup.
- Around line 27-30: The Checkout repository step in the deploy workflow needs
hardening: `actions/checkout` is currently tag-pinned and leaves credentials in
git config by default. Update the `Checkout repository` step to use a full
commit SHA for `actions/checkout` and set `persist-credentials` to false unless
later steps in the workflow require authenticated git access.
- Around line 55-56: The local action referenced by Send Slack Notification is
missing required metadata, causing actionlint to reject the workflow. Update
.github/actions/send_slack_notification/action.yml to add a top-level
description field alongside the existing action metadata so the uses step for
send_slack_notification is lint-valid.

---

Outside diff comments:
In @.github/workflows/deploy_switch_ensnode_environment.yml:
- Around line 19-22: Add job-level concurrency to the switch-environment job so
only one production environment switch runs at a time, and configure it to queue
rather than cancel in-progress or pending runs. Update the switch-environment
job in the workflow that uses the ubuntu-latest runner and the “Switch
Environment to ${{ inputs.target }}” name, using a stable concurrency group for
this workflow/job so concurrent manual triggers serialize cleanly.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 03851eab-5def-4e1c-88eb-8fc82bbe4b61

📥 Commits

Reviewing files that changed from the base of the PR and between 29358f8 and fd46b96.

📒 Files selected for processing (4)
  • .github/actions/promote_vercel_deployment/action.yml
  • .github/actions/promote_vercel_deployment/promote_vercel_deployment.sh
  • .github/workflows/deploy_switch_ensdb_playground_environment.yml
  • .github/workflows/deploy_switch_ensnode_environment.yml

Comment on lines +41 to +48
# first, get the deployed ENSNode version from the ENSApi indexing-status endpoint
INDEXING_STATUS_URL="https://api.alpha.${ENSNODE_ENVIRONMENT}.ensnode.io/api/indexing-status"
ENSNODE_VERSION=$(curl \
--silent \
--show-error \
--url https://backboard.railway.app/graphql/v2 \
--header "Authorization: Bearer $RAILWAY_TOKEN" \
--header 'Content-Type: application/json' \
--data "{\"query\": \"{ environment(id: \\\"$RAILWAY_ENVIRONMENT_ID\\\") { serviceInstances { edges { node { source { image } } } } } }\"}")

if [ $? -ne 0 ]; then
echo "Error: curl command failed. Output:"
echo "$RAILWAY_SERVICES_OUTPUT"
exit 1
fi
--fail \
--url "$INDEXING_STATUS_URL" | \
jq -r '.stackInfo.ensIndexer.versionInfo.ensIndexer')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound the ENSNode indexing-status request.

curl --fail still has no connection or total timeout, so a stalled endpoint can hang this production promotion job until the workflow timeout. Add bounded timeouts and a small retry budget.

Proposed fix
 ENSNODE_VERSION=$(curl \
   --silent \
   --show-error \
   --fail \
+  --connect-timeout 10 \
+  --max-time 30 \
+  --retry 3 \
+  --retry-delay 2 \
+  --retry-connrefused \
   --url "$INDEXING_STATUS_URL" | \
   jq -r '.stackInfo.ensIndexer.versionInfo.ensIndexer')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# first, get the deployed ENSNode version from the ENSApi indexing-status endpoint
INDEXING_STATUS_URL="https://api.alpha.${ENSNODE_ENVIRONMENT}.ensnode.io/api/indexing-status"
ENSNODE_VERSION=$(curl \
--silent \
--show-error \
--url https://backboard.railway.app/graphql/v2 \
--header "Authorization: Bearer $RAILWAY_TOKEN" \
--header 'Content-Type: application/json' \
--data "{\"query\": \"{ environment(id: \\\"$RAILWAY_ENVIRONMENT_ID\\\") { serviceInstances { edges { node { source { image } } } } } }\"}")
if [ $? -ne 0 ]; then
echo "Error: curl command failed. Output:"
echo "$RAILWAY_SERVICES_OUTPUT"
exit 1
fi
--fail \
--url "$INDEXING_STATUS_URL" | \
jq -r '.stackInfo.ensIndexer.versionInfo.ensIndexer')
# first, get the deployed ENSNode version from the ENSApi indexing-status endpoint
INDEXING_STATUS_URL="https://api.alpha.${ENSNODE_ENVIRONMENT}.ensnode.io/api/indexing-status"
ENSNODE_VERSION=$(curl \
--silent \
--show-error \
--fail \
--connect-timeout 10 \
--max-time 30 \
--retry 3 \
--retry-delay 2 \
--retry-connrefused \
--url "$INDEXING_STATUS_URL" | \
jq -r '.stackInfo.ensIndexer.versionInfo.ensIndexer')
🤖 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/actions/promote_vercel_deployment/promote_vercel_deployment.sh
around lines 41 - 48, The ENSNode indexing-status fetch in
promote_vercel_deployment.sh is unbounded and can hang the promotion job if the
endpoint stalls. Update the curl call used to populate ENSNODE_VERSION with
explicit connection and total timeouts, plus a small retry budget, while keeping
the existing INDEXING_STATUS_URL and jq parsing flow intact. Use the existing
promote_vercel_deployment.sh request block as the place to apply the
timeout/retry settings so the workflow fails fast instead of waiting for the
full job timeout.

Comment on lines +6 to +20
on:
workflow_dispatch:
inputs:
target:
description: "New ENSDb Playground environment"
required: true
type: choice
options:
- green
- blue

jobs:
switch-environment:
# NOTE: this needs to run on GH runner because of some obscure skopeo permissions thing
runs-on: ubuntu-latest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Serialize ENSDb Playground environment switches.

This workflow mutates a single Traefik production routing key; overlapping manual dispatches can race and leave routing determined by the last Redis write, not operator intent. Add a workflow-level deployment lock.

Proposed fix
 on:
   workflow_dispatch:
     inputs:
       target:
         description: "New ENSDb Playground environment"
         required: true
         type: choice
         options:
           - green
           - blue
+
+concurrency:
+  group: deploy-switch-ensdb-playground-environment
+  cancel-in-progress: false
 
 jobs:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on:
workflow_dispatch:
inputs:
target:
description: "New ENSDb Playground environment"
required: true
type: choice
options:
- green
- blue
jobs:
switch-environment:
# NOTE: this needs to run on GH runner because of some obscure skopeo permissions thing
runs-on: ubuntu-latest
on:
workflow_dispatch:
inputs:
target:
description: "New ENSDb Playground environment"
required: true
type: choice
options:
- green
- blue
concurrency:
group: deploy-switch-ensdb-playground-environment
cancel-in-progress: false
jobs:
switch-environment:
# NOTE: this needs to run on GH runner because of some obscure skopeo permissions thing
runs-on: ubuntu-latest
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 6-15: insufficient job-level concurrency limits (concurrency-limits): workflow is missing concurrency setting

(concurrency-limits)

🤖 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/deploy_switch_ensdb_playground_environment.yml around
lines 6 - 20, The manual environment switch workflow can race because multiple
dispatches of switch-environment mutate the same Traefik routing key at once.
Add a workflow-level deployment lock using the workflow’s concurrency controls
so only one run can execute or queue at a time, and apply it to the
deploy_switch_ensdb_playground_environment workflow around the existing
workflow_dispatch/job setup.

Source: Linters/SAST tools

Comment on lines +27 to +30
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ref_json="$(gh api repos/actions/checkout/git/ref/tags/v6)"
sha="$(jq -r '.object.sha' <<<"$ref_json")"
type="$(jq -r '.object.type' <<<"$ref_json")"

if [ "$type" = "tag" ]; then
  gh api "repos/actions/checkout/git/tags/$sha" --jq '.object.sha'
else
  echo "$sha"
fi

Repository: namehash/ensnode

Length of output: 1984


🌐 Web query:

actions/checkout persist-credentials default documentation hash pinning recommendation

💡 Result:

The actions/checkout action, maintained by GitHub, includes a persist-credentials input that controls whether authentication credentials (the GitHub token or a provided SSH key) are configured in the local Git configuration [1][2]. Default Behavior and Recommendation: The default value for persist-credentials is true [3][4]. When enabled, the action configures the runner's local Git environment with credentials, which allows subsequent steps in the same job to execute authenticated Git commands [1][5]. Security experts and industry guidance, including the OWASP GitHub Actions Security Cheat Sheet, strongly recommend setting persist-credentials: false unless your workflow explicitly requires authenticated Git operations [6][7]. This practice is recommended to minimize the attack surface by preventing credentials from being stored in the environment, thereby reducing the risk of accidental exposure if the workflow is compromised [6][7]. Action Versioning and Hash Pinning: Regarding hash pinning, it is a recommended security best practice to pin all GitHub Actions to a specific commit SHA rather than using tags (like v4) [6][7]. This ensures that your workflow consistently runs the exact same code, protecting against potential supply chain attacks where a tag might be updated to point to malicious code [7]. Example Configuration: To implement these security recommendations, use the following pattern in your workflow YAML: - uses: actions/checkout@<FULL_COMMIT_SHA> with: persist-credentials: false Replace <FULL_COMMIT_SHA> with the specific 40-character commit hash of the version you intend to use [6][7].

Citations:


Harden the checkout step.

actions/checkout@v6 is tag-pinned instead of SHA-pinned, and persist-credentials defaults to true, which leaves GITHUB_TOKEN in the local git config. Pin to a full commit SHA and set persist-credentials: false unless later steps need authenticated git access.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 27-30: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 28-28: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/deploy_switch_ensdb_playground_environment.yml around
lines 27 - 30, The Checkout repository step in the deploy workflow needs
hardening: `actions/checkout` is currently tag-pinned and leaves credentials in
git config by default. Update the `Checkout repository` step to use a full
commit SHA for `actions/checkout` and set `persist-credentials` to false unless
later steps in the workflow require authenticated git access.

Source: Linters/SAST tools

Comment on lines +55 to +56
- name: Send Slack Notification
uses: ./.github/actions/send_slack_notification

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Workflow snippet ==\n'
sed -n '45,65p' .github/workflows/deploy_switch_ensdb_playground_environment.yml

printf '\n== Action metadata ==\n'
sed -n '1,80p' .github/actions/send_slack_notification/action.yml

printf '\n== References to send_slack_notification ==\n'
rg -n "send_slack_notification|actionlint|description:" .github -S

Repository: namehash/ensnode

Length of output: 1955


🌐 Web query:

GitHub Actions action.yml top-level description required local action metadata actionlint local action missing description

💡 Result:

In GitHub Actions, the description field in the action.yml metadata file is required [1][2]. The official GitHub Actions metadata syntax documentation explicitly lists description as a required top-level key for defining an action [1][3]. Regarding actionlint, this static analysis tool enforces metadata requirements for local actions. Since version 1.7.0, actionlint has included checks for the action metadata file (action.yml or action.yaml) [4]. If the top-level description field is missing from your action.yml file, actionlint will report an error (e.g., 'description' section is missing) [4]. Because actionlint primarily focuses on checking workflow files rather than independently validating action.yml files in isolation, you may need to ensure your action is being referenced in a workflow or test file that actionlint scans, or verify your linting configuration, to see the error reported [4].

Citations:


Add the missing description in .github/actions/send_slack_notification/action.yml
actionlint treats local actions without a top-level description as invalid, so this workflow step can fail linting until the action metadata is updated.

🧰 Tools
🪛 actionlint (1.7.12)

[error] 56-56: description is required in metadata of "Send Slack notification" action at "/home/jailuser/git/.github/actions/send_slack_notification/action.yml"

(action)

🤖 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/deploy_switch_ensdb_playground_environment.yml around
lines 55 - 56, The local action referenced by Send Slack Notification is missing
required metadata, causing actionlint to reject the workflow. Update
.github/actions/send_slack_notification/action.yml to add a top-level
description field alongside the existing action metadata so the uses step for
send_slack_notification is lint-valid.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants