Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions src/macaron/build_spec_generator/common_spec/base_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class BaseBuildSpecDict(TypedDict, total=False):
#: Flag to indicate if the artifact includes binaries.
has_binaries: NotRequired[bool]

#: The artifacts that were analyzed in generating the build specification.
upstream_artifacts: dict[str, list[str]]


class BaseBuildSpec(ABC):
"""Abstract base class for build specification behavior and field resolution."""
Expand Down
5 changes: 5 additions & 0 deletions src/macaron/build_spec_generator/common_spec/pypi_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def resolve_fields(self, purl: PackageURL) -> None:
metadata=[],
)

upstream_artifacts: dict[str, list[str]] = {}
pypi_package_json = pypi_registry.find_or_create_pypi_asset(purl.name, purl.version, registry_info)
patched_build_commands: list[list[str]] = []
build_backends_set: set[str] = set()
Expand Down Expand Up @@ -141,6 +142,7 @@ def resolve_fields(self, purl: PackageURL) -> None:
try:
# The wheel function handles downloading binaries in the case that we cannot find a pure wheel.
with pypi_package_json.wheel(download_binaries=self.data["has_binaries"]):
upstream_artifacts["wheels"] = pypi_package_json.wheel_urls
logger.debug("Wheel at %s", pypi_package_json.wheel_path)
# Should only have .dist-info directory.
logger.debug("It has directories %s", ",".join(os.listdir(pypi_package_json.wheel_path)))
Expand Down Expand Up @@ -184,6 +186,8 @@ def resolve_fields(self, purl: PackageURL) -> None:

try:
with pypi_package_json.sourcecode():
upstream_artifacts["sdist"] = [pypi_package_json.sdist_url]
logger.debug("sdist url at %s", upstream_artifacts["sdist"])
try:
# Get the build time requirements from ["build-system", "requires"]
pyproject_content = pypi_package_json.get_sourcecode_file_contents("pyproject.toml")
Expand Down Expand Up @@ -269,6 +273,7 @@ def resolve_fields(self, purl: PackageURL) -> None:
if not self.data["has_binaries"]:
patched_build_commands = self.get_default_build_commands(self.data["build_tools"])
self.data["build_commands"] = patched_build_commands
self.data["upstream_artifacts"] = upstream_artifacts

def add_parsed_requirement(self, build_requirements: dict[str, str], requirement: str) -> None:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,30 @@ def gen_dockerfile(buildspec: BaseBuildSpecDict) -> str:
build_tool_install = (
f"pip install {buildspec['build_tools'][0]} && if test -f \"flit.ini\"; then python -m flit.tomlify; fi && "
)

modern_build_command = build_tool_install + " ".join(x for x in buildspec["build_commands"][0])
legacy_build_command = (
'if test -f "setup.py"; then pip install wheel && python setup.py bdist_wheel; '
"else python -m build --wheel -n; fi"
)

wheel_url: str = ""
wheel_name: str = ""

wheel_urls = buildspec["upstream_artifacts"]["wheels"]
# We currently only look for the pure wheel, if it exists
if wheel_urls:
wheel_url = list(wheel_urls)[0]
wheel_name = wheel_url.rsplit("/", 1)[-1]
else:
logger.debug("We could not find an upstream artifact, and therefore we cannot run validation")

dockerfile_content = f"""
#syntax=docker/dockerfile:1.10
FROM oraclelinux:9

# Install core tools
RUN dnf -y install which wget tar git
RUN dnf -y install which wget tar unzip git

# Install compiler and make
RUN dnf -y install gcc make
Expand Down Expand Up @@ -127,6 +139,30 @@ def gen_dockerfile(buildspec: BaseBuildSpecDict) -> str:

# Run the build
RUN source /deps/bin/activate && {modern_build_command if version in SpecifierSet(">=3.6") else legacy_build_command}

# Validate script
RUN cat <<'EOF' >/validate
[ -n "{wheel_url}" ] || {{ echo "No upstream artifact to validate against."; exit 1; }}
# Capture artifacts generated
WHEELS=(/src/dist/*.whl)
# Ensure we only have one artifact
[ ${{#WHEELS[@]}} -eq 1 ] || {{ echo "Unexpected artifacts produced!"; exit 1; }}
# BUILT_WHEEL is the artifact we built
BUILT_WHEEL=${{WHEELS[0]}}
# Ensure the artifact produced is not the literal returned by the glob
[ -e $BUILT_WHEEL ] || {{ echo "No wheels found!"; exit 1; }}
# Download the wheel
wget -q {wheel_url}
# Compare wheel names
[ $(basename $BUILT_WHEEL) == "{wheel_name}" ] || {{ echo "Wheel name does not match!"; exit 1; }}
# Compare file tree
(unzip -Z1 $BUILT_WHEEL | grep -v '\\.dist-info' | sort) > built.tree
(unzip -Z1 "{wheel_name}" | grep -v '\\.dist-info' | sort ) > pypi_artifact.tree
diff -u built.tree pypi_artifact.tree || {{ echo "File trees do not match!"; exit 1; }}
echo "Success!"
EOF

ENTRYPOINT ["/bin/bash","/validate"]
"""

return dedent(dockerfile_content)
Expand Down
8 changes: 8 additions & 0 deletions src/macaron/slsa_analyzer/package_registry/pypi_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,12 @@ class PyPIPackageJsonAsset:
#: The source code temporary location name.
package_sourcecode_path: str = field(init=False)

#: URL of the sdist file.
sdist_url: str = field(init=False)

#: URL of the wheel file.
wheel_urls: list[str] = field(init=False)

#: The wheel temporary location name.
wheel_path: str = field(init=False)

Expand Down Expand Up @@ -832,6 +838,7 @@ def get_sourcecode_url(self, package_type: str = "sdist") -> str | None:
fragment="",
).geturl()
logger.debug("Found source URL: %s", configured_source_url)
self.sdist_url = configured_source_url
return configured_source_url
return None

Expand Down Expand Up @@ -892,6 +899,7 @@ def get_wheel_url(self, tag: str = "none-any") -> str | None:
fragment="",
).geturl()
logger.debug("Found wheel URL: %s", configured_wheel_url)
self.wheel_urls = [configured_wheel_url]
return configured_wheel_url
return None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
FROM oraclelinux:9

# Install core tools
RUN dnf -y install which wget tar git
RUN dnf -y install which wget tar unzip git

# Install compiler and make
RUN dnf -y install gcc make
Expand Down Expand Up @@ -69,5 +69,29 @@
# Run the build
RUN source /deps/bin/activate && python -m build

# Validate script
RUN cat <<'EOF' >/validate
[ -n "https://files.pythonhosted.org/packages/96/c5/1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl" ] || { echo "No upstream artifact to validate against."; exit 1; }
# Capture artifacts generated
WHEELS=(/src/dist/*.whl)
# Ensure we only have one artifact
[ ${#WHEELS[@]} -eq 1 ] || { echo "Unexpected artifacts produced!"; exit 1; }
# BUILT_WHEEL is the artifact we built
BUILT_WHEEL=${WHEELS[0]}
# Ensure the artifact produced is not the literal returned by the glob
[ -e $BUILT_WHEEL ] || { echo "No wheels found!"; exit 1; }
# Download the wheel
wget -q https://files.pythonhosted.org/packages/96/c5/1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl
# Compare wheel names
[ $(basename $BUILT_WHEEL) == "cachetools-6.2.1-py3-none-any.whl" ] || { echo "Wheel name does not match!"; exit 1; }
# Compare file tree
(unzip -Z1 $BUILT_WHEEL | grep -v '\.dist-info' | sort) > built.tree
(unzip -Z1 "cachetools-6.2.1-py3-none-any.whl" | grep -v '\.dist-info' | sort ) > pypi_artifact.tree
diff -u built.tree pypi_artifact.tree || { echo "File trees do not match!"; exit 1; }
echo "Success!"
EOF

ENTRYPOINT ["/bin/bash","/validate"]

'''
# ---
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ def fixture_base_build_spec() -> BaseBuildSpecDict:
"build_commands": [["python", "-m", "build"]],
"build_requires": {"setuptools": "==80.9.0", "wheel": ""},
"build_backends": ["setuptools.build_meta"],
"upstream_artifacts": {
"wheels": [
"https://files.pythonhosted.org/packages/96/c5/"
"1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl"
],
"sdist": [
"https://files.pythonhosted.org/packages/cc/7e/"
"b975b5814bd36faf009faebe22c1072a1fa1168db34d285ef0ba071ad78c/cachetools-6.2.1.tar.gz"
],
},
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,13 @@
},
"build_backends": [
"setuptools.build_meta"
]
],
"upstream_artifacts": {
"wheels": [
"https://files.pythonhosted.org/packages/96/c5/1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl"
],
"sdist": [
"https://files.pythonhosted.org/packages/cc/7e/b975b5814bd36faf009faebe22c1072a1fa1168db34d285ef0ba071ad78c/cachetools-6.2.1.tar.gz"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
FROM oraclelinux:9

# Install core tools
RUN dnf -y install which wget tar git
RUN dnf -y install which wget tar unzip git

# Install compiler and make
RUN dnf -y install gcc make
Expand Down Expand Up @@ -65,3 +65,27 @@ EOF

# Run the build
RUN source /deps/bin/activate && python -m build --wheel -n

# Validate script
RUN cat <<'EOF' >/validate
[ -n "https://files.pythonhosted.org/packages/96/c5/1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl" ] || { echo "No upstream artifact to validate against."; exit 1; }
# Capture artifacts generated
WHEELS=(/src/dist/*.whl)
# Ensure we only have one artifact
[ ${#WHEELS[@]} -eq 1 ] || { echo "Unexpected artifacts produced!"; exit 1; }
# BUILT_WHEEL is the artifact we built
BUILT_WHEEL=${WHEELS[0]}
# Ensure the artifact produced is not the literal returned by the glob
[ -e $BUILT_WHEEL ] || { echo "No wheels found!"; exit 1; }
# Download the wheel
wget -q https://files.pythonhosted.org/packages/96/c5/1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl
# Compare wheel names
[ $(basename $BUILT_WHEEL) == "cachetools-6.2.1-py3-none-any.whl" ] || { echo "Wheel name does not match!"; exit 1; }
# Compare file tree
(unzip -Z1 $BUILT_WHEEL | grep -v '\.dist-info' | sort) > built.tree
(unzip -Z1 "cachetools-6.2.1-py3-none-any.whl" | grep -v '\.dist-info' | sort ) > pypi_artifact.tree
diff -u built.tree pypi_artifact.tree || { echo "File trees do not match!"; exit 1; }
echo "Success!"
EOF

ENTRYPOINT ["/bin/bash","/validate"]
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,13 @@
},
"build_backends": [
"flit_core.buildapi"
]
],
"upstream_artifacts": {
"wheels": [
"https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"
],
"sdist": [
"https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
FROM oraclelinux:9

# Install core tools
RUN dnf -y install which wget tar git
RUN dnf -y install which wget tar unzip git

# Install compiler and make
RUN dnf -y install gcc make
Expand Down Expand Up @@ -65,3 +65,27 @@ EOF

# Run the build
RUN source /deps/bin/activate && pip install flit && if test -f "flit.ini"; then python -m flit.tomlify; fi && flit build

# Validate script
RUN cat <<'EOF' >/validate
[ -n "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl" ] || { echo "No upstream artifact to validate against."; exit 1; }
# Capture artifacts generated
WHEELS=(/src/dist/*.whl)
# Ensure we only have one artifact
[ ${#WHEELS[@]} -eq 1 ] || { echo "Unexpected artifacts produced!"; exit 1; }
# BUILT_WHEEL is the artifact we built
BUILT_WHEEL=${WHEELS[0]}
# Ensure the artifact produced is not the literal returned by the glob
[ -e $BUILT_WHEEL ] || { echo "No wheels found!"; exit 1; }
# Download the wheel
wget -q https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl
# Compare wheel names
[ $(basename $BUILT_WHEEL) == "markdown_it_py-4.0.0-py3-none-any.whl" ] || { echo "Wheel name does not match!"; exit 1; }
# Compare file tree
(unzip -Z1 $BUILT_WHEEL | grep -v '\.dist-info' | sort) > built.tree
(unzip -Z1 "markdown_it_py-4.0.0-py3-none-any.whl" | grep -v '\.dist-info' | sort ) > pypi_artifact.tree
diff -u built.tree pypi_artifact.tree || { echo "File trees do not match!"; exit 1; }
echo "Success!"
EOF

ENTRYPOINT ["/bin/bash","/validate"]
10 changes: 9 additions & 1 deletion tests/integration/cases/pypi_toga/expected_default.buildspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,13 @@
},
"build_backends": [
"setuptools.build_meta"
]
],
"upstream_artifacts": {
"wheels": [
"https://files.pythonhosted.org/packages/2b/1a/6a9c8230ad30e819f0965bbd596c736a03e16003d27b0363c632c84d4861/toga-0.5.1-py3-none-any.whl"
],
"sdist": [
"https://files.pythonhosted.org/packages/17/e7/0924150329474d61e9f40f8bba1056d640cba22438e05355924019111b46/toga-0.5.1.tar.gz"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
FROM oraclelinux:9

# Install core tools
RUN dnf -y install which wget tar git
RUN dnf -y install which wget tar unzip git

# Install compiler and make
RUN dnf -y install gcc make
Expand Down Expand Up @@ -65,3 +65,27 @@ EOF

# Run the build
RUN source /deps/bin/activate && python -m build --wheel -n

# Validate script
RUN cat <<'EOF' >/validate
[ -n "https://files.pythonhosted.org/packages/2b/1a/6a9c8230ad30e819f0965bbd596c736a03e16003d27b0363c632c84d4861/toga-0.5.1-py3-none-any.whl" ] || { echo "No upstream artifact to validate against."; exit 1; }
# Capture artifacts generated
WHEELS=(/src/dist/*.whl)
# Ensure we only have one artifact
[ ${#WHEELS[@]} -eq 1 ] || { echo "Unexpected artifacts produced!"; exit 1; }
# BUILT_WHEEL is the artifact we built
BUILT_WHEEL=${WHEELS[0]}
# Ensure the artifact produced is not the literal returned by the glob
[ -e $BUILT_WHEEL ] || { echo "No wheels found!"; exit 1; }
# Download the wheel
wget -q https://files.pythonhosted.org/packages/2b/1a/6a9c8230ad30e819f0965bbd596c736a03e16003d27b0363c632c84d4861/toga-0.5.1-py3-none-any.whl
# Compare wheel names
[ $(basename $BUILT_WHEEL) == "toga-0.5.1-py3-none-any.whl" ] || { echo "Wheel name does not match!"; exit 1; }
# Compare file tree
(unzip -Z1 $BUILT_WHEEL | grep -v '\.dist-info' | sort) > built.tree
(unzip -Z1 "toga-0.5.1-py3-none-any.whl" | grep -v '\.dist-info' | sort ) > pypi_artifact.tree
diff -u built.tree pypi_artifact.tree || { echo "File trees do not match!"; exit 1; }
echo "Success!"
EOF

ENTRYPOINT ["/bin/bash","/validate"]
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
},
"build_backends": [
"setuptools.build_meta"
]
],
"upstream_artifacts": {
"sdist": ["https://files.pythonhosted.org/packages/66/7c/0350cfc47faadc0d3cf7d8237a4e34032b3014ddf4a12ded9933e1648b55/tree-sitter-0.25.2.tar.gz"]
}
}
2 changes: 1 addition & 1 deletion tests/integration/cases/pypi_tree-sitter/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ steps:
options:
command_args:
- -purl
- pkg:pypi/markdown-it-py@0.25.2
- pkg:pypi/tree-sitter@0.25.2
- --output-format
- dockerfile
Loading