Common GitHub Workflows for Code Scanning, Image Builds, Lighthouse, and Deployments

Drupal

Common GitHub Workflows for Code Scanning, Image Builds, Lighthouse, and Deployments

A practical guide to common GitHub Actions workflows: PHPCS, PHPStan, CodeQL, dependency review, Docker image builds, container scans, Lighthouse tests, smoke tests, and deployment gates.

GitHub Actions can be as small as a PHPCS check or as important as the pipeline that builds and deploys production images. For Drupal, PHP, Node, and Docker-based projects, a good workflow set should answer five questions on every change:

  • Does the code meet project standards?
  • Did we introduce a security risk?
  • Can the application build?
  • Does the running site still behave and perform well?
  • Is deployment controlled, repeatable, and auditable?
GitHub Actions workflow stack showing quality, security, image build, Lighthouse, and deployment layers
Use separate workflows for separate responsibilities. It keeps failures understandable and ownership clear.

1. Code Quality Workflow

For Drupal projects, the first workflow is usually code quality. It should run on pull requests before code reaches main or develop.

Common checks:

  • PHPCS: Drupal coding standards.
  • PHPStan: static analysis for PHP mistakes.
  • Composer validate: dependency metadata sanity.
  • Twig lint: template syntax if your project uses Twig-heavy custom themes.
  • ESLint/Stylelint: frontend code quality if custom JavaScript/CSS is present.

A focused Drupal workflow might look like this:

name: Drupal Code Quality

on:
  pull_request:
    branches: [main, develop]

permissions:
  contents: read

jobs:
  code-quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
          extensions: mbstring, intl, pdo, pdo_mysql

      - run: composer install --prefer-dist --no-progress --no-interaction --dev
      - run: composer validate --strict
      - run: vendor/bin/phpcs --standard=phpcs.xml web/modules/custom web/themes/custom
      - run: vendor/bin/phpstan analyse web/modules/custom web/themes/custom

Keep this workflow fast. Developers should get feedback within minutes, not after a full deployment pipeline finishes.

2. Unit And Kernel Test Workflow

Static checks catch many issues, but tests prove behavior. In Drupal, this can mean unit tests, kernel tests, browser tests, or a small smoke-test suite.

Good candidates:

  • Custom services.
  • Custom Drush commands.
  • Access checks.
  • Form validation.
  • Migration process plugins.
  • API normalization logic.

Do not start by trying to test the entire site. Start with the custom code that would hurt most if it silently broke.

3. Code Scanning Workflow

Code scanning looks for security issues and unsafe patterns. GitHub CodeQL is the common GitHub-native option. It works best for supported languages and should run on pull requests and on a scheduled cadence.

name: CodeQL

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main]
  schedule:
    - cron: '30 3 * * 1'

permissions:
  contents: read
  security-events: write

jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: javascript-typescript
      - uses: github/codeql-action/analyze@v3

For PHP-heavy Drupal projects, pair CodeQL with PHPStan, PHPCS security rules, dependency scanning, and code review. Code scanning is not a substitute for Drupal access-control thinking.

4. Dependency Review And Vulnerability Checks

Dependency changes deserve their own attention. A pull request that changes composer.lock, package-lock.json, or Docker base images can change the risk profile even if application code is untouched.

Useful checks:

  • GitHub Dependabot alerts.
  • Dependency Review Action on pull requests.
  • composer audit.
  • npm audit where appropriate.
  • Container image vulnerability scanning with tools such as Trivy or Grype.
name: Dependency Review

on:
  pull_request:

permissions:
  contents: read
  pull-requests: read

jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/dependency-review-action@v4

For Drupal, also pay attention to contrib module security advisories. A green CI run does not mean a module is safe if you are behind on security releases.

5. Docker Image Build Workflow

If your site runs from a Docker image, the image workflow is one of the most important workflows in the repo. It should build on pull requests but only push from trusted branches, tags, or manual release events.

GitHub Actions Docker image build and push workflow pattern
Build on pull requests. Publish only from trusted events.
name: Docker Image

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main, develop, 'release/**']
  workflow_dispatch:

permissions:
  contents: read
  packages: write

concurrency:
  group: docker-image-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=sha,prefix=sha-
      - uses: docker/login-action@v3
        if: github.event_name != 'pull_request'
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Important safety rule: do not publish images or expose registry credentials from untrusted pull request events.

6. Container Scanning Workflow

Building an image is not the same as trusting it. Add a scan step before pushing, or scan the pushed image and fail on unacceptable severity levels.

Typical scan targets:

  • OS packages in the base image.
  • PHP extensions and system libraries.
  • Composer dependencies.
  • Node dependencies if built into the image.
  • Secrets accidentally copied into the image.

If the scanner is too noisy at first, start by reporting results as artifacts, then tighten failure thresholds once the baseline is under control.

7. Lighthouse Workflow

Lighthouse checks the real user-facing surface: performance, accessibility, SEO, and best practices. For Drupal, this is especially useful after theme changes, image handling changes, cache changes, or JavaScript updates.

GitHub Actions Lighthouse CI workflow pattern for a running site
Lighthouse needs a running site or preview URL. Audit key pages, not only the homepage.

Recommended URLs:

  • Homepage.
  • Article detail page.
  • Article listing page.
  • Contact form.
  • Any high-value landing page.

A Lighthouse workflow usually has four steps:

  1. Build or start the application.
  2. Wait until the site responds.
  3. Run Lighthouse CI.
  4. Upload the HTML/JSON report artifact.
name: Lighthouse

on:
  pull_request:
    branches: [main, develop]

permissions:
  contents: read

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install -g @lhci/cli
      - run: lhci autorun
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: lighthouse-reports
          path: .lighthouseci

Performance budgets should be realistic. Start with warnings and trend tracking; make hard failures only when the team agrees on the thresholds.

8. Smoke Test Workflow

A smoke test checks whether the site basically works after build or deploy. It does not replace full tests; it catches obvious breakage quickly.

Examples:

  • Homepage returns HTTP 200.
  • Important route returns HTTP 200.
  • Login page loads.
  • Health endpoint responds.
  • Drupal bootstrap works with drush status.
  • Expected response headers exist.
curl -fsS https://example.com/ >/dev/null
curl -fsS https://example.com/articles >/dev/null
drush status
drush watchdog:show --count=20

9. Deployment Workflow

Deployment should be boring. The workflow should know which image or tag is being deployed, which environment receives it, who approved it, and how to roll back.

Good deployment workflow features:

  • Uses protected GitHub environments.
  • Requires manual approval for production.
  • Deploys immutable tags or image digests, not vague moving state.
  • Runs database updates and config import after code is live.
  • Runs smoke tests after deployment.
  • Posts the result somewhere visible.

For Drupal, a post-deploy command block usually includes:

drush updatedb -y
drush config:import -y
drush cache:rebuild
drush cron

10. Workflow Security Hardening

GitHub Actions workflow security hardening checklist
Workflow YAML is supply-chain infrastructure. Review it with the same care as deployment code.

Security habits that matter:

  • Set permissions explicitly for every workflow.
  • Use least privilege: most PR checks only need contents: read.
  • Do not expose secrets to untrusted pull requests.
  • Push packages only from protected branches or tags.
  • Use environments and required reviewers for production.
  • Review changes under .github/workflows carefully.
  • Prefer official or trusted actions.
  • Use concurrency controls to prevent overlapping deploys.
  • Keep artifacts short-lived if they may contain sensitive logs.

Recommended Workflow Set For A Drupal Project

WorkflowTriggerPurpose
Code QualityPull requestPHPCS, PHPStan, Composer validation
TestsPull request, push to mainUnit/kernel/browser tests
Code ScanningPull request, push, scheduleSecurity analysis
Dependency ReviewPull requestRisky dependency changes
Docker ImagePull request, push, manualBuild and publish deployable image
Container ScanAfter image buildFind image vulnerabilities
LighthousePull request or nightlyPerformance/accessibility regression checks
DeployManual or protected push/tagRelease to live environment

Common Mistakes

One Giant Workflow

If everything is in one YAML file, failures are harder to understand and slower checks block faster feedback. Split by responsibility.

Publishing From Pull Requests

Build pull requests, but do not push production images or run deployments from untrusted PR contexts.

No Permissions Block

Explicit permissions make workflows safer and easier to audit.

No Concurrency For Deployments

Two deploys running at once can produce strange production state. Use concurrency groups for image builds and deploys.

Lighthouse Without A Stable Environment

Lighthouse scores are noisy if the target site is not stable. Use consistent URLs, cache warmup, and realistic budgets.

Final Takeaway

Good GitHub workflows are not about collecting badges. They create confidence at each stage: code quality before review, security before merge, build before deploy, performance before release, and approval before production.

For a Drupal project, start with PHPCS/PHPStan and Docker image build. Then add dependency review, code scanning, container scanning, Lighthouse, smoke tests, and protected deployment workflows. Keep each workflow small, explicit, and boring enough that the whole team trusts it.

Keep reading

Drupal Sep 7, 2026 6 min read

Build a Drupal Chatbot with Local AI

Learn how a Drupal chatbot finds relevant published articles, uses Ollama to generate answers, and displays source links while keeping inference on your own hardware.