Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6f8c499
test(ISV-6236): early impl of integration tests
bclindner May 11, 2026
95a9d5e
Merge branch 'main' into ISV-6236
bclindner May 11, 2026
fd585ab
style: ruff
bclindner May 11, 2026
321e5a1
Merge branch 'ISV-6236' of github.com:konflux-ci/mobster into ISV-6236
bclindner May 11, 2026
7932ce4
fix(ISV-6236): trued up purls/pullspecs/etc
bclindner May 11, 2026
e1985cb
feat(ISV-6236): added extra_images to make_metadata_yaml
bclindner May 13, 2026
41e027c
refactor(ISV-6236): add interchange class for packages
bclindner May 13, 2026
3afca53
feat(ISV-6236): test rewrite
bclindner May 18, 2026
0aa8412
Merge branch 'main' into ISV-6236
bclindner May 18, 2026
3f7319d
style: ruff
bclindner May 18, 2026
d87ecc9
Merge branch 'ISV-6236' of github.com:konflux-ci/mobster into ISV-6236
bclindner May 18, 2026
d6a3a5a
chore: mypy
bclindner May 18, 2026
0243971
refactor: test iteration
bclindner May 19, 2026
a4162ed
refactor: more test iteration
bclindner May 19, 2026
0b8efdf
fix: removed parent/grandparent images from build metadata
bclindner May 19, 2026
d9e01d6
fix: pip-audit
bclindner May 19, 2026
2e6f467
style: ruff
bclindner May 19, 2026
4d64091
Merge branch 'main' into ISV-6236
bclindner May 27, 2026
75e290f
test(ISV-6236): added test cases
bclindner May 28, 2026
03b1cf6
Merge branch 'ISV-6236' of github.com:konflux-ci/mobster into ISV-6236
bclindner May 28, 2026
164d8e8
style: ruff
bclindner May 28, 2026
a3c57f8
test(ISV-6236): slight test refactor + added 1 new test
bclindner May 29, 2026
c2697ab
refactor: scaffolding for multiple builder images
bclindner May 29, 2026
19ab19d
test(ISV-6236): added final tests
bclindner May 29, 2026
4fae800
fix(ISV-6236): added skips to failing tests
bclindner May 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions tests/integration/img_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,35 @@


def make_metadata_yaml(
tmp_path: Path, img: Image, parent_img: Image | None = None
tmp_path: Path,
img: Image,
base_imgs: list[Image] | None = None,
extra_imgs: list[Image] | None = None,
) -> Path:
metadata = {
"image": {
"pullspec": f"{img.repository}:{img.tag}",
"digest": img.digest,
},
"base_images": [],
"extra_images": [],
}
if parent_img:
metadata["base_images"].append( # type: ignore[attr-defined]
{
"pullspec": f"{parent_img.repository}:{parent_img.tag}",
"digest": parent_img.digest,
}
)
if base_imgs:
for base_img in base_imgs:
metadata["base_images"].append( # type: ignore[attr-defined]
{
"pullspec": f"{base_img.repository}:{base_img.tag}",
"digest": base_img.digest,
}
)
if extra_imgs:
for extra_img in extra_imgs:
metadata["extra_images"].append( # type: ignore[attr-defined]
{
"pullspec": f"{extra_img.repository}:{extra_img.tag}",
"digest": extra_img.digest,
}
)
path = tmp_path / f"{img.digest}.metadata.yaml"
with open(path, "w") as fp:
fp.write(yaml.dump(metadata))
Expand Down
201 changes: 140 additions & 61 deletions tests/integration/oci_image/conftest.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,136 @@
import subprocess
from dataclasses import dataclass
from pathlib import Path
from typing import Literal

import pytest
from spdx_tools.spdx.model.relationship import Relationship, RelationshipType
from spdx_tools.spdx.parser.parse_anything import parse_file
from spdx_tools.spdx.writer.write_anything import write_file

from mobster.cmd.generate.oci_image.contextual_sbom.builder import (
BuilderPkgMetadataItem,
)
from mobster.image import Image
from tests.spdx_builder import AnnotatedPackage, SPDXPackageBuilder, SPDXSBOMBuilder


@dataclass
class SBOMPackage:
"""Interchange format for a (non-image) package in an SBOM.

Since our tests sometimes need the same package data in AnnotatedPackage
and BuilderPkgMetadataItem formats, we use this class as to avoid declaring
the same strings twice.

This does not support generating AnnotatedPackages for OCI images."""

name: str
purl: str
version: str
dependency_of_purl: str | None
sha256_checksum: str | None
verification_code: str | None

def to_spdx(self) -> AnnotatedPackage:
"""Convert to AnnotatedPackage (using SPDXPackageBuilder).

The verification_code and sha256_checksum fields will be added if
available."""
builder = (
SPDXPackageBuilder().name(self.name).purl(self.purl).version(self.version)
)
if self.sha256_checksum:
builder.sha256_checksum(self.sha256_checksum)
if self.verification_code:
builder.verification_code(self.verification_code)
return builder.build()

def to_metadata(
self, origin_type: Literal["builder", "intermediate"], origin_pullspec: str
) -> BuilderPkgMetadataItem:
"""Convert to BuilderPkgMetadataItem.

Ignores verification_code and sha256_checksum."""
return BuilderPkgMetadataItem(
purl=self.purl,
pullspec=origin_pullspec,
origin_type=origin_type,
)


@pytest.fixture
def gin_pkg() -> SBOMPackage:
return SBOMPackage(
name="github.com/gin-gonic/gin",
version="v1.9.1",
purl="pkg:golang/github.com/gin-gonic/gin@v1.9.1",
dependency_of_purl=None,
sha256_checksum="a1b2c3d4e5f67890123456789012345678901234567890123456789012345678",
verification_code=None,
)


@pytest.fixture
def crypto_pkg() -> SBOMPackage:
return SBOMPackage(
name="golang.org/x/crypto",
version="v0.14.0",
purl="pkg:golang/golang/golang.org/x/crypto@v0.14.0",
dependency_of_purl=None,
sha256_checksum="9876543210abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
verification_code=None,
)


@pytest.fixture
def random_pkg() -> SBOMPackage:
return SBOMPackage(
name="golang.org/x/random",
version="v0.14.0",
purl="pkg:golang/golang/golang.org/x/random@v0.14.0",
dependency_of_purl=None,
sha256_checksum=None,
verification_code="d6a770ba38583ed4bb4525bd96e50461655d2758",
)


@pytest.fixture
def malware_pkg() -> SBOMPackage:
return SBOMPackage(
name="golang.org/x/malware",
version="v1.14.0",
purl="pkg:golang/golang/golang.org/x/malware@v1.14.0",
dependency_of_purl="pkg:golang/github.com/gin-gonic/gin@v1.9.1",
sha256_checksum=None,
verification_code=None,
)


@pytest.fixture
def ginkgo_pkg() -> SBOMPackage:
return SBOMPackage(
name="golang.org/x/ginkgo",
version="v0.14.0",
purl="pkg:golang/golang/golang.org/x/ginkgo@v0.14.0",
dependency_of_purl=None,
sha256_checksum="487198278acdcdef0123456789abcdef0123456789abcdef0123456789abcdef",
verification_code=None,
)


@pytest.fixture
def stdlib_pkg() -> SBOMPackage:
return SBOMPackage(
name="golang.org/x/stdlib",
version="v0.14.0",
purl="pkg:golang/golang/golang.org/x/stdlib@v0.14.0",
dependency_of_purl=None,
sha256_checksum="1237773276cdcdef0123456789abcdef0123456789abcdef0123456789abcdef",
verification_code=None,
)


@dataclass
class GenerateData:
"""
Expand All @@ -22,10 +142,11 @@ class GenerateData:
image: Image | None = None
input_sbom_path: Path | None = None
metadata_path: Path | None = None
build_metadata_path: Path | None = None
contextualize: bool = True


def run_mobster_generate(gdata: GenerateData) -> None:
def run_mobster_generate(gdata: GenerateData) -> subprocess.CompletedProcess[bytes]:
"""
Run a mobster generate oci image command with the supplied arguments.
"""
Expand Down Expand Up @@ -58,62 +179,38 @@ def run_mobster_generate(gdata: GenerateData) -> None:
if gdata.metadata_path:
cmd.extend(["--metadata-path", str(gdata.metadata_path)])

subprocess.run(cmd, check=True)
if gdata.build_metadata_path:
cmd.extend(["--build-metadata-path", str(gdata.build_metadata_path)])

return subprocess.run(cmd, check=True, capture_output=True)


@pytest.fixture
def grandparent_packages() -> list[AnnotatedPackage]:
def grandparent_packages(gin_pkg: SBOMPackage) -> list[AnnotatedPackage]:
"""
Returns a list of annotated packages that should be specific to the
grandparent after parent/component contextualization.
"""
return [
SPDXPackageBuilder()
.name("github.com/gin-gonic/gin")
.version("v1.9.1")
.sha256_checksum(
"a1b2c3d4e5f67890123456789012345678901234567890123456789012345678"
)
.purl("pkg:golang/github.com/gin-gonic/gin@v1.9.1")
.build()
]
return [gin_pkg.to_spdx()]


@pytest.fixture
def parent_packages() -> list[AnnotatedPackage]:
def parent_packages(
crypto_pkg: SBOMPackage,
random_pkg: SBOMPackage,
malware_pkg: SBOMPackage,
) -> list[AnnotatedPackage]:
"""
Returns a list of annotated packages that should be specific to the parent
after component contextualization.

Tests multiple purl matching mechanisms.
"""
checksum_match = (
SPDXPackageBuilder()
.name("golang.org/x/crypto")
.version("v0.14.0")
.sha256_checksum(
"9876543210abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
)
.purl("pkg:golang/golang/golang.org/x/crypto@v0.14.0")
.build()
)
checksum_match = crypto_pkg.to_spdx()

verification_code_match = (
SPDXPackageBuilder()
.name("golang.org/x/random")
.version("v0.14.0")
.purl("pkg:golang/golang/golang.org/x/random@v0.14.0")
.verification_code("d6a770ba38583ed4bb4525bd96e50461655d2758")
.build()
)
verification_code_match = random_pkg.to_spdx()

purl_match = (
SPDXPackageBuilder()
.name("golang.org/x/malware")
.version("v1.14.0")
.purl("pkg:golang/golang/golang.org/x/malware@v1.14.0")
.build()
)
purl_match = malware_pkg.to_spdx()

return [
checksum_match,
Expand All @@ -123,40 +220,22 @@ def parent_packages() -> list[AnnotatedPackage]:


@pytest.fixture
def parent_only_packages() -> list[AnnotatedPackage]:
def parent_only_packages(ginkgo_pkg: SBOMPackage) -> list[AnnotatedPackage]:
"""
Returns a list of annotated packages that should be removed from the
component SBOM after contextualization. This simulates a case when some
packages are remove during a component build.
"""
return [
SPDXPackageBuilder()
.name("golang.org/x/ginkgo")
.version("v0.14.0")
.sha256_checksum(
"487198278acdcdef0123456789abcdef0123456789abcdef0123456789abcdef"
)
.purl("pkg:golang/golang/golang.org/x/ginkgo@v0.14.0")
.build()
]
return [ginkgo_pkg.to_spdx()]


@pytest.fixture
def component_packages() -> list[AnnotatedPackage]:
def component_packages(stdlib_pkg: SBOMPackage) -> list[AnnotatedPackage]:
"""
Returns a list of annotated packages that should be specific to the
component SBOM after contextualization.
"""
return [
SPDXPackageBuilder()
.name("golang.org/x/stdlib")
.version("v0.14.0")
.sha256_checksum(
"1237773276cdcdef0123456789abcdef0123456789abcdef0123456789abcdef"
)
.purl("pkg:golang/golang/golang.org/x/stdlib@v0.14.0")
.build()
]
return [stdlib_pkg.to_spdx()]


@pytest.fixture
Expand Down
Loading
Loading