Files
computer-playbook/docs/contributing/actions/testing/suppression.md
T
kevinveenbirkenbachandClaude Opus 5 685c6b50ec test(images): require a mount for every VOLUME an image declares
An unmounted VOLUME does not fail: docker creates an anonymous volume for
it, the container works, and the gap shows up later as a volume nobody can
attribute. sys-ctl-hlth-volumes fails the deploy over exactly that, and its
whitelist keys on volume ids, which are new on every deploy, so the gap
cannot be suppressed there either. e0b973f9bb fixed one such case in
web-svc-xmpp by hand; this is the check that would have found it.

Attribution is the whole difficulty. meta/services.yml declares an image
under a key, and the compose file often runs it under another name:
web-app-jitsi declares the image under 'jitsi' and renders the service as
'web', web-app-erpnext runs one image as seven services, and the two RDBMS
consumer keys name no service of their own because the container comes from
sys-svc-rdbms. The sweep therefore unions the entry key with its
proxy.service_key and delegates the RDBMS keys to their provider role. A
first version keyed on the entry alone and reported six roles that mount
every path correctly, web-svc-xmpp among them.

Reading a config blob section is now its own module beside the registry
client, because the two readers were the same walk twice and registry.py
sat three lines under the file-size cap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-17 21:17:25 +02:00

56 KiB

Suppression Markers 🚫

The unified # noqa / # nocheck syntax that suppresses individual checks across the infinito-nexus test suite.

You MUST use these markers only when the check genuinely does not apply. You MUST NOT use them to silence legitimate issues.

Grammar 📐

A suppression marker is a comment carrying one or more rule keys:

<comment-prefix> (noqa|nocheck): <rule>(, <rule>)*

noqa and nocheck are case-insensitive synonyms in the parser. Every project rule MUST use nocheck: because # noqa: <code> is also parsed by ruff as a flake8 directive and warns on non-flake8 keys. Reserve noqa: for real flake8 / ruff codes (E402, F401, …). test_noqa_only_ruff_codes.py hard-rejects # noqa: <code> whose codes do not match [A-Z]+\d+.

<rule> is a kebab-case identifier from the catalog below. Multiple rules MAY be combined comma-separated.

Prefix Use in
# Python, YAML, shell, conf, INI, …
// JS, JSONC, …
{# … #} Jinja2 templates
<!-- … --> HTML, Markdown

Implementation: suppress.py.

Position semantics 📍

The placement rule is per check. The catalog "Position" column uses these labels.

Label Meaning
same line Marker MUST be on the construct's line.
same line / span Marker MUST be on the construct's line or any physical line spanned by a multi-line call.
line above Marker MUST be on the immediately preceding non-empty line. Blank lines break the association.
same or above Either of the above is accepted.
comment block above Marker MAY sit on any line of a contiguous comment block above the construct. No blank line between marker and construct.
entry block Marker MAY sit on the construct's line or on any comment line above it within the same blank-line-delimited block. Used for .po, where one entry stacks several comments and repeats its text in msgid and msgstr.
head (first 30 lines) Marker MAY appear anywhere in the first 30 lines of the file. For file-level opt-outs that stay visible at the top.
anywhere Marker MAY appear on any line of the file. For whole-file opt-outs.

Catalog 📚

Rule Position Affected test Effect
url same or above, entry block in .po test_urls_reachable.py Skips probing the literal HTTP(S) URL. Use for CDN roots and API base URLs that 4xx without a path.
onion-flag same or above test_onion_port_flag.py Accepts a false under ports.onion. The marker MUST carry a reason naming why that port stays off the node onion; a bare marker is rejected.
docker-version same or above test_image_versions.py, test_semver_pinning.py Skips both the live version-update warning and the non-semver-pin lint for that image's version: key.
repository-version same or above test_repository_versions.py, test_semver_pinning.py Skips both the live ref-update warning and the non-semver-pin lint for that entity's ref: key.
version-source same or above test_version_sources.py Skips the live update warning for a pin that declares its upstream in an update: block.
unwatched-version same or above test_version_pins_are_watched.py Accepts a semver pin that no updater bumps. The marker MUST carry a reason naming why the version stays where it is.
dockerfile-arg-default same or above test_arg_without_default.py Allows the marked ARG to carry a default. The caller normally supplies every build argument so a missing one fails the build instead of selecting a base image nobody chose.
dockerfile-pip-pin same or above test_pip_no_version_pins.py Allows a role Dockerfile to pin an exact version inside a pip install. The pin normally lives in a requirements.txt or pyproject.toml under the role's files/ and is installed with pip install -r, so dependabot's pip ecosystem can raise it.
debian-codename same or above test_no_debian_codename_tags.py Allows an image reference whose tag names a Debian release by codename. Reserved for an upstream that publishes no numeric tag; the marker MUST name which upstream, because a codename pin can never be raised by the updater.
direct-yaml same line / span test_no_direct_calls.py Allows the marked yaml.safe_load / safe_dump call to bypass utils.cache.yaml. MUST use nocheck:, not noqa:.
curl-timeout same or above test_curl_via_filter.py Allows a bare curl invocation without the curl filter or inline --max-time.
redundant-bool-ternary same line test_no_redundant_bool_patterns.py Allows the redundant | bool | ternary('true','false') pattern when a consumer requires the lowercase tokens.
redundant-bool-comparison same line test_no_redundant_bool_patterns.py Allows ... | bool == True/False/true/false when a real tri-state guard is intended (distinguishing None from False).
shared comment block above test_service_shared_consistency.py Marks a service whose enabled: true does not require shared: true.
email line above test_email.py Suppresses the missing-email-integration warning. Pair with enabled: false and shared: false.
logout line above test_logout_dashboard.py Opts a web-app-* role out of the universal-logout integration. Marker MUST be directly above logout:. Pair with enabled: false and shared: false.
dashboard line above test_logout_dashboard.py Opts a web-app-* role out of the dashboard tile integration. Same shape as logout.
sso line above test_sso.py Opts the role's unified services.sso block out. Declares "no login flow"; paired with enabled: false + shared: false.
file-size head (first 30 lines) test_python_file_size.py Opts the entire .py file out of the 500-line cap.
comments-valid head (first 30 lines) test_comments_valid.py Opts the entire file out of the useful-comment check. Reserved for vendored / upstream config templates (e.g. Discourse app.yml) whose inline documentation is all intentional.
info-media head of meta/main.yml (first 30 lines) test_info_homepage_video.py Opts an invokable role out of the required meta/info.yml homepage + video entries. Marker lives in meta/main.yml (a comment-only info.yml would fail the info schema lint). Reserved for fully self-written roles (backups, host plumbing) that have no upstream product page or demo video.
credential-masking same or above test_credential_tasks_are_masked.py Allows the marked task to carry a credential without no_log on itself or a parent. Marker goes on or directly above the task's - name:.
env-default same or above test_no_env_defaults_in_javascript.py Allows JavaScript to substitute a value for an unset environment variable. Reserved for a value the code itself owns and no role renders. Normalising to "", "[]", false, 0 or another process.env entry needs no marker.
jinja-mapping-key same or above test_no_jinja_in_mapping_keys.py Allows a Jinja expression to stand as a mapping key under roles/*/meta/ or roles/*/vars/. Ansible renders the values of a loaded variable structure and leaves the keys as written, so the consumer receives the source text. Marker goes on or directly above the line.
host-node-resolver same or above test_host_node_resolver_is_unconditional.py Allows a conditional resolve_host_cid include whose <PREFIX>_HOST_NODE a delegate_to in the same role reads. Marker goes on or directly above the include's - name:.
project-walk same line / span test_no_raw_project_walk.py Allows a raw Path.rglob, os.walk, or glob.glob call outside the utils.cache.files.iter_project_files contract.
cache-read same line / span test_no_uncached_file_reads.py Allows a raw Path.read_text / Path.read_bytes call in tests/lint/ outside the LRU-cached utils.cache.files.read_text contract.
lookup-cache-import same or above test_no_cache_imports_in_lookups.py Allows a lookup plugin (plugins/lookup/ or roles/*/lookup_plugins/) to import a config-merge function from utils.cache.applications / .domains / .users instead of reaching the SPOT via lookup_loader.get('applications'/'config'/'domains'/'users'). Reserved for the SPOT providers (applications / config / applications_current_play / users / domains) and the raw-volume accessors (volume / nginx).
run-once anywhere test_run_once_tags.py, test_schema.py Marks a role's tasks/main.yml as intentionally re-runnable. Skips both the run-once tag check and the suffix check.
run-once-suffix same line test_schema.py Allows a single when: item to reference a run_once_<other> flag whose suffix differs from the current role.
raw-docker same or above; head (first 30 lines) test_no_raw_docker.py Marks a single line or a whole file under roles/ as legitimately calling docker / docker compose / docker-compose directly.
hardcoded-dns-resolver same or above test_no_hardcoded_dns_resolvers.py Marks a line that needs a literal IP from NETWORK_PUBLIC_DNS_RESOLVERS where the substitution point cannot consume the variable (CoreDNS non-Jinja templates, host-bootstrap shell, doc examples).
dynamic-flag same line OR comment block above key test_dynamic_flags.py Marks a roles/*/meta/services.yml flag whose value stays literal. Per-flag (same line) for databases. Block-level (comment block above) when both flags stay literal. Second sanctioned use: the literal enabled: false a lifecycle: eol provider's key carries in every consumer, which lifecycle.md makes a MUST and which this rule would otherwise report as a missing dynamic flag.
design-off line or comment block above design: test_design_off_reason.py Required with Reason: <text> on a design.enabled: false in a web-app-/web-svc- role. Keeps the role out of the design queue and off the shared CSS.
native-metrics comment block above test_native_metrics_contract.py Marks a role whose services.prometheus.native_metrics.enabled and templates/prometheus.yml.j2 presence are intentionally inconsistent. Reserved for prepared-but-default-off scrape fragments (operator opt-in).
prometheus-scrape same or above test_roles_with_service.py Documents a services.prometheus.scrape: false opt-out in roles/<role>/meta/services.yml. The role keeps services.prometheus.{enabled,shared}: true (so the role-wiring contract stays satisfied) but roles_with_service('prometheus') drops it from PROMETHEUS_TARGET_ROLES_JSON. Reserved for 301-redirect-only vhosts that never serve a request through lua-resty-prometheus, so they emit no app="<role>" label and have no scrape target. The marker accompanies the scrape: data flag the lookup honors.
matomo-track same or above test_roles_with_service.py Documents a services.matomo.track: false opt-out in roles/<role>/meta/services.yml. The role keeps services.matomo.{enabled,shared}: true (so the role-wiring contract stays satisfied) but roles_with_service('matomo') drops it from MATOMO_TARGET_ROLES_JSON and the matomo tracker e2e contract. Reserved for static-file (autoindex) and 301-redirect vhosts that carry no user-facing HTML page worth a _paq tracker. The marker accompanies the track: data flag the lookup honors.
variants-static-override same line test_variants_no_static_override.py Allows a roles/*/meta/variants.yml leaf override of an attribute whose base value in meta/services.yml is a static literal. Place on the override line in variants.yml. Use only when the consumer chain is provably immune to the variant-merge propagation gap; the default is to make the base value dynamic via "{{ '<role>' in group_names }}".
variants-shared-false-once same or above test_variants_shared_false_once.py Exempts one roles/*/meta/variants.yml services.<key>.shared: false pin from the one-local-provider-variant limit for a service whose base meta/services.yml uses literal enabled: true and dynamic shared. Place on the extra shared: false line or service key line. Place above the service key in meta/services.yml to exempt the service.
variants-services-match same or above test_services_match.py Allows a roles/*/meta/variants.yml services.<key> entry to reference a service key that is NOT declared as a top-level entry in meta/services.yml. Reserved for resolver-only matrix hooks (typically on invokable infrastructure roles) whose variant entries pin the round's companion topology via service-key flags the resolver maps to provider roles, with no real consumer contract in the base meta.
variants-auth-isolation same or above test_auth_isolation.py Exempts an auth-isolated variant entry in roles/*/meta/variants.yml (one that enables exactly one of LDAP / OIDC / OAuth2) from the rule that every non-auth service-key in the role's variant union must be pinned to literal false. Place on the leading - services: line of the variant or on the line above. Use only when the broader closure is intentional.
variant-tor-collateral same or above test_variant_tor_collateral.py Allows a roles/*/meta/variants.yml entry that pins services.tor.enabled: false to keep onion-capable frontend partners enabled. Place on the variant's own tor key line. The marker MUST name why those partners belong in a clearnet round; the usual reason is a real-time media partner in the same round whose transport the onion breaks.
lookup-config-path same or above config/ Skips a single lookup('config', …) call from path-validation passes. Use when the call resolves against runtime-only state, typically self-referential roles.
unused-var same or above test_role_and_group_vars_used.py Exempts a top-level key in roles/<role>/{vars,defaults}/main.yml or group_vars/**/*.yml from the "must be referenced" check. Use when the consumer is non-YAML/Jinja (Python plugins, external tools).
project-root-import same or above test_project_root_import.py Permits a local PROJECT_ROOT / parents[N] / os.pardir chain. Reserved for __main__.py sys.path bootstrap and standalone scripts under roles/<role>/files/. The marker MUST carry an inline explanation.
domain-spot same or above test_domain_primary_spot.py Marks a line using a <word>.{{ DOMAIN_PRIMARY }} host literal outside the meta SPOT. Reserved for legacy domain cleanups that the canonical SPOT cannot represent.
literal-protocol-lookup same or above test_literal_protocol_with_lookup.py Allows a hardcoded http:// / https:// literal next to a lookup(...) call. Reserved for genuinely fixed protocols (Docker-network upstreams, loopback URLs in CI fixtures).
self-path-reference same line test_no_self_path_reference.py Allows a file to contain its own relative path from the repo root as a string literal. Reserved for load-bearing self-references. Repo-root files are exempt without a marker.
role-file-spot same or above test_file_spot.py Allows a .py file to carry a literal role-file path instead of the matching ROLE_FILE_* constant from utils.roles.mapping. Reserved for tests asserting the constant's value, migration scripts, or doc strings.
playwright-service-flag comment block above test_env_services_match.py Exempts a top-level service in roles/<role>/meta/services.yml from the "must be registered as <NAME>_SERVICE_ENABLED= in templates/playwright.env.j2" check.
playwright-service-gate same or above test_spec_env_gates.py Exempts a <NAME>_SERVICE_ENABLED= line in roles/<role>/templates/playwright.env.j2 from the "must be gated in files/playwright/playwright.spec.js" check.
mcp-consumer-services-entry head of file test_mcp_consumer_services_entry.py Exempts a server-capable roles/<role>/meta/mcp.yml from the "must carry a "{{ '<client>' in group_names }}"-gated services.<client-entity> entry for every role declaring mcp_consumer: true" check. Reserved for a provider that legitimately owns no co-deploy edge to its clients.
mcp-consumer-variant head of file test_mcp_consumer_variant.py Exempts a server-capable roles/<role>/meta/mcp.yml from the "must ship one meta/variants.yml entry enabling every admitted consumer, with sso pinned on, and pulling in a consumer variant that does not pin sso: false" check. Reserved for a provider whose pairing is genuinely proven elsewhere.
pkgmgr-deprecated same or above test_pkgmgr_deprecated.py Suppresses the warn-only deprecation notice for include_role / import_role of pkgmgr / pkgmgr-install. The check emits a DeprecationWarning locally and a GitHub Actions ::warning annotation in CI. Prefer pip install <name> or pip install git+<repo>.
deprecated-http-header same or above test_no_deprecated_http_security_headers.py Exempts a deprecated add_header / Header set/add line for X-Frame-Options / X-XSS-Protection / X-Download-Options / X-Permitted-Cross-Domain-Policies. Prefer Content-Security-Policy via the role's meta/server.yml (csp.flags / csp.whitelist).
container-name same or above test_mode_incompatible_keys.py Allows a raw container_name: key in a roles/*/templates/**/*.j2 template. Default path: route through the generic compose_only lookup ({{ lookup('compose_only', 'container_name', NAME) }}) so swarm-mode replicas do not collide on the static name.
pull-policy-key same or above test_mode_incompatible_keys.py Allows a raw pull_policy: key in a roles/*/templates/**/*.j2 template. Default path: route through the generic compose_only lookup ({{ lookup('compose_only', 'pull_policy', 'never') }}) so swarm does not reject the compose-only extension with "Additional property pull_policy is not allowed".
restart-key same or above test_mode_incompatible_keys.py Allows a raw restart: key in a roles/*/templates/**/*.j2 template. Default path: route through the compose_restart lookup so swarm-mode does not silently drop the operator's docker_restart_policy.
compose-structure same or above; head (first 30 lines) test_compose_template_structure.py Exempts a roles/*/templates/*compose.yml.j2 line, or the whole file (head marker), from the canonical compose skeleton: base-include header, {{ service_name }}: service keys each preceded by their {% set service_name %}, all per-service {% set %} knobs on two-space-indented dash-free lines above the key, {% include %} at four spaces inside the service body, and column-0 compose_volumes / compose_networks at the tail. The layout renders correctly because the stack_host_template action plugin sets lstrip_blocks=True for compose.yml.j2. Reserved for legitimate deviations that genuinely cannot follow the skeleton.
seaweedfs-required head (first 30 lines) test_database_requires_seaweedfs.py Exempts a database-backed web-app-* role from the requirement to declare a seaweedfs object-store service. Place in the head of roles/<role>/meta/services.yml. Use only when the application genuinely needs no object storage.
seaweedfs-playwright head (first 30 lines) test_seaweedfs_consumer_playwright.py Exempts a Playwright-enabled web-app-* seaweedfs consumer from shipping files/playwright/test-seaweedfs.js gated on skipUnlessServiceEnabled("seaweedfs"). Place in the head of roles/<role>/meta/services.yml. Reserved for a role whose seaweedfs flag carries no user-facing document surface, e.g. one that enables the service only to join the provider's shared network.
tor-contract anywhere in file test_tor_contract.py Exempts a domain-serving role (web-/svc-db- prefix or explicit domains.canonical) from the "must declare a tor: block in meta/services.yml" contract. Reserved for roles with no onion surface, e.g. pure redirect helpers.
templated-conditional same or above test_no_templated_conditionals.py Exempts a when / failed_when / changed_when / until value that legitimately carries {{ }} / {% %}. Reserved for genuine edge cases; the default path is a bare expression. Per-item render/apply data guards belong on a condition: data field (honored by the sys-svc-compose render helper and LISTMONK_SETTINGS), not when:.
container-address-quote same or above test_address_never_quoted.py Allows *_CONTAINER_ADDRESS | quote in a role task file. Reserved for sites that never see the swarm $(...) fragment (IS_COMPOSE_MODE-gated tasks, compose_mode_force roles) or consumers that re-evaluate the argument themselves.
container-exec-resolver same or above; argv: target item test_exec_uses_resolver.py Allows a container exec / container inspect target that does not route through the container_address lookup. Reserved for a container ID already resolved at delegate_to runtime (*_LOCAL_CID), where the lookup would return a manager-only subshell, and for deliberate bare-name partner probes gated on compose co-location.
container-address-needs-shell same or above; argv: target item test_argv_exec_needs_shell.py Allows a container_address-derived target to be reached from a command: argv: list, which runs no shell to evaluate the swarm $(...) fragment. Reserved for roles pinned to compose via compose_mode_force, where the lookup can only ever yield a bare name.
container-inspect-type same or above; argv: inspect item test_inspect_pins_type.py Allows an untyped container inspect under roles/. Default path: pin --type container, because a role's overlay network carries the same entity name as its main container, so an untyped inspect can resolve the network and report map has no entry for key "State". Use the typed subcommand (container volume inspect etc.) when the target genuinely is not a container.
container-healthcheck-unused same or above the service key or its healthcheck: line test_container_healthcheck_declared_is_used.py Allows a services.<key>.healthcheck that no lookup('container_healthcheck', …) call renders. Default path: add the lookup to the service block, because an unrendered declaration reads like the service is watched while the compose file carries no probe. Reserved for a call the static resolver cannot attribute — mastodon renders every service through a macro whose service_name is a macro parameter.
image-healthcheck same or above the service key test_image_healthcheck_declared.py Allows a roles/*/meta/services.yml entry whose image ships no HEALTHCHECK to declare none either. Default path: add healthcheck: to the entry, because a container without a probe counts as healthy the moment its process starts — which is how a service that came back empty passes a restore drill. Reserved for containers nothing can probe: a one-shot process that exits, or an image with neither a port nor a shell.
image-volumes same or above the service key test_image_volumes_mounted.py Allows a roles/*/meta/services.yml entry whose image declares a VOLUME the role mounts nothing at. MUST be paired with a Reason: naming the path and why the volume stays anonymous. Default path: declare the mount in roles/<role>/meta/volumes.yml against the service key the compose file names, because docker creates an anonymous volume for an unmounted VOLUME and sys-ctl-hlth-volumes fails the deploy over it — and its whitelist keys on volume ids, which are new on every deploy, so the gap cannot be suppressed there. Reserved for an anonymous volume that is genuinely intended: a scratch path the container rewrites on every start, whose contents no restore has to bring back.
csp-unsafe same line test_csp_unsafe_requires_justification.py Documents an unsafe-*: true flag in roles/*/meta/csp.yml. MUST be paired with a Reason: on the same line naming what breaks without the relaxation. unsafe-inline re-admits the inline execution an XSS needs and unsafe-eval re-admits string-to-code, so the flag has to be verified against the running app, not copied from another role.
min-storage-headroom same line OR comment block above key test_min_storage_headroom.py Allows a roles/*/meta/services.yml min_storage to exceed the measured compressed size of its own image:/version: by more than 1 GB. MUST be paired with a Reason: on the same comment line naming what occupies the space. Reserved for services whose data volume genuinely dominates the footprint; the default path is to lower the value, because an over-declared budget makes a host look too small and prunes a cache the deploy did not need to lose.
architecture-pin same line OR comment block above key test_architecture_pin_is_justified.py Allows a roles/*/meta/services.yml entity to declare architectures, which takes the role's rows out of part of the deploy matrix so it stops being exercised where it is narrowed away. MUST be paired with a Reason: naming what cannot run elsewhere. Reserved for an upstream that publishes no manifest for the dropped architecture; where the role builds its own image, the default path is to build it for both instead. test_image_architectures.py fails once every image the role pins publishes the narrowed-away architecture, which is when the declaration and this marker are deleted together.
mem-limit-budget anywhere inside the variant's own entry test_resource_budget.py Lets one meta/variants.yml entry exceed the 64 GB mem_limit cap. MUST carry text after the marker naming what the round transitively bills and why the overage is acceptable; a bare marker grants nothing. mem_reservation stays enforced, and test_every_mem_limit_exemption_is_still_needed fails once the variant is back under the cap.
healthcheck-binary same or above test_healthcheck_binary_on_slim_base.py Exempts a roles/*/meta/services.yml healthcheck flavor from the requirement that the role's files/Dockerfile install the binary the probe runs, when the service sits on a -slim image. MUST name where the binary comes from instead. A -slim tag carries the runtime and nothing around it, so curl is absent and the probe fails from the first beat; under swarm the task is then reaped with exit 137 and every deployment holding the service in its closure fails on the convergence wait, naming the service rather than the missing binary.
galaxy-git-parity same or above test_galaxy_entries_have_git_source.py Exempts a requirements/requirements.galaxy.yml collection from the requirement to also carry a type: git entry in requirements/requirements.git.yml. Reserved for collections that publish no usable git remote; without the git entry a galaxy.ansible.com outage fails make install, because the fallback in scripts/install/ansible.sh cannot resolve the collection either.
loop-var-shadow same or above test_loop_var_shadowing.py Allows a loop_var to take the name of a variable declared in group_vars/** or in a role's vars/defaults. Inside the loop that name carries the item, so every lookup, template and nested include reading it sees the item instead, and ansible only warns. Reserved for a loop whose body reads the name as the item on purpose, typically because the item IS that value: state which meaning the body relies on.
firewall-fragment-accept same or above test_firewall_fragment_verdicts.py Allows a rule in a roles/*/templates/nftables.conf.j2 fragment to end in an accept verdict. Default path: express the intent as a drop of what must not pass, or put the rule in the chain carrying the policy it has to overrule, because an accept terminates only its own base chain and every other chain at that hook still runs, docker's drop policy on forwarded packets included. Reserved for an accept whose only job is to skip the fragment's own later rules.
shell-template head (first 30 lines) test_no_shell_templates.py Allows a *.sh.j2 to exist. Default path: ship the script as a plain .sh under files/shell/ and pass its values as ExecStart arguments or Environment= entries, because shellcheck, the repository's .sh guards and every test skip a Jinja template, so nothing reads what actually runs on the host. Reserved for a script whose shape is generated, not just its values. Place the marker BELOW the shebang, never above it, and prefer the Jinja comment form so it does not reach the rendered script.
systemd-via-sys-service same or above test_systemd_units_via_sys_service.py Allows a role task to render a *.service.j2 itself instead of handing the unit to sys-service. Default path: name the template templates/systemctl.service.j2 and include sys-service with system_service_id, so the unit also gets the daemon reload, the enable, and the timer, async and flush behaviour. Reserved for units sys-service cannot carry, such as a user-scope unit under $HOME.
software-identity same or above test_software_identity_variables.py Allows a .j2 template to write the software's name, domain or URL as a literal. Default path: render SOFTWARE_NAME, SOFTWARE_DOMAIN, SOFTWARE_URL or ORGANIZATION, which group_vars/all/00_general.yml declares once and derives from each other, so a rename reaches the template too. Reserved for a literal that must survive a rename, such as an identifier a third party issued under the old name.
eol-dependency per shape, on the construct's own line or on the nearest non-blank line above it when that is a COMMENT line; a data line above governs only when its indent is strictly smaller, so a nested enabled: inside a modes: sub-block and a sibling shared: cannot reach the flag below them: a meta/services.yml block's enabled: line, or the block's key line when it declares none; a meta/variants.yml pin's enabled: line under the service or addon key, falling back to that key's line and then to the section's first line, which is also where a flow-mapping pin (jira: {enabled: true}) and a YAML-aliased addons: *anchor resolve, and where the marker additionally has to resolve inside the span of the variant being judged; an addon's own enabled: line, or its bridges: line when it declares no enabled test_eol_dependency_requires_eol_consumer.py Allows an enabled: flag that is not a literal false on a service whose provider's primary entity carries lifecycle: eol, in a roles/*/meta/services.yml block, a roles/*/meta/variants.yml pin under services: or addons:, or a roles/*/meta/addons/*.yml gate whose bridges: value names the key, at any depth, because the rule reads an off-shape bridges as bound rather than trusting the suppressible addon-schema lint to have rejected it. shared is deliberately NOT covered: an EOL provider keeps its registration so disable= and the preload order keep working. This key is per flag only: the repository-wide scope has its own key eol-dependency-provider, so no position inside a file can promote a per-flag marker to it. The policy, including the storage rule and the no-variant-pin rule, lives at lifecycle.md. The marker MUST name why the dependency outlives the upstream's end of life; a bare marker is rejected, as with onion-flag.
eol-dependency-provider head (first 30 lines) of the EOL provider's own meta/services.yml, the same placement file-size uses test_eol_dependency_requires_eol_consumer.py Drops one lifecycle: eol role out of the EOL set, which exempts every consumer of that service in the repository at once. Reserved for an EOL entity that still backs a live surface the rule has no claim on. The scope carries its own key so it is claimed by name instead of by line number: a trailing # nocheck: eol-dependency on a flag that happens to sit in the first 30 lines governs that flag and nothing else. test_no_eol_role_exempts_every_consumer keeps the exemption red until the role is recorded in WHOLE_RULE_EXEMPTIONS in the test module, every assertion's footer names the roles dropped that way, and test_no_whole_rule_marker_is_bare reports a marker that names no reason, which is withheld rather than granted.

Tool-Native noqa Codes 🧹

Some Python files use Ruff-compatible uppercase # noqa codes. Ruff and related Python linters handle these, not suppress.py. They MAY appear when the local exception is intentional and clear from context.

Code Tool meaning Typical allowed use
BLE001 Blind exception caught Narrow command-wrapper boundaries that convert any underlying failure into a domain-specific error.
E402 Module import not at top Tests that MUST adjust sys.path or load fixtures before importing the module under test.
E731 Lambda assigned to variable Small test-local callbacks or path formatters where a named function would add noise.
F401 Imported but unused Re-export modules or import-probe tests where import success is the assertion.
SLF001 Private member access Test-only introspection of parser or object internals when the public surface does not expose the needed state.

Adding a new rule 🆕

  1. Pick a kebab-case <rule> identifier.
  2. Decide which position semantic from the list above fits the check.
  3. Use is_suppressed_at / is_suppressed_in_head / is_suppressed_anywhere from suppress.py in your test. Do NOT roll a new regex.
  4. Add the rule to the catalog table on this page.