Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 105 additions & 19 deletions .github/workflows/build-test-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#
# This configuration file uses a custom "container" executor to run the
# Docker stack to speed up the build process.
#;
#; Comments starting with '#;<' and '#;>' are internal Vortex comments
#; and will be removed during installation or update of Vortex.
name: Database, Build, Test and Deploy

on:
Expand Down Expand Up @@ -42,8 +45,20 @@ on:
description: 'Enable terminal session.'
required: false
default: false
deploy_target:
type: string
description: 'Deploy target: branch name (e.g., "develop") or PR reference (e.g., "pr-123"). When provided, lint/build/test jobs are skipped.'
required: false
default: ''
override_db:
type: boolean
description: 'Override existing database in the deployment environment.'
required: false
default: false
#;< !PROVISION_TYPE_PROFILE
schedule:
- cron: '0 18 * * *'
#;> !PROVISION_TYPE_PROFILE

defaults:
run:
Expand All @@ -59,11 +74,13 @@ jobs:

lint:
runs-on: ubuntu-latest
if: ${{ github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }}
#;< !PROVISION_TYPE_PROFILE
if: ${{ !inputs.deploy_target && github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/build-test-deploy.yml | sed -n '70,90p'

Repository: drevops/website

Length of output: 1020


🏁 Script executed:

cat -n .github/workflows/build-test-deploy.yml | sed -n '300,315p'

Repository: drevops/website

Length of output: 879


🏁 Script executed:

cat -n .github/workflows/build-test-deploy.yml | sed -n '530,550p'

Repository: drevops/website

Length of output: 1088


🌐 Web query:

GitHub Actions job needs dependency skipped if condition semantics

💡 Result:

In GitHub Actions, a job that declares needs: is implicitly gated by if: success(). So if any job in its dependency chain is skipped (or fails/cancels), downstream jobs are skipped by default (“a failure or skip applies to all jobs in the dependency chain…”). [1]

To override that default and decide yourself, put always() in the dependent job’s if: (this removes the implicit success() gate), then check dependency results via needs.<job_id>.result (values: success, failure, cancelled, skipped). [1][2]

Example: run deploy even if build was skipped, but not if it failed/cancelled:

jobs:
  build:
    if: ${{ github.ref == 'refs/heads/main' }}   # may be skipped

  deploy:
    needs: build
    if: ${{ always() && (needs.build.result == 'success' || needs.build.result == 'skipped') }}
    runs-on: ubuntu-latest
    steps:
      - run: echo "deploying..."

If you only write if: needs.build.result == 'skipped' without always(), deploy will still be skipped, because the implicit success() gate prevents the job from running/evaluating as you expect when a dependency is skipped. [1][3]

Sources: GitHub Docs on dependency-chain skip behavior and using always() [1], and on needs.<job_id>.result values [2], plus GitHub Community discussion of success() being false when dependencies are skipped [3].

[1] (docs.github.com)
[2] (docs.github.com)
[3] (github.com)

Citations:


🏁 Script executed:

cat -n .github/workflows/build-test-deploy.yml | sed -n '546,565p'

Repository: drevops/website

Length of output: 1081


Manual deploy_target runs are blocked by the implicit success gate on job dependencies.

When inputs.deploy_target is set, the lint and build jobs are skipped by their if conditions (lines 78 and 313). However, the deploy job declares needs: [build, lint] without always(), which adds an implicit if: success() gate to the entire dependency chain. GitHub Actions will skip the deploy job when its dependencies are skipped, regardless of the explicit if condition on line 551 evaluating to true.

Use always() to remove the implicit success gate and explicitly check dependency results only for the normal (non-manual) deployment path:

Suggested fix
   deploy:
     runs-on: ubuntu-latest
     needs: [build, lint]
-    if: ${{ !cancelled() && (inputs.deploy_target || (github.event_name != 'schedule' && !startsWith(github.head_ref || github.ref_name, 'deps/') && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')))) }}
+    if: ${{ always() && (inputs.deploy_target || (needs.build.result == 'success' && needs.lint.result == 'success' && github.event_name != 'schedule' && !startsWith(github.head_ref || github.ref_name, 'deps/') && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')))) }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-test-deploy.yml at line 78, The deploy job is being
skipped when lint/build are skipped because its needs: [build, lint] creates an
implicit success() gate; update the deploy job (deploy) to use always() in its
if expression so it will run even when dependencies were skipped, and then
combine always() with the existing condition that checks inputs.deploy_target
and the push/branch logic (i.e. change the deploy job's if to start with
always() && (your current condition OR inputs.deploy_target) ), leaving needs:
[build, lint] in place so artifacts/outputs remain available when present but
not blocking manual deploys.

#;> !PROVISION_TYPE_PROFILE

container:
# https://hub.docker.com/r/drevops/ci-runner
image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398
image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97
env:
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }}
Expand Down Expand Up @@ -114,7 +131,9 @@ jobs:
docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \
if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \
COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist"
#;< TOOL_ESLINT_STYLELINT
docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile"
#;> TOOL_ESLINT_STYLELINT

- name: Audit Composer packages
run: docker compose exec -T cli composer audit
Expand All @@ -124,42 +143,61 @@ jobs:
run: docker compose exec -T cli composer normalize --dry-run
continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE == '1' }}

#;< TOOL_PHPCS
- name: Lint code with PHPCS
run: docker compose exec -T cli vendor/bin/phpcs
continue-on-error: ${{ vars.VORTEX_CI_PHPCS_IGNORE_FAILURE == '1' }}
#;> TOOL_PHPCS

#;< TOOL_PHPSTAN
- name: Lint code with PHPStan
run: docker compose exec -T cli vendor/bin/phpstan
continue-on-error: ${{ vars.VORTEX_CI_PHPSTAN_IGNORE_FAILURE == '1' }}
#;> TOOL_PHPSTAN

#;< TOOL_RECTOR
- name: Lint code with Rector
run: docker compose exec -T cli vendor/bin/rector --dry-run
continue-on-error: ${{ vars.VORTEX_CI_RECTOR_IGNORE_FAILURE == '1' }}
#;> TOOL_RECTOR

#;< TOOL_PHPMD
- name: Lint code with PHPMD
run: docker compose exec -T cli vendor/bin/phpmd . text phpmd.xml
continue-on-error: ${{ vars.VORTEX_CI_PHPMD_IGNORE_FAILURE == '1' }}
#;> TOOL_PHPMD

- name: Lint code with Twig CS Fixer
run: docker compose exec -T cli vendor/bin/twig-cs-fixer
continue-on-error: ${{ vars.VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE == '1' }}

#;< TOOL_BEHAT
- name: Lint code with Gherkin Lint
run: docker compose exec -T cli vendor/bin/gherkinlint lint tests/behat/features
continue-on-error: ${{ vars.VORTEX_CI_GHERKIN_LINT_IGNORE_FAILURE == '1' }}
#;> TOOL_BEHAT

#;< TOOL_ESLINT_STYLELINT
- name: Lint module code with NodeJS linters
run: docker compose exec -T cli bash -c "yarn run lint"
continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }}
#;> TOOL_ESLINT_STYLELINT

#;< DRUPAL_THEME
- name: Lint theme code with NodeJS linters
if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }}
run: docker compose exec -T cli bash -c "yarn --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint"
continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }}
#;> DRUPAL_THEME

#;< !PROVISION_TYPE_PROFILE
database:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'project/') }}
if: ${{ !inputs.deploy_target && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }}

container:
# https://hub.docker.com/r/drevops/ci-runner
image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398
image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97
env:
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }}
Expand Down Expand Up @@ -235,6 +273,11 @@ jobs:
VORTEX_DOWNLOAD_DB_SEMAPHORE=/tmp/download-db-success ./scripts/vortex/download-db.sh
echo "db_hash=${{ hashFiles('.data') }}" >> "$GITHUB_ENV"
timeout-minutes: 30
#;< DB_DOWNLOAD_SOURCE_ACQUIA
env:
VORTEX_ACQUIA_KEY: ${{ secrets.VORTEX_ACQUIA_KEY }}
VORTEX_ACQUIA_SECRET: ${{ secrets.VORTEX_ACQUIA_SECRET }}
#;> DB_DOWNLOAD_SOURCE_ACQUIA

- name: Export DB
run: |
Expand All @@ -256,11 +299,14 @@ jobs:
with:
path: .data
key: v26.2.0-db11-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-${{ hashFiles('db_cache_timestamp') }}
#;> !PROVISION_TYPE_PROFILE

build:
runs-on: ubuntu-latest
#;< !PROVISION_TYPE_PROFILE
needs: database
if: ${{ github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }}
if: ${{ !inputs.deploy_target && github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }}
#;> !PROVISION_TYPE_PROFILE

strategy:
# A matrix to run multiple jobs in parallel.
Expand All @@ -270,7 +316,7 @@ jobs:

container:
# https://hub.docker.com/r/drevops/ci-runner
image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398
image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97
env:
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }}
Expand All @@ -281,6 +327,7 @@ jobs:
VORTEX_SSH_DISABLE_STRICT_HOST_KEY_CHECKING: "1"
VORTEX_SSH_REMOVE_ALL_KEYS: "1"
VORTEX_DEBUG: ${{ vars.VORTEX_DEBUG }}
#;< !PROVISION_TYPE_PROFILE
# How often to refresh the cache of the DB dump. Refer to `date` command.
VORTEX_CI_DB_CACHE_TIMESTAMP: +%Y%m%d
# Use previous database caches on this branch as a fallback if the above cache
Expand All @@ -289,6 +336,7 @@ jobs:
VORTEX_CI_DB_CACHE_FALLBACK: "yes"
# Which branch to use as a source of DB caches.
VORTEX_CI_DB_CACHE_BRANCH: "develop"
#;> !PROVISION_TYPE_PROFILE

steps:
- name: Preserve $HOME set in the container
Expand All @@ -310,6 +358,7 @@ jobs:
run: composer validate --strict
continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_VALIDATE_IGNORE_FAILURE == '1' }}

#;< !PROVISION_TYPE_PROFILE
- name: Create cache keys files for database caching
run: |
echo "${VORTEX_CI_DB_CACHE_BRANCH}" | tee db_cache_branch
Expand All @@ -332,6 +381,7 @@ jobs:
key: v26.2.0-db11-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-${{ hashFiles('db_cache_timestamp') }}
restore-keys: |
v26.2.0-db11-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-
#;> !PROVISION_TYPE_PROFILE

- name: Login to container registry
run: ./scripts/vortex/login-container-registry.sh
Expand Down Expand Up @@ -362,6 +412,7 @@ jobs:
docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh
timeout-minutes: 30

#;< TOOL_PHPUNIT
- name: Test with PHPUnit
if: ${{ matrix.instance == 0 || strategy.job-total == 1 }}
run: docker compose exec -T cli vendor/bin/phpunit
Expand All @@ -381,8 +432,15 @@ jobs:
RATE=$(grep -om1 'line-rate="[0-9.]*"' .logs/coverage/phpunit/cobertura.xml | tr -cd '0-9.')
PERCENT=$(awk "BEGIN {printf \"%.2f\", $RATE*100}")
echo "Coverage: $PERCENT% (threshold: $VORTEX_CI_CODE_COVERAGE_THRESHOLD%)" | tee -a "$GITHUB_STEP_SUMMARY"
echo "COVERAGE_PERCENT=${PERCENT}" >> "$GITHUB_ENV"
{ echo "COVERAGE_CONTENT<<EOF"; sed '/./,$!d' .logs/coverage/phpunit/coverage.txt; echo "EOF"; } >> "$GITHUB_ENV"
{
echo "COVERAGE_PERCENT=${PERCENT}"
echo "COVERAGE_SUMMARY<<EOF"
awk '/^ *Summary:/{f=1;next} f && /^$/{exit} f' .logs/coverage/phpunit/coverage.txt
echo "EOF"
echo "COVERAGE_DETAILS<<EOF"
awk 'BEGIN{s=0} /^ *Summary:/{s=1} s==1 && /^$/{s=2;next} s==2' .logs/coverage/phpunit/coverage.txt
echo "EOF"
} >> "$GITHUB_ENV"
env:
VORTEX_CI_CODE_COVERAGE_THRESHOLD: ${{ vars.VORTEX_CI_CODE_COVERAGE_THRESHOLD || '90' }}

Expand All @@ -392,10 +450,17 @@ jobs:
with:
header: coverage-gha
message: |
**Code coverage (GitHub Actions)**
**Code coverage** (threshold: ${{ vars.VORTEX_CI_CODE_COVERAGE_THRESHOLD || '90' }}%)
```
${{ env.COVERAGE_CONTENT }}
${{ env.COVERAGE_SUMMARY }}
```
<details>
<summary>Per-class coverage</summary>

```
${{ env.COVERAGE_DETAILS }}
```
</details>
hide_and_recreate: true

- name: Upload coverage report to Codecov
Expand All @@ -417,7 +482,9 @@ jobs:
fi
env:
VORTEX_CI_CODE_COVERAGE_THRESHOLD: ${{ vars.VORTEX_CI_CODE_COVERAGE_THRESHOLD || '90' }}
#;> TOOL_PHPUNIT

#;< TOOL_BEHAT
- name: Test with Behat
run: |
# shellcheck disable=SC2170
Expand All @@ -429,6 +496,7 @@ jobs:
VORTEX_CI_BEHAT_PROFILE: ${{ vars.VORTEX_CI_BEHAT_PROFILE }}
continue-on-error: ${{ vars.VORTEX_CI_BEHAT_IGNORE_FAILURE == '1' }}
timeout-minutes: 30
#;> TOOL_BEHAT

- name: Process test logs and artifacts
if: always()
Expand Down Expand Up @@ -464,14 +532,17 @@ jobs:
with:
detached: true

#;< DEPLOYMENT
deploy:
runs-on: ubuntu-latest
needs: [build, lint]
if: ${{ github.event_name != 'schedule' && !startsWith(github.head_ref || github.ref_name, 'deps/') && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }}
#;< !PROVISION_TYPE_PROFILE
if: ${{ inputs.deploy_target || (github.event_name != 'schedule' && !startsWith(github.head_ref || github.ref_name, 'deps/') && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/'))) }}
#;> !PROVISION_TYPE_PROFILE

container:
# https://hub.docker.com/r/drevops/ci-runner
image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398
image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97
env:
TZ: ${{ vars.TZ || 'UTC' }}
TERM: xterm-256color
Expand All @@ -482,6 +553,19 @@ jobs:
- name: Preserve $HOME set in the container
run: echo HOME=/root >> "$GITHUB_ENV" # https://github.com/actions/runner/issues/863

- name: Resolve deploy target
if: ${{ inputs.deploy_target }}
env:
DEPLOY_TARGET: ${{ inputs.deploy_target }}
GH_TOKEN: ${{ github.token }}
run: |
echo "DEPLOY_BRANCH=${DEPLOY_TARGET}" >> "$GITHUB_ENV"
if echo "${DEPLOY_TARGET}" | grep -iq '^pr-'; then
echo "DEPLOY_PR_NUMBER=${DEPLOY_TARGET#*-}" >> "$GITHUB_ENV"
echo "DEPLOY_PR_HEAD_SHA=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefOid --jq '.headRefOid')" >> "$GITHUB_ENV"
echo "DEPLOY_BRANCH=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefName --jq '.headRefName')" >> "$GITHUB_ENV"
fi
Comment on lines +567 to +578
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add error handling for PR resolution.

If the PR number is invalid or the PR doesn't exist, gh pr view will fail silently (exit code captured but env vars won't be set correctly). Additionally, if someone passes pr-abc instead of pr-123, the behavior is undefined.

Consider adding validation and error handling:

Suggested improvement
       - name: Resolve deploy target
         if: ${{ inputs.deploy_target }}
         env:
           DEPLOY_TARGET: ${{ inputs.deploy_target }}
           GH_TOKEN: ${{ github.token }}
         run: |
           echo "DEPLOY_BRANCH=${DEPLOY_TARGET}" >> "$GITHUB_ENV"
           if echo "${DEPLOY_TARGET}" | grep -iq '^pr-'; then
-            echo "DEPLOY_PR_NUMBER=${DEPLOY_TARGET#*-}" >> "$GITHUB_ENV"
-            echo "DEPLOY_PR_HEAD_SHA=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefOid --jq '.headRefOid')" >> "$GITHUB_ENV"
-            echo "DEPLOY_BRANCH=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefName --jq '.headRefName')" >> "$GITHUB_ENV"
+            PR_NUM="${DEPLOY_TARGET#*-}"
+            if ! [[ "${PR_NUM}" =~ ^[0-9]+$ ]]; then
+              echo "::error::Invalid PR number format: ${PR_NUM}. Expected 'pr-<number>'."
+              exit 1
+            fi
+            if ! gh pr view "${PR_NUM}" --repo "${{ github.repository }}" --json state --jq '.state' > /dev/null 2>&1; then
+              echo "::error::PR #${PR_NUM} not found or inaccessible."
+              exit 1
+            fi
+            echo "DEPLOY_PR_NUMBER=${PR_NUM}" >> "$GITHUB_ENV"
+            echo "DEPLOY_PR_HEAD_SHA=$(gh pr view "${PR_NUM}" --repo "${{ github.repository }}" --json headRefOid --jq '.headRefOid')" >> "$GITHUB_ENV"
+            echo "DEPLOY_BRANCH=$(gh pr view "${PR_NUM}" --repo "${{ github.repository }}" --json headRefName --jq '.headRefName')" >> "$GITHUB_ENV"
           fi
📝 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
- name: Resolve deploy target
if: ${{ inputs.deploy_target }}
env:
DEPLOY_TARGET: ${{ inputs.deploy_target }}
GH_TOKEN: ${{ github.token }}
run: |
echo "DEPLOY_BRANCH=${DEPLOY_TARGET}" >> "$GITHUB_ENV"
if echo "${DEPLOY_TARGET}" | grep -iq '^pr-'; then
echo "DEPLOY_PR_NUMBER=${DEPLOY_TARGET#*-}" >> "$GITHUB_ENV"
echo "DEPLOY_PR_HEAD_SHA=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefOid --jq '.headRefOid')" >> "$GITHUB_ENV"
echo "DEPLOY_BRANCH=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefName --jq '.headRefName')" >> "$GITHUB_ENV"
fi
- name: Resolve deploy target
if: ${{ inputs.deploy_target }}
env:
DEPLOY_TARGET: ${{ inputs.deploy_target }}
GH_TOKEN: ${{ github.token }}
run: |
echo "DEPLOY_BRANCH=${DEPLOY_TARGET}" >> "$GITHUB_ENV"
if echo "${DEPLOY_TARGET}" | grep -iq '^pr-'; then
PR_NUM="${DEPLOY_TARGET#*-}"
if ! [[ "${PR_NUM}" =~ ^[0-9]+$ ]]; then
echo "::error::Invalid PR number format: ${PR_NUM}. Expected 'pr-<number>'."
exit 1
fi
if ! gh pr view "${PR_NUM}" --repo "${{ github.repository }}" --json state --jq '.state' > /dev/null 2>&1; then
echo "::error::PR #${PR_NUM} not found or inaccessible."
exit 1
fi
echo "DEPLOY_PR_NUMBER=${PR_NUM}" >> "$GITHUB_ENV"
echo "DEPLOY_PR_HEAD_SHA=$(gh pr view "${PR_NUM}" --repo "${{ github.repository }}" --json headRefOid --jq '.headRefOid')" >> "$GITHUB_ENV"
echo "DEPLOY_BRANCH=$(gh pr view "${PR_NUM}" --repo "${{ github.repository }}" --json headRefName --jq '.headRefName')" >> "$GITHUB_ENV"
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-test-deploy.yml around lines 567 - 578, Validate
DEPLOY_TARGET when it matches '^pr-' by extracting the suffix and ensuring it's
a numeric PR ID before calling gh; for DEPLOY_PR_NUMBER extraction
(DEPLOY_TARGET#*), check the regex and if not numeric emit a clear error and
exit non‑zero. For each gh pr view invocation that sets DEPLOY_PR_HEAD_SHA and
DEPLOY_BRANCH, capture the command exit status and on failure log a descriptive
message including DEPLOY_PR_NUMBER and fail the step (or set safe defaults)
instead of allowing silent failure; ensure all uses of gh pr view are guarded so
env vars are only written when the gh command succeeds.


- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
Expand All @@ -490,23 +574,24 @@ jobs:
# Do not persist credentials after checkout
# to allow using the custom credentials to push to a remote repo.
persist-credentials: false
ref: ${{ github.head_ref || github.ref_name }}
ref: ${{ env.DEPLOY_BRANCH || github.head_ref || github.ref_name }}

- name: Fix Git ownership permissions
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Load environment variables from .env
run: t=$(mktemp) && export -p >"${t}" && set -a && . ./.env && set +a && . "${t}" && env >> "$GITHUB_ENV"

# Artifact deployments do not work for manual deploys as the build job is skipped.
- name: Download exported codebase as an artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
if: ${{ contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }}
if: ${{ !inputs.deploy_target && contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }}
with:
name: code-artifact
path: "/tmp/artifacts"

- name: Unpack downloaded exported codebase
if: ${{ contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }}
if: ${{ !inputs.deploy_target && contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }}
run: |
Comment on lines +599 to 606
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's get the size and read the workflow file
wc -l .github/workflows/build-test-deploy.yml

Repository: drevops/website

Length of output: 102


🏁 Script executed:

# Read the relevant sections around lines 588-595 and 615
sed -n '580,630p' .github/workflows/build-test-deploy.yml

Repository: drevops/website

Length of output: 2690


🏁 Script executed:

# Search for VORTEX_DEPLOY_ARTIFACT_SRC and VORTEX_DEPLOY_TYPES to understand the flow
rg "VORTEX_DEPLOY_ARTIFACT_SRC|VORTEX_DEPLOY_TYPES" .github/workflows/build-test-deploy.yml -n

Repository: drevops/website

Length of output: 614


🏁 Script executed:

# Also search for where deploy_target is used and how it affects artifact handling
rg "inputs.deploy_target" .github/workflows/build-test-deploy.yml -B 2 -A 2 -n

Repository: drevops/website

Length of output: 1845


🏁 Script executed:

sed -n '610,620p' .github/workflows/build-test-deploy.yml

Repository: drevops/website

Length of output: 524


🏁 Script executed:

# Let's also check if there's any other artifact download/unpack step or similar condition
rg "Download|Unpack|artifact" .github/workflows/build-test-deploy.yml -n

Repository: drevops/website

Length of output: 1594


🏁 Script executed:

sed -n '615,615p' .github/workflows/build-test-deploy.yml

Repository: drevops/website

Length of output: 93


🏁 Script executed:

# Also check the context around it
sed -n '620,635p' .github/workflows/build-test-deploy.yml

Repository: drevops/website

Length of output: 1246


Reject manual artifact deployments to prevent failures.

The download and unpack steps skip when inputs.deploy_target is set, but the Deploy step always sets VORTEX_DEPLOY_ARTIFACT_SRC to /tmp/workspace/code. When artifact is in VORTEX_DEPLOY_TYPES, this causes the deploy to fail because the artifact directory doesn't exist. Since the build job is skipped for manual deploys, the artifact is never created.

Add a guard to explicitly reject this unsupported configuration:

Suggested guard
      - name: Load environment variables from .env
        run: t=$(mktemp) && export -p >"${t}" && set -a && . ./.env && set +a && . "${t}" && env >> "$GITHUB_ENV"
+
+      - name: Reject manual artifact deploys until artifact preparation exists
+        if: ${{ inputs.deploy_target && contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }}
+        run: |
+          echo "Manual deploys are not supported for artifact deployments because the build job is skipped."
+          exit 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-test-deploy.yml around lines 588 - 595, The workflow
allows a manual deploy (inputs.deploy_target set) while VORTEX_DEPLOY_TYPES
contains "artifact", which leads to VORTEX_DEPLOY_ARTIFACT_SRC pointing to a
non-existent /tmp/workspace/code; add an explicit guard that rejects this
unsupported configuration by adding a workflow step before the Deploy step (or
adding an if on the Deploy step) that checks both inputs.deploy_target and
whether env.VORTEX_DEPLOY_TYPES contains "artifact" and fails early with a clear
error (exit non-zero) if both are true; reference the variables
VORTEX_DEPLOY_TYPES, inputs.deploy_target and VORTEX_DEPLOY_ARTIFACT_SRC and
ensure the message explains that manual deploys with artifact type are
unsupported.

mkdir -p /tmp/workspace
tar -xpf /tmp/artifacts/code.tar -C /tmp/workspace
Expand All @@ -524,10 +609,9 @@ jobs:
run: ./scripts/vortex/deploy.sh
env:
VORTEX_DEPLOY_MODE: ${{ startsWith(github.ref, 'refs/tags/') && 'tag' || 'branch' }}
# Get branch for PR from 'head_ref' or for branch from 'ref_name'.
VORTEX_DEPLOY_BRANCH: ${{ github.head_ref || github.ref_name }}
VORTEX_DEPLOY_PR: ${{ github.event.number }}
VORTEX_DEPLOY_PR_HEAD: ${{ github.event.pull_request.head.sha }}
VORTEX_DEPLOY_BRANCH: ${{ env.DEPLOY_BRANCH || github.head_ref || github.ref_name }}
VORTEX_DEPLOY_PR: ${{ env.DEPLOY_PR_NUMBER || github.event.number }}
VORTEX_DEPLOY_PR_HEAD: ${{ env.DEPLOY_PR_HEAD_SHA || github.event.pull_request.head.sha }}
VORTEX_DEPLOY_ARTIFACT_SRC: /tmp/workspace/code
VORTEX_DEPLOY_ARTIFACT_ROOT: ${{ github.workspace }}
VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE: ${{ vars.VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE }}
Expand All @@ -538,4 +622,6 @@ jobs:
VORTEX_DEPLOY_ALLOW_SKIP: ${{ vars.VORTEX_DEPLOY_ALLOW_SKIP }}
VORTEX_DEPLOY_SKIP_PRS: ${{ vars.VORTEX_DEPLOY_SKIP_PRS }}
VORTEX_DEPLOY_SKIP_BRANCHES: ${{ vars.VORTEX_DEPLOY_SKIP_BRANCHES }}
VORTEX_DEPLOY_ACTION: ${{ inputs.override_db && 'deploy_override_db' || '' }}
timeout-minutes: 30
#;> DEPLOYMENT
Loading