Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172import { describe, expect, it } from "vitest";import { PROSODY_IMAGE, checkImageSafe, checkPodmanInfo, prosodyRunArgs } from "../../central/xmppServer";
/** * GHSA-2cvf-wqm6-wr9g (podman 4.4.0 up to 5.8.7, and 6.0.0 up to 6.1.2): `podman run` on an image that carries the annotation io.podman.annotations.checkpoint.runtime.name * treats it as a checkpoint and silently ignores the caller's options, such as --cap-drop, so an image could give itself every capability. Rootless podman is not * affected. These checks keep the central system from starting a container in the one setup, or with the one kind of image, that the advisory describes. */
const ANNOTATION = "io.podman.annotations.checkpoint.runtime.name";
describe("the XMPP image reference", () => { it("is pinned by digest, not by a tag a registry can move", () => { expect(PROSODY_IMAGE).toMatch(/^docker\.io\/prosodyim\/prosody@sha256:[0-9a-f]{64}$/); });});
describe("checkPodmanInfo", () => { it("accepts rootless podman", () => { expect(checkPodmanInfo({ host: { security: { rootless: true } }, version: { Version: "5.7.0" } })).toBeUndefined(); }); it("refuses rootful podman: that is the setup the advisory applies to", () => { expect(checkPodmanInfo({ host: { security: { rootless: false } }, version: { Version: "5.7.0" } })).toMatch(/rootless/); }); it("refuses when podman cannot say whether it is rootless", () => { expect(checkPodmanInfo({})).toMatch(/rootless/); expect(checkPodmanInfo(null)).toMatch(/rootless/); });});
describe("checkImageSafe", () => { it("accepts an image with no annotations and no labels", () => { expect(checkImageSafe({ Annotations: {}, Labels: null, Config: { Labels: null } })).toBeUndefined(); expect(checkImageSafe({})).toBeUndefined(); }); it("accepts ordinary annotations and labels", () => { expect(checkImageSafe({ Annotations: { "org.opencontainers.image.source": "x" }, Labels: { maintainer: "y" } })).toBeUndefined(); }); it.each([ ["a manifest annotation", { Annotations: { [ANNOTATION]: "crun" } }], ["an image label", { Labels: { [ANNOTATION]: "crun" } }], ["a config label", { Config: { Labels: { [ANNOTATION]: "crun" } } }], ["the annotation with another value", { Annotations: { [ANNOTATION]: "" } }], ["the annotation in another case", { Annotations: { [ANNOTATION.toUpperCase()]: "crun" } }], ])("refuses an image with %s", (_n, inspected) => expect(checkImageSafe(inspected)).toMatch(/checkpoint/)); it("names the advisory so the reason can be looked up", () => { expect(checkImageSafe({ Annotations: { [ANNOTATION]: "x" } })).toContain("GHSA-2cvf-wqm6-wr9g"); });});
describe("how the container is run (the advisory is about options an image can override, so ours are also kept minimal)", () => { const args = prosodyRunArgs({ name: "n" }, "/c/prosody.cfg.lua", "/c/modules", "/c/.env-1"); it("drops every capability, forbids gaining privileges, has a read-only root, limits processes and runs as the host user, not root", () => { expect(args).toEqual(expect.arrayContaining(["--cap-drop=ALL", "--security-opt=no-new-privileges", "--read-only", "--pids-limit=256", "--userns=keep-id"])); const user = args[args.indexOf("--user") + 1]!; expect(user).not.toMatch(/^0:/); expect(args).not.toContain("--privileged"); expect(args.filter((a) => a.startsWith("--cap-add"))).toEqual([]); }); it("mounts the configuration and the modules read-only, and gives the secret only through an env file, never on the command line", () => { expect(args).toContain("/c/prosody.cfg.lua:/etc/prosody/prosody.cfg.lua:ro"); expect(args).toContain("/c/modules:/aite:ro"); expect(args[args.indexOf("--env-file") + 1]).toBe("/c/.env-1"); expect(args.join(" ")).not.toMatch(/SECRET|-e /); }); it("its only writable places are two in-memory folders, and the image is the pinned one unless another is given", () => { expect(args.filter((a) => a.startsWith("/") && a.includes(":rw"))).toEqual(["/var/lib/prosody:rw,mode=1777", "/tmp:rw,mode=1777"]); expect(args).toContain(PROSODY_IMAGE); expect(prosodyRunArgs({ name: "n", image: "localhost/x" }, "a", "b", "c")).toContain("localhost/x"); });});