7.2 VEX blast radius + ACS

Overview

You ingest Lightwell GAV-bound CycloneDX and OSV for the Track 2 pin into Trusted Profile Analyzer. Then you write a blast-radius report. That advisory is remediated via the Lightwell pin, not still-open upstream. The ACS task acs-image-check must not be skipped. Hummingbird and Red Hat CSAF are an OS-layer callout. They are not this Check. The live CSAF importer stays off.

ACS is not the admission gate. That was 6.1.

Why it matters

Scanners stay red unless the system of record knows the library CVE is remediated because you pinned Lightwell. ACS must actually run in the pipeline. Do not quote RHEL CSAF for a library CVE.

You download from Nexus, ingest into TPA (/api/v3/sbom and /api/v3/advisory), and record blast-radius tokens (via-lightwell-pin) so scanners and TPA recognize the pin. Setting fail-on-skipped to true proves the ACS control is not a stub.

Lightwell Clearinghouse Premier member advisories ingest the same way. The report would still say via-Lightwell-pin (member version), never via-upstream and never via-Hummingbird-CSAF. Public OSV and VEX on this lab are the post-disclosure Network state. During a Premier embargo, that advisory would stay member-private until disclosure. ACS can still scan the image.

What does it solve

  • Scanner noise with no GAV-bound VEX

  • ACS left out or skipped

  • Mixing OS-layer CSAF with library VEX

Layer map (library VEX vs OS CSAF)

Library Lightwell GAV VEX versus OS-layer Hummingbird CSAF

Do not quote RHEL or Hummingbird CSAF for a library CVE. The library layer is the .rhlw-* GAV you pinned in 2.2.

End-state trust chain: Hummingbird digest

Discover the scored VEX (not the spring-core sample)

oc -n lightwell-repo get configmap demo-userinfo-lightwell-repo \
  -o jsonpath='id={.data.scored_vex_id}{"\n"}gav={.data.scored_vex_gav}{"\n"}cdx={.data.scored_vex_maven_cdx}{"\n"}vex={.data.scored_vex_maven_vex}{"\n"}osv={.data.scored_vex_osv}{"\n"}csaf={.data.live_csaf_gate}{"\n"}'
oc -n trusted-profile-analyzer get configmap rhtpa-ingestion-info \
  -o jsonpath='{.data.upload_hint}{"\n"}{.data.os_layer_callout}{"\n"}'
  • Scored: LW-DEMO-0002 / org.apache.commons:commons-lang3 / 3.14.0.rhlw-00001

Worked example (not the Check)

Spring-core / LW-DEMO-0001 and “fixed upstream.” If the blast-radius ConfigMap uses these tokens, the Check fails.

# Worked example ONLY — different advisory, different GAV, wrong remediation.
vulnerability_id: LW-DEMO-0001
gav: org.springframework:spring-core:5.3.18.rhlw-00003
status: fixed
remediation: via-upstream

Your change: download, ingest, report, ACS on

  1. Download Maven classifier cdx from the userinfo URL (Nexus Remediated) and POST it to TPA /api/v3/sbom. The companion -vex.json classifier is OpenVEX — TPA does not accept OpenVEX as an SBOM or as /api/v3/advisory (that path is CSAF, CVE, or OSV only). Ingest the scored OSV document instead (scored_vex_osv / LW-DEMO-0002.json). Do not scrape CSAF. Do not POST OpenVEX to /api/v3/sbom.

  2. Upload the CycloneDX file to /api/v3/sbom and the OSV file to /api/v3/advisory (same SoR as 7.1). Provision does not pre-ingest them. Keep live_csaf_gate=false.

CDX_URL="$(oc -n lightwell-repo get configmap demo-userinfo-lightwell-repo -o jsonpath='{.data.scored_vex_maven_cdx}')"
OSV_URL="$(oc -n lightwell-repo get configmap demo-userinfo-lightwell-repo -o jsonpath='{.data.scored_vex_osv}')"
curl -fsSL -o ~/commons-lang3-cdx.json "${CDX_URL}"
curl -fsSL -o ~/LW-DEMO-0002.json "${OSV_URL}"
export OIDC_ISSUER="$(oc -n sso get configmap demo-userinfo-keycloak -o jsonpath='{.data.oidc_issuer}')"
export RHTPA_URL="$(oc -n trusted-profile-analyzer get configmap rhtpa-ingestion-info -o jsonpath='{.data.server_url}')"
export TPA_USER="$(oc -n sso get configmap demo-userinfo-keycloak -o jsonpath='{.data.workshop_username}')"
: "${TPA_PASS:=$(oc -n sso get configmap demo-userinfo-keycloak -o jsonpath='{.data.workshop_password}')}"
export CLI_SECRET="$(oc -n trusted-profile-analyzer get secret tpa-realm-cli-clients -o jsonpath='{.data.cli}' | base64 -d)"
TOKEN="$(curl -sk -X POST "${OIDC_ISSUER}/protocol/openid-connect/token" \
  -d grant_type=password -d client_id=cli -d client_secret="${CLI_SECRET}" \
  -d username="${TPA_USER}" -d password="${TPA_PASS}" -d scope=openid \
  | jq -r .access_token)"
curl -sk -X POST -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @"${HOME}/commons-lang3-cdx.json" \
  -w '\nCDX HTTP %{http_code}\n' \
  "${RHTPA_URL%/}/api/v3/sbom"
curl -sk -X POST -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @"${HOME}/LW-DEMO-0002.json" \
  -w '\nOSV HTTP %{http_code}\n' \
  "${RHTPA_URL%/}/api/v3/advisory"
TPA UI after ingesting GAV-bound VEX for LW-DEMO-0002
  1. Write ConfigMap stub-18-blast-radius (extract, fill, write back). Placeholders fail. Allowed tokens (the Check grades these):

vulnerability_id: REPLACE_ME_VEX_ID
gav: REPLACE_ME_GAV
status: REPLACE_ME_STATUS
remediation: REPLACE_ME_VIA

Fill with LW-DEMO-0002, the remediated GAV (include 3.14.0.rhlw-00001), status fixed (or not_affected if the VEX statement uses that), and remediation via-lightwell-pin. Do not claim the upstream 3.14.0 is fixed. Do not use LW-DEMO-0001.

Extract the incomplete seed, then write it back after you fill the keys
oc -n lightwell-repo get configmap stub-18-blast-radius \
  -o jsonpath='{.data.blast-radius\.txt}' > ~/track-7-2-blast-radius.txt
# edit ~/track-7-2-blast-radius.txt, then:
oc -n lightwell-repo create configmap stub-18-blast-radius \
  --from-file=blast-radius.txt=$HOME/track-7-2-blast-radius.txt \
  --dry-run=client -o yaml | oc apply -f -
  1. ACS: confirm Job rhacs-ci-token-mint in stackrox is Complete. That Job mints Secret rhacs-ci-secrets and copies it into your build namespace (student_build_namespace) so acs-image-check can mount it. Provision also registers the in-cluster registry with Central — do not add an image integration by hand. On the learner Pipeline, pass fail-on-skipped: "true" on acs-image-check (seeded default is soft-skip). Re-run if the last TaskRun was skipped. Expect passed or failed — both prove the control is on. Do not screenshot Central as this Check.

Check: report tokens + ACS not skipped

BUILD_NS="$(oc -n gitea get configmap demo-userinfo-gitea -o jsonpath='{.data.student_build_namespace}')"
grep -E 'REPLACE_ME' ~/track-7-2-blast-radius.txt && echo 'STILL HAS PLACEHOLDERS' || echo 'placeholders gone'
grep -E 'LW-DEMO-0002|3.14.0.rhlw-00001|via-lightwell-pin' ~/track-7-2-blast-radius.txt
oc -n lightwell-repo get configmap stub-18-blast-radius \
  -o jsonpath='{.data.blast-radius\.txt}' | grep -E 'LW-DEMO-0002|3.14.0.rhlw-00001|via-lightwell-pin'
oc -n stackrox get job rhacs-ci-token-mint
oc -n "${BUILD_NS}" get secret rhacs-ci-secrets
oc -n "${BUILD_NS}" get tr -l tekton.dev/pipelineTask=acs-image-check

Pass when: Nexus GAV files were ingested; the report has the scored id + GAV + via-Lightwell token and no REPLACE_ME; acs-image-check is not skipped; CSAF importer is still off.

Fill the report

The Job also grades ConfigMap report-18-vex-acs key vex_layer. Set it to gav-bound. Empty or REPLACE_ME fails even if cluster state is correct. Do not copy validate-docs.

oc -n lw-poc-validate edit configmap report-18-vex-acs

The scored Check is Job validate-18-vex-acs in lw-poc-validate. Direct nav URLs still work (honor system). Unlimited retries. There is no Solve.

Run the Validate Job
oc -n lw-poc-validate delete job validate-18-vex-acs --ignore-not-found
TPL='job-18.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-18-vex-acs

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.

Callouts (not Checks)

  • Hummingbird / RHEL CSAF = OS layer. Do not score it.

  • PyPI VEX/SPDX is the same “metadata travels with the pin” idea (+rhlw.* on requirements.txt). This Check is the Maven GAV from Track 2.

  • Artifactory can host the same GAV-bound CDX/VEX classifiers beside the Maven GAV (local/generic or the remote cache). It is not installed here. This Check downloads from Nexus Remediated.

Key takeaways

  • Advisory metadata travels with the .rhlw-* GAV you pin. Lightwell Network is post-disclosure. Premier member versions use the same ingest and stay embargoed until disclosure.

  • Quoting OS-layer CSAF for a library CVE is the wrong layer.

  • ACS on is a pipeline control. It is not the 6.1 admission gate.

cd ~/ocp5-rhacs-showroom
bash setup/lab-cleanup.sh --module tssc-18