Ansible templates delegate_to before it evaluates the task's when, so a task delegating to N8N_HOST_NODE kills the play with 'N8N_HOST_NODE' is undefined whenever the resolver that sets it was skipped, even though the delegating task would have been skipped too. 43e09ebf0d put the resolver inside the same conditional block. Run 34653754175 shows the pair directly above the failure: the include skipped on the false condition while the setup call had returned status 200, and the play ended at 01_bootstrap.yml:92.
The resolver now runs unconditionally, before the block. It costs one lookup per deploy and changes no state.
The new lint reads the class rather than this instance: a conditional resolve_host_cid include whose PREFIX_HOST_NODE a delegate_to in the same role reads, unless an unconditional resolver or set_fact defines that prefix role-wide. The walker carries the condition through block, rescue and always, so an include nested in a block does not read as unconditional. Against the pre-fix file it reports would flag: ['N8N'].
It found one more: web-app-yourls/tasks/install.yml wrapped its tasks in a block whose when repeated the IS_STACK_HOST condition that main.yml already carries on the include. The wrapper is gone and the tasks are dedented; nothing had broken there because the condition always held.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
n8n accepts the owner password only at /rest/owner/setup, which answers
400 "Instance owner already setup" once an owner exists. After the CI
rotated owner_password between the passes, the probe got 401, setup got
400, the assert accepted "already setup", and the owner kept the old
password: the Playwright owner login failed in n8n#1 and the AI gateway
login in n8n#0 got 401 and 429 (run 34615516009, jobs 103327034581 and
103327034619).
Only in exactly that state, probe 401/403 plus "already setup", a node
script now runs inside the n8n container with n8n's own modules and
DB_POSTGRESDB_* settings: it compares the stored bcrypt hash with the
deployed password, writes a fresh bcryptjs hash when they differ, and
prints CHANGED or OK. A single confirming login then requires 200, so a
failed write stops the deploy with a clear status. Fresh hosts and deploys
whose password already matches never run the script. The pattern follows
web-app-flowise's identity_password.js.
The module path was measured in n8nio/n8n:1.100.1: bcryptjs and pg
resolve from /usr/local/lib/node_modules/n8n/node_modules, pg's
transitive modules load, and bcryptjs hashes as $2a$ like n8n.
no_log moves from the bootstrap include's apply to the four tasks that
carry the password, so the setup assert and the host and container
resolution stay readable when they fail.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
meta/schema.yml held credential definitions and their runtime values, but the
name said 'schema' and read like structural metadata next to services.yml and
volumes.yml. Nothing in the file is a schema in the sense the other meta files
use the word, and a contributor had to open it to learn it holds secrets.
62 role files renamed. ROLE_FILE_META_SCHEMA becomes ROLE_FILE_META_SECRETS and
keeps its role as the SPOT the path is built from.
Two readers bypassed that constant and spelled the name themselves:
utils/cache/applications.py built meta_dir / 'schema.yml' twice, and
plugins/lookup/application_gid.py carries the filename in the marker list it
detects application roles by. Left behind, the rename would not have raised —
credentials would have resolved empty and the role would have stopped counting
as an application.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add tests/lint/repository/test_task_file_numbering.py: numbered task
files use exactly two leading digits, a numbered *_core.yml must be
00_core.yml, per directory the numbers are unique/consecutive and start
at 01 (00 with a core file), numbered includes appear in ascending
order, and shared helpers live in tasks/utils/ instead of the numbered
chain.
Apply it across every role: rename NN_core.yml to 00_core.yml with a
consecutive down-shift of the siblings, move letter-suffix children into
a subdirectory named after their parent task, relocate helpers included
from more than one place into tasks/utils/, and update every reference
(include_tasks, path_absolute, .ansible-lint-ignore, requirement docs).
Legacy narration comments in the touched files are deleted; the upstream
xwiki.properties reference block opts out via nocheck. The unused
MAILU_IP6_PUBLIC var (only ever named in now-removed comments) is dropped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>