// Copyright (C) 2026 Viorel Munteanu // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #pragma once #include #include #include #include #include struct OciLayer { std::string digest; // "sha256:", as it appears in the manifest std::string media_type; }; // Validates that `tar_path` is an OCI Image Layout tar (oci-layout + index.json + // a referenced blobs/sha256/ image manifest) and returns its layers in // base-to-top order. Logs a specific error via fmt and returns nullopt if anything // required is missing or malformed. std::optional> read_oci_layers(const std::filesystem::path& tar_path); // Extracts the raw bytes of blobs/sha256/ from `tar_path` into `out_file`. // Returns false (and logs) if the entry isn't found. bool extract_blob_to_file(const std::filesystem::path& tar_path, std::string_view digest_hex, const std::filesystem::path& out_file); // Strips the "sha256:" algorithm prefix from a digest string, e.g. // "sha256:abcd" -> "abcd". Returns the input unchanged if there is no such prefix. std::string oci_digest_hex(std::string_view digest); struct OciImageRef { std::string name; std::string tag; std::filesystem::path path; // the archive file this was found in }; // Scans `dir` (non-recursively) for files matching *.tar or *.tar.*, and for each one // that's a valid OCI Image Layout archive, determines an image name/tag from its // index.json manifest annotations (io.containerd.image.name or // org.opencontainers.image.ref.name), falling back to the archive's filename (with // .tar and any compression suffix stripped) for the name and "latest" for the tag. // Files that aren't valid OCI archives are silently skipped. Returns nullopt if `dir` // isn't a readable directory; an empty vector is a valid result (nothing matched). std::optional> list_oci_images(const std::filesystem::path& dir); enum class OciPortProtocol { kTcp, kUdp }; struct OciExposedPort { int port; OciPortProtocol protocol; }; struct OciImageConfig { std::string user; // config.User's "" part; empty if unset std::string group; // config.User's optional ":" part; empty if unset std::vector exposed_ports; // config.ExposedPorts keys, parsed "/" std::vector env; // config.Env, e.g. "PATH=..." std::vector volumes; // config.Volumes keys, e.g. "/var/lib/mysql" std::vector command; // config.Entrypoint ++ config.Cmd }; // Reads the image config blob referenced by the manifest (found via index.json, same // validation read_oci_layers() already does) and extracts User, ExposedPorts, Env, // Volumes, and the effective default command (Entrypoint ++ Cmd). Logs a specific // error and returns nullopt if anything required is missing or malformed. std::optional read_oci_image_config(const std::filesystem::path& tar_path);