Api::validatePurgeCredentials() can fail in non-production environments

Created on 18 June 2025, 17 days ago

Problem/Motivation

I noticed this while trying to find a way to disable purging on dev environments (attached) when I noticed the Fastly errors on certain dev-environment Drush commands included invalid URLs:

[error] Client error: `POST https://api.fastly.com/service//purge` resulted in a `404 Not Found` response:

(Note the double-/ between the 'service' and 'purge' URL parameters).

The TL;DR is, it's easy for any non-production environment to get into a condition where the recorded value of the fastly.state.valid_purge_credentials state key will be wrong about the validity of the current purge credentials.

Steps to reproduce

  1. copy code and database from a site with a working Fastly module into an environment with no $FASTLY_API_SERVICE in environment variables or config
  2. do something like e.g. drush pm:uninstall webform

This creates a lot of errors like this one when the module runs its API::purgeKeys() method:

 [error]  Unable to purge following key(s) cQw1 from Fastly. Purge Method: instant. 
 [error]  Client error: `POST https://api.fastly.com/service//purge` resulted in a `404 Not Found` response:
@"msg":"Record not found", "detail": "Cannot find service '(null)'"

Analysis

This bug technically relies on the module being misconfigured--it won't happen if there is a correctly defined service, but this is not an uncommon situation (as the related issue makes clear).

But that issue's discussion masks the fact that the module is sometimes able to make HTTP requests to a URL that cannot exist from inside a loop.

The issue appears to stem from the fact that the module calls setPurgeCredentialState() on install, and in the settings form, then uses that value when running Api::purgeKeys() (and purgeAll()).

But in the context of CI or development where tooling uses a copy of the Prod database, the value of fastly.state.valid_purge_credentials may remain 'true', even though it is not true of the current environment.

Thus the check passes, and the many purge requests POST to https://api.fastly.com/service//purge.

Proposed resolution

I don't have an in-depth knowledge of this module. One simple solution would be to use Api::validatePurgeCredentials() for potentially expensive operations like HTTP requests instead of $this->state->getPurgeCredentialsState().

This would have the advantages of using the existing API, and relying on the specific properties of the currently instantiated object, but there may be a superior solution that I'm overlooking. I'm not sure what the implications of that solution would be for the module's state subsystem.

Remaining tasks

User interface changes

API changes

Data model changes

🐛 Bug report
Status

Active

Version

4.0

Component

Code

Created by

🇫🇷France bedlam Lyon

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024