--diff, and Producing Evidence for Change Review

Scenario: A change request says 'update nginx configuration'. The reviewer approves it. The change also rotated a TLS cipher list and disabled HTTP/2, because nobody looked at the rendered output.

New words, in plain English

--check --diff produces something a description cannot: the exact bytes that will change, on each host, generated from the real current state.

Used properly this replaces a whole class of review theatre. Instead of "update nginx configuration", the change record carries the rendered diff - and the reviewer can see the cipher change and the HTTP/2 line that the summary omitted.

The practical workflow for anything risky:

  1. --check --diff --limit web01 - see what it would do to one host.
  2. --limit web01 - do it to that one host, and observe the service.
  3. Full run, with serial set, so the blast radius stays bounded.

One caveat: --diff prints file contents, which will include secrets if your templates render them. no_log: true on a task suppresses its output entirely - necessary for credential-handling tasks, and painful when debugging, so apply it to the specific task rather than the whole play.

Analogy: A change description is the estate agent's summary. --diff is the survey. Approving the summary without reading the survey is how people discover the subsidence after they have moved in.

A worked example

# Generate reviewable evidence, changing nothing
ansible-playbook site.yml --check --diff --limit web01

# TASK [Render the nginx configuration] ****************
# --- before: /etc/nginx/nginx.conf
# +++ after:  /etc/nginx/nginx.conf
# @@ -12,7 +12,7 @@
# -    ssl_ciphers HIGH:!aNULL:!MD5;
# +    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384;
# -    listen 443 ssl http2;
# +    listen 443 ssl;
# changed: [web01]

# Keep credentials out of the diff and the log
- name: Deploy the API credential
  ansible.builtin.template:
    src: creds.j2
    dest: /etc/app/creds
    mode: "0600"
  no_log: true

In CI, running --check --diff on every pull request and attaching the output to the review turns "what does this change do?" into a mechanical answer. Where the estate is large, running it against a representative subset with --limit keeps it fast enough to be habitual.

Be aware that --check cannot predict everything. A task whose behaviour depends on the result of an earlier task that was skipped in check mode will report inaccurately, and a module that does not support check mode is simply skipped. Read the dry run as strong evidence, not as proof.

Tip: Attach the --check --diff output to the change request. It is generated evidence rather than a written claim, and it takes no extra effort to produce.
Goal: Put this to work in the ansible-check-mode-safety lab. Open /labs/ansible, pick ansible-check-mode-safety, and fix the real broken project - Ansible really does SSH into four managed hosts and converge them.