# Upstream containernetworking/plugins binaries, baked in at build time.
#
# WHY THIS IMAGE EXISTS
# The multus cni-plugins-installer DaemonSet used to fetch this tarball from
# GitHub on the node itself, at node-provisioning time, and extract it straight
# into /opt/cni/bin. Two problems with that:
#
#   1. Security. The download had NO integrity verification — wget, then tar,
#      into a directory whose contents are executed as root in the CNI path on
#      every node. A tampered or MITM'd artifact would have got privileged
#      execution cluster-wide, with nothing to detect it.
#   2. Node rebuild. It put a live dependency on github.com (and previously the
#      Alpine package index too) on the critical path of bringing a node up, so
#      a GitHub outage or slow transfer stalled or broke CNI installation
#      exactly when a node was being rebuilt.
#
# Baking the binaries in fixes both: the fetch happens once, here, where the
# checksum IS verified, and the installer becomes a local file copy with no
# network at all.
#
# The version and digest are pinned literals, so bumping them is a reviewable
# commit rather than a silent change in what runs on every node. The digest was
# cross-checked against upstream's own published
# cni-plugins-linux-amd64-<version>.tgz.sha256 asset rather than merely recorded
# from a local download — a download can be tampered with; the point of the
# check is to compare against what upstream states.
#
# amd64 only, matching the ARCH the installer already hardcoded and the cluster's
# node architecture. Add a second stage if a different arch is ever needed.

FROM alpine:3.24@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6 AS fetch

ARG CNI_PLUGINS_VERSION=v1.9.1
ARG CNI_PLUGINS_SHA256=b98f74a0f8522f0a83867178729c1aa70f2158f90c45a2ca8fa791db1c76b303

# busybox wget and tar are already in the base; nothing is installed here
# either. sha256sum -c fails the BUILD if the artifact does not match, which is
# the whole point — a bad download must never reach a node.
RUN set -eu; \
    F="cni-plugins-linux-amd64-${CNI_PLUGINS_VERSION}.tgz"; \
    wget -q -O "/tmp/${F}" \
      "https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/${F}"; \
    echo "${CNI_PLUGINS_SHA256}  /tmp/${F}" | sha256sum -c -; \
    mkdir -p /plugins; \
    tar -xzf "/tmp/${F}" -C /plugins; \
    rm -f "/tmp/${F}"; \
    # Drop the non-executable payload: the tarball ships LICENSE and README.md,
    # which the old installer extracted into /opt/cni/bin alongside the binaries.
    rm -f /plugins/LICENSE /plugins/README.md; \
    # Fail loudly here rather than shipping an image that silently installs
    # nothing, if upstream ever restructures the archive.
    #
    # This list must cover every plugin the repo actually depends on, not just
    # the ones the installer happens to log. `dhcp` is included because the
    # sibling cni-dhcp-daemon DaemonSet runs that binary and documents that it
    # ships from here (see kubernetes/infrastructure/multus/cni-dhcp-daemon.yaml)
    # — without it in the check, upstream dropping `dhcp` while keeping the
    # others would build green and only surface later as a broken DHCP daemon on
    # whichever node rolled first.
    for p in macvlan static host-local dhcp; do \
      [ -x "/plugins/$p" ] || { echo "FATAL: /plugins/$p missing or not executable" >&2; exit 1; }; \
    done

FROM alpine:3.24@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6

# Alpine rather than scratch: the installer needs a shell to copy the binaries
# onto the host. busybox covers cp/mv/chown/ls, so nothing is added.
COPY --from=fetch /plugins/ /opt/cni-plugins/
