Testing Password-Protected Drupal Environments in a Deployment Pipeline
How to keep dev and staging private while still running meaningful authenticated Drupal health checks.
Development and staging environments should not be freely indexed or scraped, but protecting them introduces a testing problem: an unauthenticated health check receives HTTP 401 even when Drupal is working perfectly.
A 401 can be the expected response
Host-level password protection runs before Drupal. When a pipeline requests a protected URL without valid credentials, the web server rejects it before Drupal can bootstrap. Treating every 401 as an application failure produces noisy deployments and hides the distinction between access control and site health.
Store one combined credential securely
The pipeline stores separate development and staging secrets in GitHub. Each value uses curl’s expected username:password form. The workflow passes only the relevant environment credential to the remote check and never writes it to the repository.
curl -fsS -u "${BASIC_AUTH}" https://stage.example.com/journal
A secret that contains only the password can lead curl to interpret that value as a username and prompt interactively for a missing password. In automation the prompt cannot be answered, and the request ends with a 401. Saving the exact combined value fixes the ambiguity.
Test more than the home page
The health check requests the portfolio home page, journal index, login form, password-reset form, and XML sitemap. This samples custom routing, node rendering, account forms, and SEO output. Each route must return HTTP 200.
Status codes are necessary but not sufficient. A proxy or generic error document could still return 200, so the check also searches important responses for known application markers such as the portfolio page wrapper and styled account-card component.
Keep production checks public
Production should be checked without Basic Authentication because that is how visitors and search engines experience it. Development and staging receive credentials only for the duration of their checks. This keeps protected environments private without weakening the production test.
Make failures diagnosable
- Use curl’s fail, silent, and show-error options.
- Print the path and returned status for every successful request.
- Stop on the first unexpected response.
- Run Drupal bootstrap and database checks before HTTP requests.
- Keep credentials masked as GitHub Actions secrets.
What this caught
The staging deployment completed all Drupal work successfully but failed its final route check. The log showed a password prompt followed by HTTP 401, which narrowed the problem to the secret format rather than code, configuration, or the database. Updating the staging secret and rerunning the idempotent job produced a clean release.