@@ -16,14 +16,10 @@ ARG PYTHON_VERSION
1616ARG ACTIONS_PYTHON_VERSIONS
1717ARG TRIVY_VERSION
1818
19- # Many base images (including our `powershell` image) switch to a non-root
20- # runtime user for security. The builder stage must perform system package
21- # installs and compile steps which require root. Explicitly switch back to
22- # `root` here so all following RUN steps have the privileges they need.
19+ # Switch to root for installation privileges
2320USER root
2421
25- # Use bash with pipefail so any command in a pipeline failing will cause the
26- # whole RUN step to fail (safer for build-time checks and early failure).
22+ # Use bash with pipefail for safety
2723SHELL ["/bin/bash" , "-o" , "pipefail" , "-c" ]
2824
2925# Build environment and compiler hardening flags
@@ -44,7 +40,7 @@ ENV pythonLocation=${PYTHON_INSTALL_DIR} \
4440 RUNNER_TEMP=/tmp \
4541 RUNNER_TOOL_CACHE=/opt
4642
47- # Combined Install Step (Essential + Core + Optional) to reduce layers.
43+ # Combined Install Step (Essential + Core + Optional)
4844RUN apt-get -qq update -y && \
4945 apt-get -qq -y install --no-install-recommends \
5046 tzdata curl wget gcc g++ make git ca-certificates \
@@ -57,18 +53,18 @@ RUN apt-get -qq update -y && \
5753 python3 pkg-config sudo libmpdec-dev libbluetooth-dev libz-dev || true) && \
5854 apt-get clean && rm -rf /var/lib/apt/lists/*
5955
60- # Install Trivy (used for local security gates)
56+ # Install Trivy
6157RUN curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin ${TRIVY_VERSION}
6258
63- # Clone Python
59+ # Clone Python Build Scripts
6460RUN if [ ! -d /python-versions ]; then git clone https://github.com/actions/python-versions.git /python-versions; fi
6561WORKDIR /python-versions
6662RUN git checkout "${ACTIONS_PYTHON_VERSIONS}" && git submodule init && git submodule update
6763
68- # [CEVS STEP 1] Scan Source Code BEFORE Build
64+ # [CEVS STEP 1] Scan Source Code
6965RUN trivy fs --scanners secret,misconfig --exit-code 1 ./
7066
71- # Build Python & Restore Artifact (FIXED LOGIC)
67+ # Build Python & Restore Artifact
7268# The `build-python.ps1` script creates a compiled tarball in `/tmp/artifact` and
7369# cleans up the `/opt` directory to save space. We immediately extract that
7470# artifact back into place so `python-tests.ps1` can find the binaries.
@@ -97,31 +93,27 @@ RUN export MAKEFLAGS="-j $(nproc)" && \
9793 ${PYTHON_INSTALL_DIR}/bin/python3 -c "import ssl; print('Python installed and SSL verified')"
9894
9995# [CEVS STEP 2] Scan the Compiled Artifact (The Gatekeeper)
100- # Generate SBOM (Only happens if CEVS passed) and place it in /tmp/artifact
96+ # Generate SBOM & Reports
10197RUN mkdir -p /tmp/artifact && \
10298 trivy fs --format cyclonedx --output /tmp/artifact/python-${PYTHON_VERSION}-${TARGETARCH}.sbom.json ${PYTHON_INSTALL_DIR} || true
10399
104- # Also write Trivy JSON reports (vuln and secret/misconfig) into /tmp/artifact
100+ # Write Trivy JSON reports
105101RUN trivy --download-db-only || true; \
106102 trivy fs --format json --output /tmp/artifact/trivy-${PYTHON_VERSION}-${TARGETARCH}-vuln.json --scanners vuln ${PYTHON_INSTALL_DIR} || true && \
107103 trivy fs --format json --output /tmp/artifact/trivy-${PYTHON_VERSION}-${TARGETARCH}-secret.json --scanners secret,misconfig ${PYTHON_INSTALL_DIR} || true
108104
109- # Create a small gate script to parse Trivy JSON and decide whether to fail
110- # the build. This provides a single place to tune thresholds or ignore rules.
105+ # Create the Gate Script
111106COPY <<EOF /usr/local/bin/trivy-gate.sh
112107# !/bin/sh
113108set -e
114- # Inputs: vuln-json, secret-json
115109VULN_JSON=\$ {1:-/tmp/artifact/trivy-${PYTHON_VERSION}-${TARGETARCH}-vuln.json}
116110SECRET_JSON=\$ {2:-/tmp/artifact/trivy-${PYTHON_VERSION}-${TARGETARCH}-secret.json}
117- # Controls: Set these env vars to tune build gating behavior
118111FAIL_ON_CRITICAL=\$ {FAIL_ON_CRITICAL:-1}
119112FAIL_ON_HIGH=\$ {FAIL_ON_HIGH:-0}
120113FAIL_ON_MEDIUM=\$ {FAIL_ON_MEDIUM:-0}
121114FAIL_ON_SECRET=\$ {FAIL_ON_SECRET:-1}
122- echo "Trivy Gate: checking \$ VULN_JSON and \$ SECRET_JSON"
123115
124- # Initialize counters
116+ echo "Trivy Gate: checking \$ VULN_JSON and \$ SECRET_JSON"
125117critical=0; high=0; medium=0; secrets=0
126118
127119if [ -f "\$ VULN_JSON" ]; then
135127
136128echo "Counts => CRITICAL=\$ critical HIGH=\$ high MEDIUM=\$ medium SECRETS=\$ secrets"
137129
138- if [ " \$ FAIL_ON_CRITICAL" -eq 1 -a " \$ critical" -gt 0 ]; then
139- echo "ERROR: Trivy found CRITICAL vulnerabilities: \$ critical"
140- exit 1
141- fi
142- if [ " \$ FAIL_ON_HIGH" -eq 1 -a " \$ high" -gt 0 ]; then
143- echo "ERROR: Trivy found HIGH vulnerabilities: \$ high"
144- exit 1
145- fi
146- if [ "\$ FAIL_ON_SECRET" -eq 1 -a " \$ secrets" -gt 0 ]; then
147- echo "ERROR: Trivy found secrets/misconfigs: \$ secrets "
130+ BLOCK=false
131+ if [ " \$ FAIL_ON_CRITICAL" -eq 1 ] && [ " \$ critical" -gt 0 ]; then BLOCK=true; fi
132+ if [ " \$ FAIL_ON_HIGH" -eq 1 ] && [ " \$ high" -gt 0 ]; then BLOCK=true; fi
133+ if [ " \$ FAIL_ON_SECRET" -eq 1 ] && [ " \$ secrets" -gt 0 ]; then BLOCK=true; fi
134+
135+ # Write result for Makefile extraction
136+ printf '{"critical":%d,"high":%d,"medium":%d,"secrets":%d,"block":%s} \n ' " \$ critical" " \$ high" " \$ medium" " \$ secrets" " \$ BLOCK" > /tmp/artifact/trivy-gate-result.json
137+
138+ if [ "\$ BLOCK" = "true" ]; then
139+ echo "GATE FAILED. "
148140 exit 1
141+ else
142+ echo "GATE PASSED."
143+ exit 0
149144fi
150-
151- echo "Trivy gate passed; no blocker findings."
152- exit 0
153145EOF
154146RUN chmod +x /usr/local/bin/trivy-gate.sh
155147
156- # Run the gate. Note: FAIL_ON_CRITICAL is set to 0 here to allow build to pass
157- # during development/debugging, but the reports are generated above.
158- RUN FAIL_ON_CRITICAL=0 FAIL_ON_HIGH=0 FAIL_ON_MEDIUM=0 FAIL_ON_SECRET=0 /usr/local/bin/trivy-gate.sh /tmp/artifact/trivy-${PYTHON_VERSION}-${TARGETARCH}-vuln.json /tmp/artifact/trivy-${PYTHON_VERSION}-${TARGETARCH}-secret.json || true
148+ # Run the gate (non-blocking for now so artifacts are exported)
149+ RUN FAIL_ON_CRITICAL=0 FAIL_ON_HIGH=0 FAIL_ON_MEDIUM=0 FAIL_ON_SECRET=0 /usr/local/bin/trivy-gate.sh || true
159150
160151# Run Tests
161152WORKDIR /python-versions/tests
162- # Ensure the build output log exists (created during pwsh build) for tests to analyze
163153RUN cp $RUNNER_TEMP/work/build_output.txt $RUNNER_TEMP/ || touch $RUNNER_TEMP/build_output.txt
164154RUN pwsh -Command "Install-Module -Name Pester -Force -Scope CurrentUser -SkipPublisherCheck" && \
165155 AGENT_TOOLSDIRECTORY=/opt RUNNER_TOOL_CACHE=/opt pwsh python-tests.ps1 ${PYTHON_VERSION} linux ${TARGETARCH}
@@ -175,7 +165,7 @@ FROM ubuntu:${UBUNTU_VERSION} AS final
175165ARG PYTHON_VERSION
176166ARG TARGETARCH
177167
178- # Set up a non-root user (Security Best Practice)
168+ # Set up a non-root user
179169RUN groupadd -g 10001 python_group && \
180170 useradd -u 10001 -g python_group -s /bin/bash -m python_user
181171
@@ -185,8 +175,11 @@ RUN apt-get update && \
185175 ca-certificates openssl libssl3 libffi8 libsqlite3-0 liblzma5 libbz2-1.0 zlib1g && \
186176 rm -rf /var/lib/apt/lists/*
187177
188- # Copy Artifacts
178+ # Copy Installed Python
189179COPY --from=builder /opt/Python/${PYTHON_VERSION}/${TARGETARCH} /opt/Python/${PYTHON_VERSION}/${TARGETARCH}
180+
181+ # [IMPORTANT] Copy Build Artifacts & Reports so Makefile can extract them
182+ COPY --from=builder /tmp/artifact /tmp/artifact
190183COPY --from=builder /tmp/artifact/python-${PYTHON_VERSION}-${TARGETARCH}.sbom.json /opt/python-sbom.json
191184
192185# Clean Source
0 commit comments