4.1 Source forbid-list
On this page you prove that the files the build actually uses fetch only from inside the trust boundary.
Track 4 is the hermetic build. This is the first of its four pages. 3.2 Bind base and deps already pointed the runtime stage at the dest Hummingbird Route. The build stage is still UBI on a public registry, and settings.xml can still see Maven Central. You import a JDK builder and the dest Hummingbird image into the internal registry, retarget both FROM lines, and remove Central from the Lightwell profiles. 4.2 Prefetch (Hermeto mapping) is the offline resolve. 4.3 Build NetworkPolicy is the egress gate that will make a leftover public fetch fail.
Why this control exists
Hermetic production starts in git. Lightwell Network GAVs and the dest Hummingbird image enter the application only when the active Dockerfile and settings.xml have no public fallback. A Central remote would bypass the proxy you configured in 2.1 the moment a later page is skipped. You remove the public FROM, the curl of a random host, and the public Maven index now, while egress is still open, because 4.3 will make those fetches fail for real.
Dockerfile.known-bad stays in the repository as the negative fixture 4.4 still builds. It is not the file the BuildConfig uses.
The figure is the edit. The left column is the seed: a public build FROM, a runtime FROM that is still a public registry or the Nexus Docker Route, and repo.maven.apache.org in settings.xml. The right column is the scored tree: ImageStream openjdk-21-builder for the build stage, ImageStream hummingbird-openjdk at the imported manifest digest for the runtime stage, and the in-cluster Nexus service URL for Maven. That digest is the amd64 manifest import-image stores. The 1.2 index digest stays on the dest pull spec. Dockerfile.known-bad sits beside that column. It keeps a public FROM and a curl, and it is not the active build file.
Lightwell Clearinghouse Premier does not add a public index. A member-specific GAV resolves from the same in-cluster Nexus service URL you point Maven at here.
|
On a Python application the same grep is |
In a customer engagement this is a source policy: the Containerfile the build uses has no network fetch. You grep the git tree and fix it. The cluster NetworkPolicy is the later gate.
Learning objectives
By the end of this module, you will be able to:
-
Import the JDK builder and the dest Hummingbird image into namespace
lw-poc-build -
Point both active
FROMlines at those internal ImageStreams, and pin the runtime stage to the digest ImageStreamhummingbird-openjdkstored -
Remove Maven Central from the Lightwell profiles and point them at
nexus_internal_url -
Keep
Dockerfile.known-badin the tree without selecting it as the BuildConfig Dockerfile
What the seed still fetches
Clone the learner app if /tmp/spring-boot-lw-poc is missing. The remote is student_repo_url. Success of the grep is at least a build-stage FROM of UBI on registry.access.redhat.com, and repo.maven.apache.org in settings.xml.
cd /tmp/spring-boot-lw-poc
grep -nE 'FROM |curl |repo.maven.apache.org|registry.access.redhat.com|registry.redhat.io' Dockerfile settings.xml pom.xml || true
The block below is a public FROM and a curl on a different host. Using it as the active Dockerfile fails the Check.
# Worked example ONLY — different public host. Do not use as the active Dockerfile.
FROM docker.io/library/eclipse-temurin:21-jdk
RUN curl -fsSL https://example.invalid/install.sh | sh
Your change
build-egress is still open, so the imports below can reach the public catalog and the Nexus Route. Import a JDK builder into the build namespace. The image is the UBI JDK stream already named by the seed, copied into the internal registry. There is no separate Hummingbird builder digest to invent. Import the dest Hummingbird image the same way. The 3.2 runtime FROM is the Nexus Docker Route, and 4.3 blocks that Route from lw-poc-build.
1.1 Verify Hummingbird separated the image index from the amd64 manifest inside it. The DEST pull spec is that index. import-image stores the amd64 manifest. On ImageStream hummingbird-openjdk that manifest is status.tags[].items[].image. The tag’s dockerImageReference still names the dest Route. The runtime FROM you commit uses the internal registry host and that image digest. The index digest stays on the 1.2 pull spec. The Route host stays in dockerImageReference. Those two sha256 values differ. A FROM that puts the index digest on the internal host fails the 4.4 build with manifest unknown, because the internal registry stored the manifest.
BUILD_NS comes from student_build_namespace. Success is two ImageStreams in that namespace. DEST still prints the 1.2 index pull spec. The next lines are tag=latest and image=sha256:…. The last line is dockerImageReference, and its host is the dest Route.
BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
oc -n "${BUILD_NS}" import-image openjdk-21-builder \
--from=registry.access.redhat.com/ubi9/openjdk-21:1.21 \
--confirm
DEST="$(oc -n lightwell-repo logs job/oc-mirror-learner -c copy-signatures | grep '^DEST_PULLSPEC=' | cut -d= -f2-)"
echo "DEST=${DEST}"
oc -n "${BUILD_NS}" import-image hummingbird-openjdk \
--from="${DEST}" --confirm --insecure=true
oc -n "${BUILD_NS}" get imagestream hummingbird-openjdk \
-o jsonpath='tag={.status.tags[0].tag}{"\n"}image={.status.tags[0].items[0].image}{"\n"}'
oc -n "${BUILD_NS}" get istag hummingbird-openjdk:latest \
-o jsonpath='{.image.dockerImageReference}{"\n"}'
Point the Dockerfile build FROM at ImageStream openjdk-21-builder on the internal registry, image-registry.openshift-image-registry.svc:5000/${BUILD_NS}/openjdk-21-builder:latest. Point the runtime FROM at ImageStream hummingbird-openjdk on that same host, with the image= digest: image-registry.openshift-image-registry.svc:5000/${BUILD_NS}/hummingbird-openjdk@sha256:…. An active FROM that names dest_registry_host or registry.access.redhat.com fails the Check.
In settings.xml, remove repo.maven.apache.org from the Lightwell profiles. Point the remotes at the in-cluster Nexus service. That URL is nexus_internal_url from userinfo, http://nexus.lightwell-repo.svc:8081, which is the Service, not the HTTPS Route. Add a <mirror> whose mirrorOf is * or external:* and whose URL is ${nexus_internal_url}/repository/maven-public/. Seeded maven-public includes Validated and Remediated, so the .rhlw-* pin still resolves. 4.3 blocks the Nexus Route from lw-poc-build. The Service URL keeps working.
If Dockerfile.known-bad is missing from the clone, copy it from the seed. The template repository already includes it. It keeps a public FROM and a curl. Leave it unselected as the BuildConfig Dockerfile. 4.4 still uses that file as a negative.
Success of the commit is a push of Dockerfile, settings.xml, and Dockerfile.known-bad.
cd /tmp/spring-boot-lw-poc
git add Dockerfile settings.xml Dockerfile.known-bad
git commit -m "Forbid-list: internal FROM and Nexus-only Maven remotes"
git push origin HEAD
Check
Read the committed files. Success is active FROM lines on the internal registry, a runtime digest equal to the ImageStream image value, no dest-registry Route, no Maven Central, and no curl installer in Dockerfile or settings.xml. Dockerfile.known-bad is still in the work tree. The Validate Job grades the host. Match the runtime sha256 to the image= line, because the 4.4 build pulls that manifest from the internal registry.
cd /tmp/spring-boot-lw-poc
git show HEAD:Dockerfile | grep -E '^FROM '
BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
oc -n "${BUILD_NS}" get imagestream hummingbird-openjdk \
-o jsonpath='image={.status.tags[0].items[0].image}{"\n"}'
git show HEAD:settings.xml | grep -E 'repo.maven.apache.org|lightwell-repo' || true
test -f Dockerfile.known-bad && echo 'known-bad fixture present'
The Validate Job grades that scan. The next page still opens if you skip this one.
The Job also grades ConfigMap report-08-forbid-list key hermetic_starts. Set it to source. Empty or REPLACE_ME fails even if cluster state is correct. Do not copy validate-docs.
oc -n lw-poc-validate edit configmap report-08-forbid-list
The scored Check is Job validate-08-forbid-list in lw-poc-validate. Direct nav URLs still work (honor system). Unlimited retries. There is no Solve.
oc -n lw-poc-validate delete job validate-08-forbid-list --ignore-not-found
TPL='job-08.yaml'
oc -n lw-poc-validate get configmap validate-job-templates \
-o go-template="{{ index .data \"${TPL}\" }}" | oc create -f -
oc -n lw-poc-validate logs -f job/validate-08-forbid-list
Expect CHECK PASSED: before you continue. CHECK FAILED: names the object to fix. Delete the Job and create it again as often as you need.
Official documentation
-
Lightwell Network Java repository (the remotes that remain after Central is gone)
-
Konflux mapping (a hermetic source policy maps to this Check)
