Providers
=========

Exosphere implements platform support for Patch and Update management through an
extensible :doc:`Providers API <api/providers_api>` that allows for new providers
to be more or less transparently implemented.

Current implementation details and notes for the built-in providers are provided
below.

Debian/Ubuntu (Apt)
-------------------

The Debian/Ubuntu provider is implemented in the `exosphere.providers.debian` module.

Repo sync **requires** sudo privileges, as it needs to run ``apt-get update`` to
update the package cache from repository.

By default, given the stock :ref:`Sudo Policy <default_sudo_policy_option>`,
in Exosphere, Repo sync will **not** run for Debian-like hosts, and you will need
to configure sudoers appropriately before changing the Sudo Policy.

Updates retrieval is done using ``apt-get dist-upgrade`` in simulation mode,
and **does not** require elevated privileges.

Pending reboot detection checks for the presence of ``/var/run/reboot-required``,
which the system creates after applying updates that need a reboot to take effect
(such as kernel or libc upgrades). This **does not** require elevated privileges.

.. admonition:: Note

    If you want repo sync without sudo privileges, you can also just
    install the ``apt-config-auto-update`` package, or configure
    `Unattended Upgrades`_ to achieve this on a schedule.


Exact Commands run on remote hosts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- ``/usr/bin/apt-get update`` **(requires sudo)**
- ``apt-get dist-upgrade -s | grep -e '^Inst'``
- ``test -f /var/run/reboot-required``


Command dependencies
^^^^^^^^^^^^^^^^^^^^

- `apt-get`
- `grep`

.. _Unattended Upgrades: https://wiki.debian.org/UnattendedUpgrades

RedHat-Likes (Yum/DNF)
----------------------

The RedHat provider is implemented in the `exosphere.providers.redhat` module.

It implements the functionality identically between Yum and DNF, as they share
an interface for the relevant commands. The only distinction is the command name.

Internally, using Yum as a provider wraps Dnf, but with a different command name.

Repo sync **does not** require sudo privileges, as it runs ``yum/dnf makecache``
as the connection user to retrieve the information.

Updates retrieval is done using ``yum/dnf check-update``, and does *not* require
elevated privileges.

Pending reboot detection uses ``needs-restarting -r``, which reports whether a
reboot is recommended following kernel or core library updates, and **does not**
require elevated privileges. The exact invocation depends on the backend:

- On **dnf**, the ``dnf needs-restarting`` subcommand is used. It is built in to
  dnf5 and provided by the ``python3-dnf-plugins-core`` plugin on dnf4 (installed
  by default on RHEL 8/9).
- On **yum**, the standalone ``needs-restarting`` command is used, shipped with
  the ``yum-utils`` package.

If the command or plugin is unavailable, the reboot status is reported as
*unknown* rather than failing the refresh, making this feature entirely optional.

Exact Commands run on remote systems
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. note::

   If your system uses ``yum`` you can replace ``dnf`` with it here.

- ``dnf --quiet -y makecache --refresh``
- ``dnf --quiet -y check-update``
- ``dnf --quiet -y check-update --security``
- ``dnf --quiet -y list installed <package_name> [<package_name> ...]``
- ``dnf needs-restarting -r`` **or** ``needs-restarting -r`` (dnf vs yum)

Command dependencies
^^^^^^^^^^^^^^^^^^^^

- `yum` or `dnf`
- For updates (optional):

  - `python3-dnf-plugins-core` on dnf4 (installed by default on RHEL 8/9)
  - `yum-utils` on yum

Usage Notes and Issues
^^^^^^^^^^^^^^^^^^^^^^

Some minor limitations:

* Current version detection is done on a best effort basis, installonly packages
  are clobbered down to the last installed version. This is generally accurate enough, but
  it is difficult to provide guarantees given the dnf/yum interfaces available.
* Some Vendor configurations may cause the provider to fail to detect kernel updates.
  This is generally a misconfiguration, and you should seek vendor support to resolve this.
  Google Compute Platform (GCP) is known to exhibit this issue with some legacy vendor kernels.

In some scenarios, the `yum` or `dnf` commands may hang when running due to
unexpectedly prompting for user input interactively, which Exosphere cannot handle.

The provider is written to avoid this, but if you do encounter this, simply run
``dnf makecache --refresh`` or ``yum makecache --refresh`` manually on the remote system
and answer any prompts that may appear.

Once that is done, you should be able to run Exosphere commands without issues.

Note that we consider having to do this a bug, and would appreciate if you could
`file a bug report`_.

FreeBSD (Pkg)
-------------

The FreeBSD provider is implemented in the `exosphere.providers.freebsd` module.
It uses the `pkg` command to manage packages and updates.

Repo sync **requires** sudo privileges, as it needs to run ``/usr/sbin/pkg update``
to update the package cache from repository, as well as refresh ``vuln.xml`` for
use by ``pkg audit``.

This also means you will need to have the ``sudo`` package installed on the
remote system if you want to use this functionality. Unfortunately, ``doas``
is not supported at this time.

By default, given the stock :ref:`Sudo Policy <default_sudo_policy_option>`,
in Exosphere, Repo sync will **not** run for FreeBSD hosts, and you will need
to configure sudoers appropriately before changing the Sudo Policy.

Alternatively, you can run ``/usr/sbin/pkg update`` via a cronjob or similar
mechanism to keep the repository information up to date without having
to configure sudo privileges for Exosphere.

Updates retrieval is done using ``pkg upgrade`` in simulation mode, and **does not**
require elevated privileges.

Pending reboot detection compares the installed kernel version
(``freebsd-version -k``) with the running kernel (``freebsd-version -r``).
A mismatch indicates a kernel update that has been installed but not yet booted.
This is intentionally kernel-only, and **does not** require elevated privileges.

Exact Commands run on remote systems
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- ``/usr/sbin/pkg update -q`` **(requires sudo)**
- ``/usr/sbin/pkg audit -qF`` **(requires sudo)**
- ``/usr/sbin/pkg audit -q`` for security updates
- ``/usr/sbin/pkg upgrade -qn | grep -e '^\\s'``
- ``freebsd-version -k``
- ``freebsd-version -r``

Command dependencies
^^^^^^^^^^^^^^^^^^^^

- `pkg`
- `grep`
- `freebsd-version`

OpenBSD (pkg_add)
-----------------

The OpenBSD provider is implemented in the `exosphere.providers.openbsd` module.
It uses the `pkg_add` command to manage packages and updates.

Repo sync is essentially a no-op, as OpenBSD does not have a command to
synchronize package repositories. The command being run will directly query
package mirrors on demand, and maintains no cache.

Updates retrieval is done using ``pkg_add -un``, and **does not** require
elevated privileges.

Branch detection is done using ``syspatch -l``, which is in turn used to
determine whether updates should be considered security updates or not.
This **does not** require elevated privileges either.

Pending reboot detection is **not implemented** for OpenBSD, as it does not
really provide any useful tooling around this.

Additionally, as the provider only handles binary packages and not ``syspatch``
or system updates, reboot status is always reported as *unknown*.

Limitations
^^^^^^^^^^^

- On **stable/release**, all package updates are assumed to be security updates,
  since OpenBSD only ever updates packages for security issues.
- If the system is tracking `-current` or `-beta`, security status will default to
  False, as there is no way to tell given the rolling release nature of these branches.
- On more exotic architectures, `syspatch` may not be available and the failure
  modes are untested. If you have such a system, and this breaks for you, please
  `file a bug report`_ and include the output of ``syspatch -l``.
- Only handles binary packages, does not support ports or syspatch/system updates.
- Handles transitive dependencies without marking them as such, and may,
  in some edge cases, list more packages than strictly necessary for an update.
- Reboot status is always reported as *unknown*

Exact Commands run on remote systems
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- ``/usr/sbin/syspatch -l``
- ``/usr/sbin/pkg_add -u -v -x -n | grep -e '^Update candidate'``

Command dependencies
^^^^^^^^^^^^^^^^^^^^

- `pkg_add`
- `grep`
- `syspatch`

.. _file a bug report: https://github.com/mrdaemon/exosphere/issues
