7.2 Explain the remediation and inspect ACS results

You have retrieved the inventory for the production image. Now explain what the workshop advisory says about its Commons Lang version, store the supported documents in Trusted Profile Analyzer (TPA), and inspect an Advanced Cluster Security (ACS) policy check for that same image. Finish with a short evidence-based report in Showroom.

Why this control exists

An inventory tells you which component version is present. An advisory explains which versions are affected or fixed. Vulnerability Exploitability eXchange (VEX) statements connect a vulnerability assessment to a particular product. Here the product is a Maven group, artifact, and version (GAV): org.apache.commons:commons-lang3:3.14.0.rhlw-00001.

LW-DEMO-0002 is a seeded workshop advisory, not a real CVE. Its OSV record marks upstream 3.14.0 affected and names 3.14.0.rhlw-00001 as fixed. Its OpenVEX document states the same distinction for those exact package URLs. Your conclusion is limited to that sample and the version you observed in the promoted application’s inventory. It does not establish that the application has no other vulnerabilities.

Application SBOM identifies the installed library; OSV and OpenVEX describe the exact library version; OS advisories and ACS policy results answer separate questions

ACS evaluates Central’s image policies. That result is separate from the sample advisory and from Track 6’s signature admission test. TPA ingest does not configure ACS policy or guarantee that ACS recognizes a seeded advisory.

Learning objectives

By the end of this module, you will be able to:

  • Compare the application inventory with the package and fixed version in OSV and OpenVEX.

  • Upload the library CycloneDX document and OSV advisory to their respective TPA endpoints.

  • Configure the pipeline to fail on a skipped ACS check and inspect a check of the promoted digest.

  • Write a report distinguishing sample remediation, ACS policy findings, and signature admission.

Prepare the evidence

Continue from module 7.1 with EVIDENCE, RHTPA_URL, and TOKEN set. If you opened a new terminal, set EVIDENCE="$HOME/lightwell-compliance-evidence" and repeat 7.1’s authentication commands. Refresh an expired token the same way. Keep all evidence outside the application Git clone.

The claim’s ConfigMap keys retain the prefix scored_vex_; they identify the sample documents. You use those coordinates directly without submitting a grading token. Leave the live CSAF importer disabled: Hummingbird and RHEL advisories concern the operating-system layer, while this exercise concerns a Java library.

In a seeded claim, 3.14.0.rhlw-00001 is a simulation fixture: its Maven and JAR metadata identify the sample coordinate, but its Java class files remain upstream 3.14.0. It is marked as a workshop simulation inside the JAR. LW-DEMO-0002 demonstrates comparing exact package identities; neither this fixture nor its sample advisory proves a real security backport. A customer remediation claim requires the actual supplier-patched artifact and advisory.

Exercise

Download and compare the three library documents

Nexus serves a CycloneDX library inventory, an OpenVEX statement, and an OSV advisory for the selected dependency. Download all three so you can inspect their contents before uploading anything. Success means their package names and exact versions agree with the Commons Lang entry retrieved in 7.1.

CDX_URL="$(oc -n lightwell-repo get configmap lab-lightwell-repo -o jsonpath='{.data.scored_vex_maven_cdx}')"
VEX_URL="$(oc -n lightwell-repo get configmap lab-lightwell-repo -o jsonpath='{.data.scored_vex_maven_vex}')"
OSV_URL="$(oc -n lightwell-repo get configmap lab-lightwell-repo -o jsonpath='{.data.scored_vex_osv}')"
oc -n lightwell-repo get configmap lab-lightwell-repo \
  -o jsonpath='advisory={.data.scored_vex_id}{"\n"}gav={.data.scored_vex_gav}{"\n"}'
curl -fsSL --max-time 60 "$CDX_URL" -o "$EVIDENCE/library.cdx.json"
curl -fsSL --max-time 60 "$VEX_URL" -o "$EVIDENCE/library.openvex.json"
curl -fsSL --max-time 60 "$OSV_URL" -o "$EVIDENCE/library.osv.json"
jq '{id, summary, affected}' "$EVIDENCE/library.osv.json"
jq '.statements[] | {vulnerability, products, status, action_statement}' "$EVIDENCE/library.openvex.json"
jq '{root:.metadata.component, components}' "$EVIDENCE/library.cdx.json"
jq '[.components[] | select(.name == "commons-lang3") |
  {name, version, purl}]' "$EVIDENCE/tpa-app-sbom.json"

Read the fixed event for package org.apache.commons:commons-lang3 in the OSV record. Compare it with the fixed OpenVEX statement’s product URL and the application inventory. The upstream 3.14.0 entry should remain affected; the .rhlw-00001 version is the sample’s fix. If the application contains the upstream version, the report must say it is affected under this sample. Downloading remediation metadata does not change the image.

Store the supported documents in TPA

The library CycloneDX document belongs on /api/v3/sbom; OSV belongs on /api/v3/advisory. This workshop’s TPA does not accept the companion OpenVEX document on either endpoint. Retain it locally as evidence for your interpretation. The library inventory is an additional document, not a replacement for the promoted application’s SBOM.

curl -fkSs --max-time 60 -X POST -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/octet-stream' \
  --data-binary @"$EVIDENCE/library.cdx.json" \
  -o "$EVIDENCE/library-upload.json" -w 'Library SBOM HTTP %{http_code}\n' \
  "${RHTPA_URL%/}/api/v3/sbom"
curl -fkSs --max-time 60 -X POST -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/octet-stream' \
  --data-binary @"$EVIDENCE/library.osv.json" \
  -o "$EVIDENCE/advisory-upload.json" -w 'OSV advisory HTTP %{http_code}\n' \
  "${RHTPA_URL%/}/api/v3/advisory"
jq . "$EVIDENCE/library-upload.json" "$EVIDENCE/advisory-upload.json"

Expect successful HTTP responses and retain the returned identifiers. List stored advisories and find LW-DEMO-0002 in the response. Increment OFFSET by 50 and repeat if it is not on the first page; an empty items list is the end. A rejected upload, expired token, or absent record needs investigation before you claim that TPA stores the advisory.

OFFSET=0
curl -fkSs --max-time 30 -H "Authorization: Bearer $TOKEN" \
  "${RHTPA_URL%/}/api/v3/advisory?limit=50&offset=$OFFSET" \
  -o "$EVIDENCE/tpa-advisories.json"
jq . "$EVIDENCE/tpa-advisories.json"

Retrieve the library SBOM using its returned upload ID. If the response does not show an ID, list /api/v3/sbom as in 7.1 and locate Commons Lang at 3.14.0.rhlw-00001. Do not apply the application digest filter to this library document. Success is a downloaded library root whose GAV matches the Nexus file.

read -r -p 'Library TPA SBOM id: ' LIBRARY_SBOM_ID
LIBRARY_ID_ENCODED="$(printf '%s' "$LIBRARY_SBOM_ID" | jq -sRr @uri)"
curl -fkSs --max-time 30 -H "Authorization: Bearer $TOKEN" \
  "${RHTPA_URL%/}/api/v3/sbom/$LIBRARY_ID_ENCODED/download" \
  -o "$EVIDENCE/library-stored.cdx.json"
jq '{root:.metadata.component, vulnerabilities}' "$EVIDENCE/library-stored.cdx.json"
jq -e -s '.[0].metadata.component.purl == .[1].metadata.component.purl and
  .[1].bomFormat == "CycloneDX"' \
  "$EVIDENCE/library.cdx.json" "$EVIDENCE/library-stored.cdx.json"

You can also open TPA’s advisory and SBOM lists and inspect the identifiers there. Record the observed advisory and library SBOM IDs in your report. Ingestion and the sample’s fixed event support a scoped conclusion; they are not proof of an independent vulnerability assessment by TPA.

Make skipped ACS checks fail in future builds

Open /home/lab-user/lightwell-workspace/spring-boot-lw-poc/.tekton/pipeline.yaml. In the task named acs-image-check, set its fail-on-skipped parameter to the string "true". Preserve the task reference, image parameter, ordering, and other pipeline edits from earlier tracks. A missing token or unavailable CLI must not look like a successful check.

    # Within tasks -> name: acs-image-check -> params:
    - name: fail-on-skipped
      value: "true"

Review, commit, push, and apply the pipeline definition. Success is a fetched remote file and a live Pipeline that both show true on this task. Applying the definition does not start a build.

cd /home/lab-user/lightwell-workspace/spring-boot-lw-poc
BUILD_NS="$(oc -n gitea get configmap lab-gitea -o jsonpath='{.data.student_build_namespace}')"
git diff --check
git diff -- .tekton/pipeline.yaml
git add .tekton/pipeline.yaml
git commit -m "Fail the ACS task when its check is skipped"
git push origin HEAD
git fetch origin "$(git branch --show-current)"
git show FETCH_HEAD:.tekton/pipeline.yaml
oc -n "$BUILD_NS" apply -f .tekton/pipeline.yaml
oc -n "$BUILD_NS" get pipeline

Read the Pipeline name from the manifest and inspect it below. Compare only the acs-image-check task’s parameters; another task’s true value is not evidence for this control.

read -r -p 'Pipeline name from .tekton/pipeline.yaml: ' PIPELINE
oc -n "$BUILD_NS" get pipeline "$PIPELINE" -o json |
  jq '.spec.tasks[] | select(.name == "acs-image-check") | {name, taskRef, params}'
oc -n "$BUILD_NS" get secret rhacs-ci-secrets \
  -o go-template='{{range $key, $value := .data}}{{$key}}{{"\n"}}{{end}}'

The Secret must contain keys rox-api-endpoint and rox-api-token. Do not print their values. Provisioning creates and distributes this Secret; if it is missing, ask the instructor to repair provisioning before running the check.

Check the promoted image without rebuilding it

Run the existing ACS Task directly against the immutable production reference saved in 7.1. This TaskRun evaluates the promoted image against the policies configured in ACS. A standalone TaskRun avoids replacing the image tag or SBOM with a new build. Together, the pipeline configuration and this TaskRun show how future builds enforce the check and how ACS evaluates the promoted image.

Commit fail-on-skipped in the pipeline then run the existing ACS task against the saved production digest and interpret its result together with logs

The cluster resolver runs the acs-image-check Task from the stackrox namespace, just as the pipeline does. Save the TaskRun name to find this run’s status and logs.

PROD_IMAGE="$(cat "$EVIDENCE/promoted-image.txt")"
printf '%s\n' "$PROD_IMAGE" | grep -Eq '@sha256:[0-9a-f]{64}$' || { echo 'Expected immutable image'; exit 1; }
cat > "$EVIDENCE/acs-taskrun.yaml" <<YAML
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: track7-acs-
spec:
  serviceAccountName: pipeline
  taskRef:
    resolver: cluster
    params:
      - name: kind
        value: task
      - name: name
        value: acs-image-check
      - name: namespace
        value: stackrox
  params:
    - name: image
      value: "$PROD_IMAGE"
    - name: fail-on-skipped
      value: "true"
    - name: rox-secret-name
      value: rhacs-ci-secrets
YAML
ACS_RUN="$(oc -n "$BUILD_NS" create -f "$EVIDENCE/acs-taskrun.yaml" -o jsonpath='{.metadata.name}')"
printf '%s\n' "$ACS_RUN" | tee "$EVIDENCE/acs-taskrun-name.txt"
oc -n "$BUILD_NS" get taskrun "$ACS_RUN" -w

Press Ctrl-C once the TaskRun settles; this stops watching without cancelling it. Save the status and logs. If it has no pod yet, inspect its condition and events for resolution or scheduling errors before trying to read logs.

oc -n "$BUILD_NS" get taskrun "$ACS_RUN" -o json > "$EVIDENCE/acs-taskrun.json"
jq '{name:.metadata.name, params:.spec.params,
  conditions:.status.conditions, results:.status.results, pod:.status.podName}' \
  "$EVIDENCE/acs-taskrun.json"
ACS_POD="$(jq -er '.status.podName | select(length > 0)' "$EVIDENCE/acs-taskrun.json")"
oc -n "$BUILD_NS" logs "$ACS_POD" --all-containers=true > "$EVIDENCE/acs.log"
cat "$EVIDENCE/acs.log"

Interpret the result with its logs:

Observation Conclusion and next action

passed, successful TaskRun, completed policy response

ACS evaluated this image against the configured policies and accepted it. This does not establish that every possible vulnerability is absent.

failed, logs contain a completed policy response with violations

ACS evaluated and rejected the image. Record the policy findings; the check ran, but the image did not pass that policy.

failed with authentication, connection, registry, or other execution errors

The check did not produce usable policy evidence. Resolve the error with the instructor and create a fresh TaskRun for the same digest.

skipped, missing result, or pending TaskRun

No completed policy assessment. Inspect conditions and logs; repair the prerequisite and repeat this task. With fail-on-skipped set, a skip must fail the TaskRun.

Write the blast-radius report

Blast radius means the set of artifacts affected by a finding. This exercise inspects one promoted image; it does not search every application in the organization. Write ~/lightwell-compliance-evidence/blast-radius.txt in your editor using the evidence you just inspected. Include:

  • The promoted image reference, production commit, and TPA application SBOM ID.

  • Sample advisory ID LW-DEMO-0002, the observed Commons Lang GAV, and the matching OpenVEX product URL.

  • The sample’s affected upstream version and fixed Lightwell version, with your observed status and reasoning. Say that remediation is via the exact Lightwell pin only when the inventory and advisory agree.

  • The stored OSV and library SBOM identifiers, and the fact that OpenVEX was inspected locally.

  • The ACS TaskRun name, checked image, result, and policy finding or operational error, including any unresolved issue.

  • The scope: one Java image and a workshop sample; OS-layer CSAF and Track 6’s signature admission are separate evidence.

You author a human-readable explanation rather than copying tokens into a cluster ConfigMap. A useful sentence links a concrete observation to its conclusion: “The retrieved application inventory contains version …; the sample’s fixed event and OpenVEX statement identify that same version, so …”. Fill the blanks from your output.

Review

Read the report beside the saved JSON and ACS logs. Check that every artifact identity agrees and that the report distinguishes a policy rejection from an execution error. A failed result alone does not prove a policy evaluation occurred. If the ACS attempt is unresolved, retain that limitation and complete the repair before claiming the exercise is finished.

cat "$EVIDENCE/blast-radius.txt"
jq '.metadata.component, [.components[] | select(.name == "commons-lang3")]' "$EVIDENCE/tpa-app-sbom.json"
jq '.id, .affected' "$EVIDENCE/library.osv.json"
jq '.status.results, .status.conditions' "$EVIDENCE/acs-taskrun.json"
oc -n trusted-profile-analyzer get configmap rhtpa-ingestion-info \
  -o jsonpath='live_csaf_gate={.data.live_csaf_gate}{"\n"}'
unset TOKEN

Expect live_csaf_gate=false. Review the fetched and live pipeline parameters from the exercise as well. There is no validation Job or report token to submit. Completion means you can trace the report back to the stored inventory, advisory evidence, and a completed ACS policy assessment, while accurately recording any policy rejection.

Python uses an exact +rhlw.* package version; Artifactory can serve the same Maven documents beside a GAV. These are equivalent delivery patterns, not additional exercises. During a Clearinghouse embargo, advisory distribution may be restricted to members; this workshop uses disclosed sample metadata.

Key takeaways

  • Remediation claims require the exact installed version and matching advisory evidence.

  • TPA inventory, library advisory interpretation, ACS policy results, and signature admission answer different questions.

  • A useful compliance report states its evidence, scope, and unresolved findings.