When building or modifying CI/CD GitHub Actions workflows, structure them as an explicit DAG of artifact-driven jobs and guard execution to prevent fork/irrelevant-context failures.

Standards 1) Gate by repo once, with correct allowlist

2) Make ordering explicit with needs

3) Use job outputs/env, not ad-hoc shell env unless needed

4) Add lightweight artifact validation

5) Keep CI dependencies aligned with what you actually run

Example pattern

jobs:
  extract:
    if: github.repository == 'redis/redis'
    runs-on: ubuntu-latest
    outputs:
      tag: $
    steps:
      - id: info
        run: echo "tag=v1.2.3" >> "$GITHUB_OUTPUT"

  create-artifact:
    needs: extract
    runs-on: ubuntu-latest
    outputs:
      sha256: $
    steps:
      - run: ./utils/releasetools/01_create_tarball.sh "$"
      - id: checksum
        run: |
          TARBALL="/tmp/redis-$.tar.gz"
          SHA256=$(shasum -a 256 "$TARBALL" | cut -d' ' -f1)
          echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"

  summary:
    needs: [extract, create-artifact]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - run: echo "Pipeline completed (may be partially skipped)."

Applying these rules prevents cascading failures on forks, makes workflow behavior predictable, and improves reliability of release automation by validating what you produce before you publish it.