


Build and Review Ansible Infrastructure Automation Without Weakening Security
Use when an AI writes or changes infrastructure automation such as Ansible playbooks. It passes every lint and security check with no warnings, keeps secrets out of the repository, debugs networks from the bottom layer up, proves tests catch the bug, and reports only checks it ran.
To use this AI rule
## Put Security and Stability First, and Change Only What Was Asked
Treat infrastructure automation as security-critical code: a small configuration error can silently weaken privacy, access control, routing, or service availability.
- Prefer stability over feature volume, security over convenience, and clarity over cleverness.
- Solve exactly the requested problem. Keep unrelated fixes and speculative features in separate work.
- Test assumptions by running the affected automation before declaring a change complete.
- Resist new dependencies. Every dependency expands the attack surface and maintenance burden.
- Follow existing repository patterns before introducing new abstractions or configuration options.
- Treat each new option as additional test surface; add one only when users have a demonstrated need.
- Use fresh deployments for behavioral tests when retained state could hide defects.
## Pass Every Lint and Security Check With Zero Warnings
Run the repository's complete local quality gate before review. The gate should cover configuration linting, YAML linting, language linting, shell analysis, static security analysis, playbook syntax checks, and relevant unit tests.
No warning is acceptable in continuous integration. In security-sensitive automation, apparently cosmetic findings can hide broken templates, unsafe file permissions, or a real regression among recurring noise.
Resolve findings in this order:
1. Fix the underlying problem.
2. If the rule is incorrect for the repository, allowlist it in the owning tool's configuration and explain why.
3. Use an inline suppression only as a last resort, naming the exact rule and documenting the exception.
Do not move findings into a permanent warning list. A rule must either pass or be explicitly skipped with a durable rationale.
Common mandatory checks include:
- Start YAML documents with `---` and quote ambiguous workflow keys when required by the parser.
- Prefer explicit failure conditions such as `failed_when` over broad `ignore_errors`.
- Use consistent Jinja2 spacing.
- Specify `mode` for every file or directory task instead of relying on `umask`.
- Quote shell variables and enable strict shell error handling.
- Treat static-analysis suppressions as reviewable exceptions, not shortcuts.
Before submitting a change, inspect the diff, record the checks run, and confirm that continuous integration will execute the same essential validations.
## Check Inputs Early and Keep Secrets Out of the Repository
Validate inputs before expensive or state-changing operations. Reject empty collections, missing configuration, malformed addresses, incompatible versions, and permission mismatches at the earliest reliable point.
- Set file and directory modes explicitly.
- Fail on permission, authentication, cryptography, or security-boundary errors. Reserve warnings for genuinely optional behavior.
- Make errors actionable by naming the failed condition and the safe corrective action.
- Apply least privilege: minimize permissions, accounts, retained credentials, and process capabilities.
- Use secure defaults, strong cryptography, strict firewall rules, minimal logging, and minimal data retention.
- Never place passwords, private keys, access tokens, or provider credentials in source control.
- Respond to confirmed security vulnerabilities promptly and verify the upgraded behavior.
- Avoid undocumented workarounds. Record why a workaround exists and reference its upstream issue so maintainers can remove it safely later.
Search the codebase for an established pattern before adding a task, conditional, provider path, or module. Reuse the established control flow unless evidence shows it is unsuitable.
## Avoid Common Mistakes in Ansible Loops and Jinja2 Templates
Do not mechanically replace legacy iteration with `loop`. Some legacy iteration forms flatten nested lists while `loop` preserves them. Verify the resulting item shape and confirm that expected files or resources are created.
- Pass a list directly to `loop`; do not wrap an existing list in another list.
- Combine lists explicitly when the previous construct flattened multiple inputs.
- Keep path variables free of trailing slashes to prevent doubled separators.
- For read-only commands and handlers, set `changed_when: false` so state reports remain accurate.
- Use `failed_when: false` only when the command's failure is explicitly expected and safe; do not hide unrelated failures.
Under native Jinja2 evaluation:
- Conditions require actual booleans, not strings such as `"true"` and `"false"`.
- Pass variables directly into lookups; do not nest template expressions inside another template expression.
- Parse JSON text explicitly when a lookup returns file contents.
- Remember that `default()` does not replace an empty string unless its falsy-value option is enabled.
- Replace complex template-generated list comprehensions with ordinary automation loops and explicit accumulation.
- Use tests for boolean predicates and filters for data transformation.
Test templates with the automation framework's real filters or faithful mocks. Syntax validity alone does not prove native-mode behavior.
## Debug Network Services Layer by Layer, Starting With Listening Ports
Debug network automation from the lowest uncertain layer instead of assuming every connectivity symptom is a routing failure.
1. Confirm that the expected TCP and UDP sockets are listening on the intended address and port.
2. Inspect service and socket-unit status for configuration warnings.
3. Verify required kernel networking settings.
4. Test name resolution directly against the configured resolver.
5. Only then inspect firewall, translation, and policy-routing rules.
For socket-activated services, configure the socket unit rather than only the service configuration. Clear inherited listeners when required, define both stream and datagram listeners, and restart the socket after changes. Disabling the socket can break service dependencies.
Account for platform differences deliberately:
- Firewall backends may reorder rules; pin or verify the backend whose behavior the automation expects.
- Multi-homed hosts may require an explicit outbound interface for address translation.
- Prefer simple interface-qualified masquerading over unnecessary source-translation complexity when it meets the requirement.
- Add compatibility flags conditionally after detecting the installed tool version.
- Bracket IPv6 endpoints where host and port syntax requires it.
- Check name resolution before redesigning routing or translation rules.
Keep network rules simple, and test packet flow rather than inferring success from task output.
## Prove Each Regression Test Fails When the Bug Comes Back
A regression test must demonstrate that it detects the defect it claims to prevent.
1. Write a focused test for the failure case.
2. Temporarily introduce the defect or mutate the relevant condition.
3. Confirm that the new test fails for the intended reason.
4. Restore the correct implementation and confirm that the test passes.
5. Document the exact regression the test protects against.
When behavior depends on templates, file paths, permissions, firewall rules, or collection shape, test the observable result rather than only the generated text. Verify created files, effective modes, parsed values, listener state, packet flow, or rendered output as appropriate.
Update existing tests when a change alters paths or behavior. Do not assume a passing test is meaningful until its failure sensitivity has been demonstrated.
## Run Deployments Without Prompts and Report Only Checks Actually Run
Automation intended for continuous integration or agents must support a fully non-interactive path.
- Every prompt must be bypassed when its variable is predefined through an approved parameter or environment variable.
- Document the complete set of core variables, their types, defaults, and purpose.
- Keep provider-specific credentials separate from ordinary configuration and accept them only through approved secret channels.
- Require explicit confirmation variables for local or high-impact deployment modes.
- Ensure optional features have explicit boolean values so headless runs do not pause for missing input.
- Test the non-interactive path from a clean environment with representative multi-interface and multi-address conditions.
Before completion, run all linters, syntax checks, relevant unit tests, and a fresh deployment or equivalent integration test. Review the diff for unrelated fixes, unjustified dependencies, hidden suppressions, missing file modes, secrets, and undocumented behavior. Report the exact evidence collected and do not claim deployment success if only static checks were run.
