AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible-Lint Error 403 package-latest: Fix State Latest Warning

By Luca Berton · Published 2024-01-01 · Category: installation

Fix ansible-lint Error 403 package-latest. Understand why state=latest is risky, when to use state=present, and how to pin package versions safely.

Ansible-Lint Error 403 package-latest: Fix State Latest Warning

Introduction

Ansible is a powerful automation tool known for its role in provisioning, configuration management, and application deployment. Ensuring the integrity and stability of software installations is vital when managing packages through Ansible. To help you achieve this, Ansible provides a set of rules, including Rule 403, known as "package-latest." This rule emphasizes the importance of controlled, safe package management practices, promoting predictability in your automation tasks.

See also: Ansible troubleshooting - Error 102: No Jinja2 in 'when' Conditions

Deciphering Rule 403 - "package-latest"

Rule 403, or "package-latest," is a rule within Ansible's comprehensive rule set that aims to establish best practices for managing packages using package manager modules, such as ansible.builtin.yum and ansible.builtin.apt. These modules allow users to configure how Ansible installs software on target systems.

The primary concern addressed by this rule is the use of the state parameter in package manager modules. In production environments, it is crucial to set the state to "present" and specify a target version for package installations. This practice ensures that packages are installed according to a predefined and tested version, adding a layer of control and predictability to your automation tasks.

Conversely, setting the state to "latest" is discouraged, as it not only installs the desired software but also initiates an update process that can lead to unintended consequences. The update process can result in performance degradation or the installation of additional packages, potentially causing service disruptions.

If your intention is to update packages to the latest version, this rule suggests using the update_only or only_upgrade parameter (depending on the package manager in use) and setting it to "true." This practice ensures that only updates are applied without the introduction of unexpected packages.

Problematic Code

Let's explore a problematic code snippet to understand how Rule 403, "package-latest," can identify issues in your playbooks:

---
- name: Example playbook
  hosts: all
  tasks:
    - name: Install Ansible
      ansible.builtin.yum:
        name: ansible
        state: latest # <- Installs the latest package.

- name: Install Ansible-lint ansible.builtin.pip: name: ansible-lint args: state: latest # <- Installs the latest package.

- name: Install some-package ansible.builtin.package: name: some-package state: latest # <- Installs the latest package.

- name: Install Ansible with update_only to false ansible.builtin.yum: name: sudo state: latest update_only: false # <- Updates and installs packages.

- name: Install Ansible with only_upgrade to false ansible.builtin.apt: name: sudo state: latest only_upgrade: false # <- Upgrades and installs packages

In this code, the state parameter is set to "latest" across various package manager modules, including ansible.builtin.yum, ansible.builtin.pip, and ansible.builtin.package. This configuration can lead to the installation of unexpected package versions and additional packages, introducing unpredictability and potential service issues.

Output:

WARNING  Listing 5 violation(s) that are fatal
package-latest: Package installs should not use latest.
403.yml:5 Task/Handler: Install Ansible

package-latest: Package installs should not use latest. 403.yml:10 Task/Handler: Install Ansible-lint

package-latest: Package installs should not use latest. 403.yml:16 Task/Handler: Install some-package

package-latest: Package installs should not use latest. 403.yml:21 Task/Handler: Install Ansible with update_only to false

package-latest: Package installs should not use latest. 403.yml:27 Task/Handler: Install Ansible with only_upgrade to false

Read documentation for instructions on how to ignore specific rule violations.

Rule Violation Summary count tag profile rule associated tags 5 package-latest safety idempotency

Failed: 5 failure(s), 0 warning(s) on 1 files. Last profile that met the validation criteria was 'moderate'. Rating: 2/5 star

See also: Ansible troubleshooting - Error 104: Deprecated Bare Vars

Correct Code

To address the issues highlighted by Rule 403, the correct code should adopt the following best practices:

---
- name: Example playbook
  hosts: all
  tasks:
    - name: Install Ansible
      ansible.builtin.yum:
        name: ansible-2.12.7.0
        state: present # <- Pins the version to install with yum.

- name: Install Ansible-lint ansible.builtin.pip: name: ansible-lint args: state: present version: 5.4.0 # <- Pins the version to install with pip.

- name: Install some-package ansible.builtin.package: name: some-package state: present # <- Ensures the package is installed.

- name: Update Ansible with update_only to true ansible.builtin.yum: name: sudo state: latest update_only: true # <- Updates but does not install additional packages.

- name: Install Ansible with only_upgrade to true ansible.builtin.apt: name: sudo state: latest only_upgrade: true # <- Upgrades but does not install additional packages.

In this improved code, the state parameter is set to "present," and specific version identifiers are used for different package installations. By doing so, the playbook ensures that software is installed to predefined versions, adding a layer of control and predictability to your automation tasks.

Implementing Rule 403 - "package-latest"

Rule 403, "package-latest," provides critical guidance for maintaining safe and controlled package management practices in Ansible. By following this rule, you can safeguard your automation tasks against unpredictability and ensure the reliable installation of software on target systems. In production environments, embracing predictability is essential to minimize the risk of service disruptions and maintain the integrity of your infrastructure.

In cases where updating packages to the latest version is intentional, the use of the update_only or only_upgrade parameter allows you to strike a balance between flexibility and stability

See also: Ansible troubleshooting - Error 105: Deprecated Module Usage

The Error

package-latest: Package installs should not use latest.

Quick Fix

# WRONG — non-deterministic, different results each run
- ansible.builtin.apt:
    name: nginx
    state: latest

# CORRECT — deterministic, same result every run - ansible.builtin.apt: name: nginx state: present

# BETTER — pin specific version - apt: name: nginx=1.24.0-1 state: present

Why latest Is Risky

# Production scenario:
# Monday: nginx 1.24.0 (works fine)
# Tuesday: nginx 1.25.0 released (breaking change)
# Wednesday: you run same playbook → gets 1.25.0 → production breaks!

# With state=present: # Monday: installs 1.24.0 # Wednesday: 1.24.0 already installed → no change → safe

Pin Specific Versions

# Debian/Ubuntu
- apt:
    name: "nginx={{ nginx_version }}"
    state: present
  vars:
    nginx_version: "1.24.0-1"

# RHEL/CentOS - yum: name: "nginx-{{ nginx_version }}" state: present vars: nginx_version: "1.24.0-1.el9"

# pip - pip: name: "flask=={{ flask_version }}" vars: flask_version: "3.0.0"

When latest IS Appropriate

# Security patches — explicitly allowed
- apt:
    name: "{{ item }}"
    state: latest  # noqa: package-latest
  loop:
    - openssl
    - libssl3
  tags: [security-patches]

# Development/staging environments - apt: name: nginx state: latest when: env == 'development'

Controlled Updates

# Update all packages explicitly (not via state=latest)
- apt:
    upgrade: safe
  become: true
  tags: [update]

# Or use a dedicated update playbook - apt: name: "*" state: latest become: true tags: [never, full-update] # Only runs when explicitly called

Configure the Rule

# .ansible-lint
skip_list:
  - package-latest  # Not recommended

# Better: suppress per-task - apt: { name: nginx, state: latest } # noqa: package-latest

FAQ

state=present doesn't install the latest version?

It installs whatever version your package manager resolves — typically the latest available. But it won't upgrade if already installed. That's the key difference.

How do I update packages safely?

Use a dedicated update playbook with apt: upgrade=safe or yum: name=* state=latest, run it intentionally (not as part of regular deploys).

What about rolling releases (pip, npm)?

Pin versions in requirements files (requirements.txt, package.json). Never use state: latest for application dependencies.

Related Articles

using when in Ansible playbooksnotify and handlers in Ansible

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home