# 0.x to 1.x recipe catalogue
1.x does not provide a dedicated plugin for each 0.x check. Instead, you
reproduce a 0.x check by composing general-purpose collect and analyse
plugins. This page is the recipe catalogue: for every 0.x check it shows the
plugin chain that achieves the same outcome in 1.x.
See The 1.x way: compose, don't port for the reasoning behind this approach.
Reading this table
None of the statuses below mean "waiting for a one-to-one port". Almost every 0.x check is reproducible today by composing plugins that already exist.
- Achievable now — a documented recipe and a working example in
examples/exist. Copy the example and adapt it. - Achievable, undocumented — the same plugins reproduce the check, but no worked example is published yet. The plugin chain is listed so you can build it; a published recipe is on the roadmap.
- Needs new capability — no existing building block collects the required data. The 1.x direction is still to be determined (TBD).
# File checks
| 0.x check | Status | 1.x plugin chain |
|---|---|---|
file | Achievable now | file:lookup + not:empty — see examples/files.yml |
file:diff | Needs new capability | TBD |
# Recipe: file
collect:
disallowed-php-scripts:
file:lookup:
path: web
pattern: '^(adminer|phpmyadmin|bigdump)?\.php$'
analyse:
disallowed-php-scripts-found:
not:empty:
description: Disallowed PHP scripts found
input: disallowed-php-scripts
Source: examples/files.yml
# YAML / JSON checks
| 0.x check | Status | 1.x plugin chain |
|---|---|---|
yaml | Achievable now | file:read + yaml:key + equals / allowed:list — see examples/drupal-config.yml |
json | Needs new capability | Needs a json:key fact plugin (analogous to yaml:key) — on the roadmap |
# Recipe: yaml
collect:
extension-file:
file:read:
path: core.extension.yml
modules:
yaml:key:
input: extension-file
path: module
keys-only: true
analyse:
required-modules:
allowed:list:
description: Required modules are not enabled
input: modules
required:
- seckit
- lagoon_logs
Source: examples/drupal-config.yml
# Drupal checks
Every Drush-based Drupal check follows the same pattern: run a command (or
docker:command) to fetch data, parse it with yaml:key where needed, then
assert with allowed:list or equals. See the
worked recipe below.
| 0.x check | Status | 1.x plugin chain |
|---|---|---|
drush-yaml | Achievable now | docker:command + yaml:key + equals — see examples/drush-over-docker.yml |
drupal-file-module | Achievable now | file:read + yaml:key + allowed:list — see examples/drupal-config.yml |
drupal-db-module | Achievable now | command + allowed:list — see examples/drupal-db-module.yml |
drupal-db-permissions | Achievable now | command + allowed:list — see examples/drupal-db-permissions.yml |
drupal-db-user-tfa | Achievable now | command + equals — see examples/drupal-db-user-tfa.yml |
drupal-admin-user | Achievable now | command + allowed:list — see examples/drupal-admin-user.yml |
drupal-user-forbidden | Achievable now | command + equals — see examples/drupal-user-forbidden.yml |
drupal-role-permissions | Achievable now | command + allowed:list — see examples/drupal-role-permissions.yml |
drupal-user-role | Achievable now | command + allowed:list — see examples/drupal-user-role.yml |
drupal-tracking-code | Achievable now | command + equals — see examples/drupal-tracking-code.yml |
# Recipe: drush-yaml via Docker
connections:
docker-cli:
docker:exec:
container: my-app
collect:
tfa-config:
docker:command:
connection: docker-cli
command: ["/app/vendor/bin/drush", "config:get", "tfa.settings"]
tfa-status:
yaml:key:
input: tfa-config
path: enabled
analyse:
tfa-enabled:
equals:
description: TFA must be enabled
input: tfa-status
value: "true"
Source: examples/drush-over-docker.yml
# Recipe: the Drush composition pattern
Every Drush-based check above follows the same shape: run a command fact that
emits the data one item per line, then assert with allowed:list or equals.
collect:
# 1. Collect: run drush and emit the machine name of each super-admin role.
admin-roles:
command:
cmd: bash
args:
- -c
- |
set -o pipefail
drush role:list --format=json \
| jq -r 'to_entries[] | select(.value.is_admin == true) | .key'
analyse:
# 2. Assert: fail if any role outside the allowed set is present.
admin-roles-check:
allowed:list:
description: Unexpected role carries the is_admin flag
input: admin-roles
# `command` output is a map; `key: stdout` selects stdout, which
# `allowed:list` then splits into one entry per line.
key: stdout
allowed:
- administrator
Source: examples/drupal-admin-user.yml
Swap the command and the allowed:list / equals assertion to reproduce any
of the other Drush-based checks — the shape stays the same.
# Code quality checks
| 0.x check | Status | 1.x plugin chain |
|---|---|---|
phpstan | Achievable now | static-analysis + static-analysis:breaches — see examples/phpstan.yml |
sca:application_type | Needs new capability | TBD |
# Recipe: phpstan
collect:
phpstan-check:
static-analysis:
tool: phpstan
config: phpstan.neon
paths: [web/modules/custom]
analyse:
phpstan-issues:
static-analysis:breaches:
description: PHPStan found code quality issues
input: phpstan-check
max-issues: 0
Source: examples/phpstan.yml
# Infrastructure checks
| 0.x check | Status | 1.x plugin chain |
|---|---|---|
docker:base_image | Achievable now | docker:images + allowed:list — see examples/docker.yml |
crawler | Needs new capability | TBD |
# Recipe: docker:base_image
collect:
dockerfile-paths:
yaml:key:
input: compose-services-nodes
path: build.dockerfile
dockerfiles:
file:read:multiple:
input: dockerfile-paths
base-images:
docker:images:
input: dockerfiles
no-tag: true
analyse:
disallowed-base-image:
allowed:list:
description: Disallowed base image found in Dockerfiles
input: base-images
allowed:
- uselagoon/php-8.2-fpm
- uselagoon/nginx-drupal
deprecated:
- uselagoon/php-8.1-fpm
Source: examples/docker.yml
# Summary
| Status | Count |
|---|---|
| Achievable now | 14 |
| Achievable, undocumented | 0 |
| Needs new capability | 4 |
The plan for the remaining capabilities is on the roadmap page.