Updated Vortex to 1.41.0. - #316
Conversation
Took the Lagoon base image bump to 26.8.0, the hadolint inline ignores that replace the file-global ignore list, and the explicit 'ARG PHP_INI_SCAN_DIR'. Kept npm for the theme build: this project migrated the 'drevops' subtheme to npm and ships 'package-lock.json', so the template's yarn default does not apply.
Bumped the Lagoon commons image to 26.8.0 and ClamAV to 1.5.4, and replaced the file-global hadolint ignore list with per-line ignores that state why each rule is waived. No project divergence in this file.
Raised the InnoDB redo log capacity to 1GB. The image default of 128MB is exhausted during a large dump import faster than the log checkpointer reclaims it, aborting with 'ERROR 1114 ... table is full'. Paired with the config path move in '.docker/database.dockerfile'.
Bumped the MySQL image to 26.8.0 and moved the server config from '/etc/my.cnf.d/' to '/etc/mysql/conf.d/', which is the directory the entrypoint rewrites before starting the server. Without the move the redo log setting added to 'my.cnf' would be ignored.
Bumped the Lagoon nginx-drupal image to 26.8.0 and moved the hadolint waivers inline. No project divergence in this file.
Bumped the Lagoon php-fpm image to 26.8.0 and moved the hadolint waivers inline. No project divergence in this file.
Bumped the Lagoon solr-9-drupal image to 26.8.0 and moved the hadolint waivers inline. The Solr config-set copied into the image is unchanged. No project divergence in this file.
Vortex inverted the file from an allowlist to a denylist, so the build context is now everything except the named paths. Added this theme's build outputs to the exclusion list: the template excludes 'web/themes/**/build', but the 'drevops' subtheme emits 'dist', 'storybook-static' and 'components_combined', which would otherwise be copied into the image and then overwritten by the in-image build.
Added a JavaScript 'max_line_length' of 160 so editors agree with the Prettier 'printWidth' raised in '.prettierrc.json'. No project divergence in this file.
Raised 'printWidth' from 80 to 160 and pinned JSDoc comments to 80 via 'jsdocPrintWidth', so code stays on one line while doc comments keep the narrow wrap. No project divergence in this file.
Raised the Drush 'memory_limit' from 512M to 1G. This project runs config sync and database imports through Drush in CI and on deploy, which are the operations the limit is sized for. No project divergence in this file.
Added the missing final newline. No project divergence in this file.
Added the missing final newline to all five files. Grouped into one commit because the change is byte-identical across them and carries no per-file decision. No project divergence in these files.
Took the only upstream change, the analysed PHP version moving from 8.4.21 to 8.4.23. Restored the project's own settings that the re-render dropped: the '.artifacts/phpstan' tmpDir, the 'scripts/composer/ScriptHandler.php' exclusion, and the ignore for the AI module's ProviderProxy '__call()' forwarding.
Replaced the hardcoded 'Drupal9SetList'/'Drupal10SetList' with the composer-based set provider, which binds the Drupal deprecation sets to the installed core version so the set tracks core upgrades without editing this file. Also took the two new foreach-rename skips and the scoping of 'RemoveUnusedPublicMethodParameterRector' to 'src/Hook/*', which matches the hook classes in do_base, do_feed and do_content_api. The set-provider API requires 'palantirnet/drupal-rector' ^1.x, so this file depends on the constraint bump made in the composer reconciliation.
Took the 'ENVIRONMENT_TYPE' pass-through, which lets the auto-detected environment type be overridden, and the hyphenated fallback for the image name. Restored the project's 'DRUPAL_AI_PROVIDER_GEMINI_API_KEY' pass-through that the re-render dropped. The database, valkey and chromium image bumps in this update were already at or ahead of the template here, so they are unchanged.
Took the two upstream changes: an explicit 'shell: bash' on the pre-deployment backup and database fetch tasks, which otherwise run under sh and mis-parse the bracket tests, and the task name spelling. Kept the project's own configuration that the re-render reset: the production and develop 'routes' blocks naming the real domains, and the absence of 'monitoring_urls' and the top-level 'routes: insecure: Redirect'. The upstream patch does not touch either of those, so re-adding them would have been the re-render undoing a project decision rather than an update.
Extended the container-image group to '.github/workflows/**' and added a regex manager that reads image tags out of 'docker run' invocations. This update pins 'hadolint/hadolint:v2.15.1' and 'gitleaks:v8.30.1' inside workflow steps, and without these managers those tags would never be updated. The '.circleci' patterns are inert here and kept for template parity. The project's 'Australia/Melbourne' timezone is unchanged.
…aceb9e. Adopted the template's version of this script, which adds an early bail-out in production, moves from the deprecated 'pm:enable' to 'pm:install', tolerates modules missing from '--no-dev' builds, and corrects the 'Drupal\Core\Site\Settings' namespace casing. Re-added the Testmode module, which the template's version does not install. Behat scenarios tagged '@Testmode' restrict lists to test content and the module is excluded from exported configuration, so provisioning is the only place it gets installed.
Took the standard message helpers and the 'composer_run' wrapper, which suppresses Composer's progress output during this bootstrap and replays it on stderr only when a command fails, so the ahoy entrypoint stays quiet without losing diagnostics. This project's local fix that removes an existing tooling directory before the move has since landed upstream, so the file now matches the template with no divergence.
Resets the search tracker and reindexes on local, ci, dev and stage, skipping production. This project runs Solr through 'search_api_solr' but had no indexing step in provisioning, so search content was only indexed by cron or by hand after a database restore. Set 'DRUPAL_SEARCH_INDEX_SKIP=1' to turn it off for an environment.
Moved the default version bump from the removed top-level 'version-resolver' key to a 'version-resolver' category entry, which is where release-drafter now reads it. Left as it was, the default minor increment would be ignored and drafted releases would resolve their version incorrectly.
Bumped the pinned 'toshimaru/auto-author-assign' SHA to v3.1.0.
…eb9e. Read the Lagoon webhook endpoint from 'vars' rather than 'env'. The step declared no 'env' block of its own, so the old reference resolved to an empty string and the override silently fell back to the hardcoded default.
…ceb9e. Granted the job 'issues: write', which Renovate needs to maintain its Dependency Dashboard issue, and bumped the pinned checkout, setup-node and renovate action SHAs. This repository already has 'renovate.json' and a 'RENOVATE_TOKEN', so the workflow is live rather than dormant.
…ceb9e. Bumped the pinned checkout and release-drafter action SHAs. The release-drafter bump is what reads the 'version-resolver' category introduced in '.github/release-drafter.yml'.
Took the reworked trigger gate: 'VR_DIFFY_AUTO_BRANCHES' becomes 'VR_DIFFY_PR_SKIP_BRANCHES', a new 'VR_DIFFY_BRANCHES' opts whole branches in outside the PR flow, and the branch matching moves into shared helpers. Neither variable is set on this repository, so the gate keeps its current behaviour of running on the 'VR' label with 'deps/*' bypassing it. This project's own additions to the file - the run-summary step, the summary job output and the 'pages_changed' jq fix - have since landed upstream, so the file now matches the template with no divergence.
Receives the Composer audit and Gitleaks steps that this update removes from 'build-test-deploy.yml', so a failing security check is distinguishable from a failing linter and can be re-run on its own. Declining it would have dropped both scans entirely. Needs no new tokens or services - it runs in the same ci-runner image and reads the existing 'VORTEX_CI_COMPOSER_AUDIT_IGNORE_FAILURE' and 'VORTEX_CI_GITLEAKS_IGNORE_FAILURE' variables. The audit now runs with '--locked', so it resolves against 'composer.lock' rather than the installed tree.
…b9e. Moved the Composer audit and Gitleaks steps out to the new 'audit.yml' workflow, bumped the ci-runner image to 26.8.0, pinned 'hadolint/hadolint' to v2.15.1 so Renovate can track it, and bumped the checkout action. Added an opt-in 'Free up disk space on the runner' step gated on the 'CI_FREE_DISK_SPACE' variable, pruned dangling images after the stack starts, and removed the database dump from the runner once it is inside the container so the job does not hold two copies. Kept npm for the theme lint step. The root of this repository uses yarn and the 'drevops' subtheme uses npm, so the template's blanket yarn default is correct at the root and wrong for the theme.
Added the 'ENVIRONMENT_' prefix to the environment variable filter for the cli command, so the 'ENVIRONMENT_TYPE' override introduced in 'docker-compose.yml' reaches the container instead of being dropped at the boundary.
| } | ||
|
|
||
| // Replace below with a call to your class method. | ||
| // Replace the line below with a call to the method under test. |
There was a problem hiding this comment.
Template scaffold example test: method and data-provider renames, the unit:subtraction group prefix collapsed to subtraction, and the placeholder comments reworded. No RunTestsInSeparateProcesses here - the rector rule targets kernel and functional tests, not unit tests.
| use Drupal\do_content_api\Hook\ModerationPolicyHook; | ||
| use PHPUnit\Framework\Attributes\CoversClass; | ||
| use PHPUnit\Framework\Attributes\Group; | ||
| use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; |
There was a problem hiding this comment.
#[RunTestsInSeparateProcesses] added for the rector rule. Attribute only; the moderation-policy assertions are unchanged.
This is the class used to measure the cost of the isolation change - 64.7s with the attribute against 73.2s without, over the same 8 tests - which is what established that the rule is not slowing the suite down.
|
|
||
| if (!$entity->isNew()) { | ||
| $original = $entity->original ?? NULL; | ||
| $original = $entity->getOriginal() ?? NULL; |
There was a problem hiding this comment.
The only production code change in this PR outside settings files.
Two reads of $entity->original become $entity->getOriginal(). The property is deprecated in favour of the accessor, which returns ?static and is present in the installed core 11.4.5, so the two are equivalent here.
Flagged by rector's ReplaceEntityOriginalPropertyRector, which reached this project through the set-provider migration in rector.php: the deprecation sets are now bound to the installed core version rather than the hardcoded Drupal 9 and 10 lists, so rules newer than those lists now apply. This is the concrete payoff of that change rather than a coincidence.
| use PHPUnit\Framework\Attributes\CoversClass; | ||
| use PHPUnit\Framework\Attributes\DataProvider; | ||
| use PHPUnit\Framework\Attributes\Group; | ||
| use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; |
There was a problem hiding this comment.
#[RunTestsInSeparateProcesses] added for the rector rule. Attribute only; the form assertions are unchanged.
| use PHPUnit\Framework\Attributes\CoversClass; | ||
| use PHPUnit\Framework\Attributes\Group; | ||
| use Drupal\do_feed\Hook\EntityDeleteHook; | ||
| use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; |
There was a problem hiding this comment.
#[RunTestsInSeparateProcesses] added for the rector rule. Attribute only.
| use PHPUnit\Framework\Attributes\CoversClass; | ||
| use PHPUnit\Framework\Attributes\Group; | ||
| use Drupal\do_feed\Hook\EntityPresaveHook; | ||
| use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; |
There was a problem hiding this comment.
#[RunTestsInSeparateProcesses] added for the rector rule. Attribute only - notably the assertions did not need changing despite the hook under test moving from $entity->original to $entity->getOriginal(), since the test drives the hook through entity saves rather than stubbing the property.
| declare(strict_types=1); | ||
|
|
||
| if ($settings['environment'] === ENVIRONMENT_CI) { | ||
| // Disable mail send out. |
There was a problem hiding this comment.
Drops a comment that restated the line below it. No behaviour change - mail is still suspended in CI.
| * Redis module works with Redis services. | ||
| * We use `DRUPAL_REDIS_` environment variables as the Drupal | ||
| * module name is `redis`. | ||
| * The `DRUPAL_REDIS_` environment variable prefix follows the Drupal module |
There was a problem hiding this comment.
Mostly a comment rewrite, but two real fixes are in here.
@phpcs:disable becomes phpcs:disable. With the leading @ those annotations were parsed as docblock tags rather than sniff directives, so the three suppressions at the top of this file were never actually applied - the sniffs were live the whole time.
The container class string loses its leading backslash: '\Drupal\redis\Cache\PhpRedis' becomes 'Drupal\redis\Cache\PhpRedis'. It is a plain string consumed by the container builder, not a resolved class name, and the leading separator is not part of the class name.
Redis is live here - DRUPAL_REDIS_ENABLED gates it and the service is in the compose stack - so this file is executed rather than dormant.
|
|
||
| if ($settings['environment'] === ENVIRONMENT_CI || $settings['environment'] === ENVIRONMENT_LOCAL) { | ||
| // Disable CSP locally and in CI as we do not serve the site over HTTPS. | ||
| if ($settings['environment'] === ENVIRONMENT_LOCAL || $settings['environment'] === ENVIRONMENT_CI) { |
There was a problem hiding this comment.
Comment rewrite and a reordering of the environment check to read local-then-CI, matching the other settings includes. Behaviour is identical: CSP stays disabled locally and in CI, where the site is not served over HTTPS.
|
|
||
| declare(strict_types=1); | ||
|
|
||
| // Default Shield credentials. |
There was a problem hiding this comment.
Comment rewrite and the same local-then-CI reordering as the other settings includes. No behaviour change: Shield stays enforced on every non-production environment and bypassed locally and in CI.
The retained comment is the load-bearing part - unlike the other settings files, enablement here deliberately does not follow the presence of environment variables, because Shield must stay on even when the credential variables are missing. Inverting that would silently unprotect an environment.
|
|
||
| declare(strict_types=1); | ||
|
|
||
| // Add custom domains to trusted host patterns if specified. |
There was a problem hiding this comment.
Drops a comment that restated the line below it. No behaviour change.
| '\.', '', '', '|', | ||
| ], $localdev_url); | ||
| $settings['trusted_host_patterns'][] = '^' . $container_patterns . '$'; | ||
| $container_localdev_url = getenv('LOCALDEV_URL'); |
There was a problem hiding this comment.
A real fix rather than a tidy-up. The trusted host pattern was built by a hand-rolled str_replace that escaped only dots and folded a comma-separated list into a single anchored alternation. Any other regex metacharacter in LOCALDEV_URL reached the pattern unescaped, and the alternation inside one ^...$ did not mean what it looked like.
Now each URL is split out, lowercased and escaped with preg_quote, producing one anchored pattern per host. The local variables are also prefixed so they cannot collide with the including scope - this file is included into settings.php, so a bare $patterns was shared state.
Covered by a new test in EnvironmentSettingsTest added in this PR, which passes two URLs with surrounding whitespace and a trailing empty entry and asserts both generated patterns.
| declare(strict_types=1); | ||
|
|
||
| if (!empty(getenv('LAGOON_KUBERNETES'))) { | ||
| // Environment is marked as 'production' in Lagoon. |
There was a problem hiding this comment.
The same trusted-host fix as the container settings, applied to LAGOON_ROUTES: each route is split out and escaped with preg_quote rather than folded into one alternation that escaped only dots.
This is the one that was actually in use. This project serves several routes per environment - drevops.com and www.drevops.com on production, dev.drevops.com on develop - so the old single-alternation pattern was the code path running on every Lagoon environment, not a theoretical case.
The rest is comment removal where the comment restated its line.
| $app_root ??= DRUPAL_ROOT; | ||
| $site_path ??= 'sites/default'; | ||
| // @phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable | ||
| // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
There was a problem hiding this comment.
@phpcs:ignore corrected to phpcs:ignore. As with the Redis settings, the leading @ made PHPCS read it as a docblock tag rather than a sniff directive, so the unused-variable suppression on the $contrib_path assignment was never applied - the sniff was live and simply had nothing to report yet.
The other change is a comment rewording on the environment-type override. This project's own settings additions in this file are unchanged.
These were added on top of the template's deny list rather than as part of the Vortex update, so they are out of scope for this branch. The theme build output paths stay, because those close a gap the template's own list leaves open for this project's subtheme.
This comment has been minimized.
This comment has been minimized.
Follows the template to the 4.x line. The exported configuration needed no change: the 4.x schema declares the same seven keys the site already stores, and 'drush config:status' reports no difference after the update. The single post-update hook only clears caches. The module keeps its role here unchanged - 'settings.stage_file_proxy.php' sets the origin from 'DRUPAL_STAGE_FILE_PROXY_ORIGIN' on every non-production environment and injects the Shield credentials into it, and none of that surface moved in 4.x. Core requirement is '^11.3 || ^12.0' against the installed 11.4.5.
This comment has been minimized.
This comment has been minimized.
…tainer. The filter matched a prefix anywhere in a variable name, so a host variable such as 'MY_DRUPAL_SECRET' or 'COMPANY_GITHUB_TOKEN' was forwarded into the container alongside the intended ones. Each alternative is now anchored at the start, and 'TERM' at both ends so it no longer matches names like 'ITERM_PROFILE'. Implements the fix raised as drevops/vortex#3023, which the template has since adopted, so this file returns to parity rather than diverging.
The three installs suppressed a non-zero Drush exit status and then printed a success message, so a module that failed to install left provisioning reporting success with the tool missing. The suppression was originally kept on the grounds that hosting environments build with '--no-dev' and would not have these modules present. That reasoning was wrong: devel, sdc_devel, testmode and generated_content are all in 'require' rather than 'require-dev', so they ship to every environment and the installs are expected to succeed wherever the script runs. The template reached the same conclusion in this release.
The installed ref is the 1.41.0 release preparation, so the badge records the release rather than the commit it was built from. Also converged two files with the template, both of which originated here: the multi-URL trusted-host test now matches the upstream version of the same test, and the 'getProtectedValue()' docblock takes the corrected wording that went with the fix.
|
Code coverage (threshold: 80%) Per-class coverage |
Checklist before requesting a review
[#123] Verb in past tense.- no ticket; this is a template update#123added to description - no ticket; this is a template updateChangedsectionChanged
Covers all upstream work between the
1.40.2release and the1.41.0release preparation - roughly five weeks. The badge records1.41.0.Key highlights: Security scanning moves out of the main build into its own
Security auditworkflow, so a failing audit is distinguishable from a failing linter and can be re-run alone. All Lagoon container images move to26.8.0, and the database container gains a 1GB InnoDB redo log so large production dumps stop aborting mid-import..dockerignoreand.gitignoreboth flip from allowlists to deny lists. The refactoring toolchain switches to a provider that binds its rule sets to the installed Drupal version rather than a hardcoded list, which immediately surfaced a deprecated entity API call in this codebase.Overall impact: No runtime code paths change and Drupal core is untouched, so the site behaves identically. The visible day-to-day differences are in CI - a new required check appears on pull requests, and the build job reclaims runner disk space when opted in. There are no breaking changes for developers. One thing is left for a conscious decision later: the template now hard-gates homepage accessibility while this project still audits everything in advisory mode.
Vortex Update
CI
Split Gitleaks and
composer auditinto a standaloneSecurity auditworkflow, so a failing security scan no longer looks like a failing linter and can be re-run on its own. This adds one new check to every pull request.composer auditnow runs with--locked, resolving advisories againstcomposer.lockrather than the installed tree, so the result no longer depends on whether dev dependencies are present.Added an opt-in "Free up disk space" step to the build and database jobs, gated on a
CI_FREE_DISK_SPACErepository variable. It removes preinstalled runner toolchains this project never uses. It is off unless the variable is set.The database dump is now deleted from the runner once it has been copied into the container, so the job stops holding two copies of a 31MB file for its remaining lifetime.
Pinned
hadolinttov2.15.1instead of trackinglatest, and taught Renovate to read image tags out ofdocker runlines in workflows so those pins actually get updated.Bumped the CI database cache key to
v26.8.0, which discards the existing cache once - the first build on this branch refetches the database rather than restoring it.Release drafter's default version bump moved to a
version-resolvercategory. Left on the old top-level key it would have been ignored, and drafted releases would have resolved the wrong version.The Lagoon webhook endpoint is now read from
varsrather thanenv. The step declared noenvblock, so the override silently resolved to an empty string and always fell back to the hardcoded default.Docker and local environment
All Lagoon images move to
26.8.0across the CLI, PHP, Nginx, Solr, ClamAV and database containers, with ClamAV itself on1.5.4.Raised the InnoDB redo log capacity to 1GB. The image default of 128MB is exhausted during a large dump import faster than the checkpointer reclaims it, aborting with
ERROR 1114 ... table is full.Moved the database config to
/etc/mysql/conf.d/, which is the directory the entrypoint actually rewrites - without the move the redo log setting above would have been ignored..dockerignoreis now a deny list, so everything not named is included rather than the reverse. This project's theme build outputs (dist,storybook-static,components_combined) were added to the exclusions, since the template only knows aboutbuild.Replaced file-global hadolint ignores with per-line ones that state why each rule is waived, so a new violation is no longer hidden by a blanket suppression at the top of the file.
The theme still builds with npm here. The template switched to yarn; this project ships
package-lock.jsonfor thedrevopssubtheme, so npm was kept in both the Docker build and the CI lint step.Provisioning
Provisioning is now split into numbered scripts - demo modules, development modules, search indexing and an example - replacing the single example script.
Added search indexing to provisioning, resetting the tracker and reindexing on local, CI, dev and stage. This project runs Solr but had no indexing step, so search content was only indexed by cron or by hand after a database restore. Set
DRUPAL_SEARCH_INDEX_SKIP=1to disable it per environment.Development modules now bail out early in production and install with
pm:installrather than the deprecatedpm:enable, tolerating modules absent from--no-devbuilds.Testmode is installed during provisioning. The template did not install it, which would have broken every
@testmodeBehat scenario. Raised upstream and fixed in 1.41.0, so this file is at template parity rather than carrying a local addition.Module installs no longer discard their exit status. The three
pm:installcalls suppressed a non-zero Drush exit and then printed success, so a failed install left provisioning reporting success with the tool missing. All four modules are declared inrequirerather thanrequire-dev, so they ship to every environment and the installs are expected to succeed wherever the script runs.Raised the Drush
memory_limitto 1G, sized for the config sync and database imports this project runs on every deploy.Testing
Wired six more behat-steps traits into
FeatureContext- Cache, Iframe, Json, Redirect, Rest and Xml - making their steps available immediately, since all of them already existed in the installed library.Removed two step definitions the library now provides. behat-steps 3.13.0 absorbed
should be pinned to the top of the viewportandshould stack above the element, and a duplicate step definition aborts the whole suite before any scenario runs. The library implementations are stronger: the stacking assertion walks the stacking-context chain rather than comparing raw z-index values that are only meaningful within one context, and the pinned assertion allows two pixels of rounding and rejects a zero-height element that would otherwise report as pinned at the origin.Added scenarios covering REST, XML and JSON assertions, viewport resizing and redirects, along with two response fixtures and a new
redirect.feature.Kernel and functional tests now run in separate processes. Measured on one class this costs no time - 64.7s with isolation against 73.2s without.
The project's own test coverage was preserved throughout. The re-render would have replaced the sitemap, search, accessibility, ClamAV and Behat feature files with template versions, dropping the blog and project sitemap scenarios, the CivicTheme media bundles and the 24-region region map.
Code quality tooling
Rector now resolves its Drupal rule sets from the installed core version rather than hardcoded Drupal 9 and 10 lists, so the checks track core upgrades without editing configuration. This required a major bump of the rules provider.
That change immediately found a deprecated API call - two reads of
$entity->originalin the feed presave hook now useEntityInterface::getOriginal().Raised Prettier's
printWidthfrom 80 to 160 while pinning doc comments to 80, so code stays on one line and comments keep the narrow wrap. One JavaScript file was reformatted as a result.RemoveUnusedPublicMethodParameterRectoris now scoped tosrc/Hook/*rather than skipped everywhere, which matches the hook classes indo_base,do_feedanddo_content_api.Settings and configuration
Trusted host patterns are now built with
preg_quoteover each route individually, instead of a hand-rolled replacement that escaped only dots and folded every route into one alternation. Any other regex metacharacter inLAGOON_ROUTESorLOCALDEV_URLpreviously reached the pattern unescaped.Corrected
@phpcs:ignoretophpcs:ignoreinsettings.phpand the Redis settings. With the leading@the suppressions were read as docblock tags and never applied.Added an
ENVIRONMENT_TYPEpass-through through Docker Compose, the ahoy container filter and the settings test harness, so the auto-detected environment type can be overridden.Anchored the environment variable prefixes forwarded into the CLI container. The filter matched a prefix anywhere in a name, so a host variable such as
MY_DRUPAL_SECRETorCOMPANY_GITHUB_TOKENwas forwarded alongside the intended ones. Raised upstream and fixed in 1.41.0.Fixed
getProtectedValue()reading the property from the reflection class rather than the object, which raised aTypeErrorfor any non-static property. This repository already carried the fix; 1.41.0 adopts it, so the file returns to template parity..gitignoreis now a deny list. Verified against this project: no file becomes newly visible, and the files directory, simpletest and local settings overrides all remain ignored.Added
.vortex-manifest.json, a checksum for every template-owned path. A later update reads it to tell whether a file has been modified since it was installed, which is what lets the installer prune paths the template no longer ships without destroying local changes.Dependency Updates
Drupal core is unchanged at
11.4.5. Every changed package is a development dependency exceptdrupal/stage_file_proxy, which is a development-environment module: it proxies files from production so they do not have to be copied down, and is inert in production.Composer
Updated
drevops/behat-steps3.12.0 → 3.13.0drevops/vortex-tooling1.3.0 → 1.4.0mglaman/phpstan-drupal2.1.1 → 2.1.2drupal/stage_file_proxy3.1.6 → 4.0.0 (major)palantirnet/drupal-rector0.21.2 → 1.1.2 (major)rector/rector2.6.1 → 2.6.2Added
softcreatr/jsonpath0.10.0Removed
Node
No changes to
package.jsonin either the repository root or the theme.Not included
Three things were deliberately left out of this update:
drupal/reroute_emailwas declined. It surfaced only because the installer was answered with every module option so that declined packages become visible; the settings file generated for it was removed.The accessibility gate was not tightened. The template now asserts the homepage passes accessibility checks as a hard gate and audits secondary pages in advisory mode; this project continues to audit everything in advisory mode.
Separately,
composer auditreportsSA-CONTRIB-2026-096againstdrupal/diff. That advisory pre-dates this branch and is unrelated to the update.Screenshots
N/A - this change touches CI configuration, Docker files, settings includes and tests. Nothing user-facing is rendered differently.
Before / After
Security scanning and the build shared one workflow, so an audit failure and a lint failure were indistinguishable and could not be re-run apart:
They now run in their own workflow, and provisioning is split into ordered, individually replaceable scripts: