Skip to content

feat: integrate Red Hat Trusted Software Supply Chain (TSSF)#206

Draft
vtz wants to merge 3 commits into
centos-automotive-suite:mainfrom
vtz:feat/tssf-integration
Draft

feat: integrate Red Hat Trusted Software Supply Chain (TSSF)#206
vtz wants to merge 3 commits into
centos-automotive-suite:mainfrom
vtz:feat/tssf-integration

Conversation

@vtz

@vtz vtz commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add ArtifactRef to ImageBuild status and ComplianceConfig to OperatorConfig spec for supply-chain traceability
  • Emit IMAGE_URL / IMAGE_DIGEST pipeline results from push-artifact-registry task (Tekton Chains contract)
  • Add sbom-generate Tekton Task (Syft) that attaches SBOMs as OCI referrers when compliance is enabled
  • Wire compliance config through BuildConfig so both OperatorConfig and ImageBuild reconcilers honour it

Test plan

  • Verify make manifests generate build succeeds
  • Unit tests pass (go test ./api/... ./internal/common/tasks/... ./internal/controller/imagebuild/...)
  • Deploy with compliance.enabled: false (default) -- existing pipelines unchanged
  • Deploy with compliance.enabled: true -- pipeline gains sbom-generate task, SBOM_URI result
  • End-to-end: ImageBuild with OCI push populates status.artifact.registry and status.artifact.digest
  • End-to-end with Tekton Chains: verify signing and SLSA provenance attach to the artifact

Closes #204

Made with Cursor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added supply-chain traceability metadata to build status, including artifact registry, digest, and SBOM references.
    • Introduced SBOM generation and attachment capability for build artifacts.
    • Added compliance configuration options to enable SBOM formatting and signing endpoints.
  • Documentation

    • Added architecture decision record documenting supply-chain security integration.

Enable supply-chain compliance for ImageBuild pipelines by adding SBOM
generation (Syft), Tekton Chains result contract (IMAGE_URL/IMAGE_DIGEST),
and traceability metadata in build status.

Closes centos-automotive-suite#204

Made-with: Cursor
@vtz

vtz commented Apr 11, 2026

Copy link
Copy Markdown
Contributor Author

Architecture context: ADR-001: Integrate Red Hat Trusted Software Supply Chain

@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fffb75fa-72e3-460f-8839-3f1283254b72

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@bennyz bennyz marked this pull request as ready for review April 12, 2026 07:17
@bennyz bennyz marked this pull request as draft April 12, 2026 07:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
docs/adr/001-tssf-integration.md (1)

124-134: Minor: ADR ComplianceConfig differs slightly from implementation.

The ADR shows TrustedArtifactSignerURL in the ComplianceConfig struct, but the actual implementation in api/v1alpha1/operatorconfig_types.go has separate RekorURL and FulcioURL fields instead. Additionally, the implementation includes a SyftImage field not shown here.

This is acceptable since ADRs capture intent at decision time and implementations may evolve, but consider updating the ADR to match the final implementation for documentation accuracy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/adr/001-tssf-integration.md` around lines 124 - 134, The ADR's
ComplianceConfig struct is out of sync with the implementation: replace the
single TrustedArtifactSignerURL field with the separate RekorURL and FulcioURL
fields and add the missing SyftImage field so the ADR reflects the actual
implementation; update the struct declaration for ComplianceConfig and its JSON
tags to match the identifiers used in the code (ComplianceConfig, RekorURL,
FulcioURL, SyftImage, SBOMFormat, SBOMTaskBundle, ECPolicyRef) so the ADR and
operatorconfig_types.go stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/v1alpha1/imagebuild_types.go`:
- Around line 181-205: The doc comments for ArtifactRef incorrectly state that
registry/digest are populated only when "compliance is enabled"; update the
comments for ArtifactRef and the other occurrence referencing the same behavior
so they match controller behavior: state that status.artifact.registry and
status.artifact.digest are set for any successful registry push, while SBOMRef,
SignatureRef, and ProvenanceRef are populated when their respective features
(SBOM, signing/Sigstore, provenance/Tekton Chains) are produced; reference
ArtifactRef and the fields Registry, Digest, SBOMRef, SignatureRef,
ProvenanceRef and status.artifact to locate the comments and change the wording
accordingly.

In `@api/v1alpha1/zz_generated.deepcopy.go`:
- Around line 55-68: This PR accidentally includes generated deepcopy code
(e.g., the ArtifactRef DeepCopyInto and DeepCopy functions) and generated CRD
manifests; drop those hunks from the change set by reverting the generated
zz_generated.deepcopy.go edits (restore the file to the upstream/generated state
or remove it from the commit) and remove any config/crd/bases/*.yaml CRD
manifests from the PR; ensure the generated outputs remain ignored (keep them
out of source control) and only commit changes to the source API types (then run
the generator separately if you need updated generated output).

In `@internal/common/tasks/scripts/push_artifact.sh`:
- Around line 338-341: The script extracts the image digest into pushed_digest
from oras output and writes it to results.IMAGE_DIGEST.path but doesn’t validate
it; if empty the task incorrectly reports success. After computing pushed_digest
(the grep/awk pipeline that sets pushed_digest) add a validation check that it
is non-empty and matches the expected sha256:hex pattern, and fail/exit with a
non-zero status and an error log if validation fails; apply the same validation
logic to the other push branch that writes to "$(results.IMAGE_DIGEST.path)"
(the second push path around the other extract/write block) so both push flows
enforce the digest presence before writing IMAGE_DIGEST and IMAGE_URL.

In `@internal/common/tasks/scripts/sbom_generate.sh`:
- Around line 54-56: The SBOM result currently writes only image_url to
result_path; change sbom_generate.sh to capture the actual SBOM artifact
reference produced by the attach operation and write that full OCI ref to
SBOM_URI: run the oras attach command (or reuse the existing variable that
captures its stdout), parse its output to extract the SBOM digest (as done in
push_artifact.sh), then set sbom_ref to the combined reference (e.g.,
image_url@<digest>) and write sbom_ref to result_path instead of just image_url;
look for symbols sbom_ref, image_url, result_path and the oras attach invocation
in sbom_generate.sh to implement this parsing and assignment.

In `@internal/common/tasks/tasks.go`:
- Around line 1475-1484: The docker-config volume uses an OCI image ref as
SecretName ("$(params.IMAGE_URL)"), which is invalid; add a parameter named
secret-ref (like in GeneratePushArtifactRegistryTask) and change the Volume's
SecretName to "$(params.secret-ref)"; also update the corresponding PipelineTask
binding that creates this task to pass the secret-ref parameter (replacing the
IMAGE_URL usage) so the task receives a valid Kubernetes secret name for the
docker-config volume.

In `@internal/controller/operatorconfig/controller.go`:
- Around line 668-670: The code only appends tasks.GenerateSBOMTask when
buildConfig.ComplianceEnabled is true, but provides no removal when it flips to
false; update the reconcile/cleanup path to prune the sbom-generate Tekton Task
so cluster state doesn't drift. Add logic either in the same branch (an else
that schedules a deletion/prune for the sbom-generate Task) or modify
cleanupOSBuilds() to include sbom-generate removal, referencing the existing
symbols tasks.GenerateSBOMTask, buildConfig.ComplianceEnabled, tektonTasks and
cleanupOSBuilds() so the controller explicitly deletes the sbom-generate Task
when compliance is disabled.
- Around line 653-658: Add the missing compliance fields to the build pipeline
by (1) adding rekorURL, fulcioURL, and ecPolicyRef to the BuildConfig struct;
(2) wiring config.Spec.Compliance.GetRekorURL(), GetFulcioURL(), and
GetECPolicyRef() into buildConfig in both operatorconfig/controller.go and
imagebuild/controller.go (alongside ComplianceEnabled, SyftImage, SBOMFormat);
and (3) update the task generation code that produces SBOM/compliance tasks (the
routines that create SBOM tasks and the Enterprise Contract gate—e.g., the
generateTasks/createSBOMTask/createECGate call sites) to read
BuildConfig.rekorURL, BuildConfig.fulcioURL and BuildConfig.ecPolicyRef and pass
them into Tekton Chains / EC gate task params so those operator API fields
actually affect execution.

---

Nitpick comments:
In `@docs/adr/001-tssf-integration.md`:
- Around line 124-134: The ADR's ComplianceConfig struct is out of sync with the
implementation: replace the single TrustedArtifactSignerURL field with the
separate RekorURL and FulcioURL fields and add the missing SyftImage field so
the ADR reflects the actual implementation; update the struct declaration for
ComplianceConfig and its JSON tags to match the identifiers used in the code
(ComplianceConfig, RekorURL, FulcioURL, SyftImage, SBOMFormat, SBOMTaskBundle,
ECPolicyRef) so the ADR and operatorconfig_types.go stay consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a9f7dbea-de5f-41b1-ba90-244b6619d6c9

📥 Commits

Reviewing files that changed from the base of the PR and between 2b0a115 and 3751c55.

⛔ Files ignored due to path filters (2)
  • config/crd/bases/automotive.sdv.cloud.redhat.com_imagebuilds.yaml is excluded by !config/crd/bases/**
  • config/crd/bases/automotive.sdv.cloud.redhat.com_operatorconfigs.yaml is excluded by !config/crd/bases/**
📒 Files selected for processing (11)
  • api/v1alpha1/imagebuild_types.go
  • api/v1alpha1/operatorconfig_types.go
  • api/v1alpha1/zz_generated.deepcopy.go
  • config/samples/automotive_v1_operatorconfig.yaml
  • docs/adr/001-tssf-integration.md
  • internal/common/tasks/scripts.go
  • internal/common/tasks/scripts/push_artifact.sh
  • internal/common/tasks/scripts/sbom_generate.sh
  • internal/common/tasks/tasks.go
  • internal/controller/imagebuild/controller.go
  • internal/controller/operatorconfig/controller.go

Comment on lines +181 to +205
// ArtifactRef captures the supply-chain traceability metadata for a build artifact.
// Populated from PipelineRun results when compliance is enabled.
type ArtifactRef struct {
// Registry is the OCI registry URL where the artifact was pushed (IMAGE_URL)
// +optional
Registry string `json:"registry,omitempty"`

// Digest is the content-addressable digest of the pushed artifact (sha256:...)
// +optional
Digest string `json:"digest,omitempty"`

// SBOMRef is the OCI reference to the attached SBOM artifact
// +optional
SBOMRef string `json:"sbomRef,omitempty"`

// SignatureRef is the OCI reference to the cosign/Sigstore signature
// Populated by Tekton Chains when signing is configured
// +optional
SignatureRef string `json:"signatureRef,omitempty"`

// ProvenanceRef is the OCI reference to the SLSA provenance attestation
// Populated by Tekton Chains when provenance is configured
// +optional
ProvenanceRef string `json:"provenanceRef,omitempty"`
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update the API docs to match the controller behavior.

These comments say artifact metadata is populated only when compliance is enabled, but the controller fills status.artifact.registry and status.artifact.digest for any successful registry push. That will mislead users of the new status field.

Also applies to: 257-260

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1alpha1/imagebuild_types.go` around lines 181 - 205, The doc comments
for ArtifactRef incorrectly state that registry/digest are populated only when
"compliance is enabled"; update the comments for ArtifactRef and the other
occurrence referencing the same behavior so they match controller behavior:
state that status.artifact.registry and status.artifact.digest are set for any
successful registry push, while SBOMRef, SignatureRef, and ProvenanceRef are
populated when their respective features (SBOM, signing/Sigstore,
provenance/Tekton Chains) are produced; reference ArtifactRef and the fields
Registry, Digest, SBOMRef, SignatureRef, ProvenanceRef and status.artifact to
locate the comments and change the wording accordingly.

Comment on lines +55 to +68
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArtifactRef) DeepCopyInto(out *ArtifactRef) {
*out = *in
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArtifactRef.
func (in *ArtifactRef) DeepCopy() *ArtifactRef {
if in == nil {
return nil
}
out := new(ArtifactRef)
in.DeepCopyInto(out)
return out
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Drop generated deepcopy hunks from the PR.

This file is generated output, not stable source. Keeping these hunks in the PR adds churn and diverges from the repository’s normal workflow for API generation.

Based on learnings: In centos-automotive-suite/automotive-dev-operator, the files api/v1alpha1/zz_generated.deepcopy.go and all config/crd/bases/*.yaml CRD manifests are explicitly listed in .gitignore and are NOT committed to the repository. PRs should NOT include these generated files.

Also applies to: 366-379, 706-710, 1204-1208

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1alpha1/zz_generated.deepcopy.go` around lines 55 - 68, This PR
accidentally includes generated deepcopy code (e.g., the ArtifactRef
DeepCopyInto and DeepCopy functions) and generated CRD manifests; drop those
hunks from the change set by reverting the generated zz_generated.deepcopy.go
edits (restore the file to the upstream/generated state or remove it from the
commit) and remove any config/crd/bases/*.yaml CRD manifests from the PR; ensure
the generated outputs remain ignored (keep them out of source control) and only
commit changes to the source API types (then run the generator separately if you
need updated generated output).

Comment on lines +338 to +341
# Extract digest from oras output (format: "Digest: sha256:abc123...")
pushed_digest=$(echo "$push_output" | grep -i '^Digest:' | awk '{print $2}' | head -1)
printf '%s' "${repo_url}" > "$(results.IMAGE_URL.path)"
printf '%s' "${pushed_digest}" > "$(results.IMAGE_DIGEST.path)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate the parsed digest before publishing Tekton results.

If oras push succeeds but its output format changes or no Digest: line is emitted, both branches write an empty IMAGE_DIGEST and still continue as if the push succeeded. That breaks the new result contract for the SBOM task and status.artifact.digest.

Suggested fix
   pushed_digest=$(echo "$push_output" | grep -i '^Digest:' | awk '{print $2}' | head -1)
+  if [ -z "$pushed_digest" ]; then
+    echo "ERROR: Failed to parse pushed digest from oras output" >&2
+    exit 1
+  fi
   printf '%s' "${repo_url}" > "$(results.IMAGE_URL.path)"
   printf '%s' "${pushed_digest}" > "$(results.IMAGE_DIGEST.path)"

Apply the same check in both push paths.

Also applies to: 407-409

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/common/tasks/scripts/push_artifact.sh` around lines 338 - 341, The
script extracts the image digest into pushed_digest from oras output and writes
it to results.IMAGE_DIGEST.path but doesn’t validate it; if empty the task
incorrectly reports success. After computing pushed_digest (the grep/awk
pipeline that sets pushed_digest) add a validation check that it is non-empty
and matches the expected sha256:hex pattern, and fail/exit with a non-zero
status and an error log if validation fails; apply the same validation logic to
the other push branch that writes to "$(results.IMAGE_DIGEST.path)" (the second
push path around the other extract/write block) so both push flows enforce the
digest presence before writing IMAGE_DIGEST and IMAGE_URL.

Comment on lines +54 to +56
# Write the SBOM reference as a result (image_url with SBOM digest)
sbom_ref="${image_url}"
printf '%s' "${sbom_ref}" > "${result_path}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check oras attach output format to confirm how to parse the SBOM digest
oras version 2>/dev/null || echo "oras not available in sandbox"
# Check if there's documentation or examples of oras attach output parsing in the repo
rg -n "oras attach" --type sh

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 219


🏁 Script executed:

cat -n internal/common/tasks/scripts/sbom_generate.sh | sed -n '40,65p'

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 940


🏁 Script executed:

# Check if there are any ADR references or documentation about SBOM artifact references
rg -i "adr.*001|SBOM.*ref|artifact.*digest" --type sh --type md -B 2 -A 2

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 3348


🏁 Script executed:

# Search for documentation about how the result_path or sbom_ref is used
rg -n "result_path|sbom_ref" internal/common/tasks/scripts/sbom_generate.sh -B 2 -A 2

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 561


🏁 Script executed:

# Search for any documentation or examples of oras output parsing
rg -i "oras.*output|oras.*digest|oras.*sha256" --type sh --type md

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 406


🏁 Script executed:

# Check if there are other places in codebase that use oras and how they handle output
rg -n "oras" --type sh -A 3 -B 1

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 10869


🌐 Web query:

oras attach output format digest sha256

💡 Result:

To output the digest (sha256) of the attached referrer manifest from the oras attach command, use the --format flag with Go template syntax. Example command: oras attach --artifact-type doc/example localhost:5000/hello:v1 hi.txt --format go-template --template "{{.digest}}" This prints only the digest string, e.g., sha256:0afd0f0c35f98dcb607de0051be7ebefd942eef1e3a6d26eefd1b2d80f2affbe. For JSON output including the digest: oras attach --artifact-type doc/example localhost:5000/hello:v1 hi.txt --format json Example JSON: { "reference": "localhost:5000/hello@sha256:0afd0f0c35f98dcb607de0051be7ebefd942eef1e3a6d26eefd1b2d80f2affbe", "mediaType": "application/vnd.oci.image.manifest.v1+json", "digest": "sha256:0afd0f0c35f98dcb607de0051be7ebefd942eef1e3a6d26eefd1b2d80f2affbe", "size": 923, "annotations": { ... }, "artifactType": "doc/example" } The --format option supports text (default), json, and go-template. The digest field is the sha256 digest of the newly created referrer manifest. This is an experimental feature documented in official ORAS CLI docs (version 1.3).

Citations:


🏁 Script executed:

# Check the exact format of oras attach output by examining push_artifact.sh more closely
sed -n '329,345p' internal/common/tasks/scripts/push_artifact.sh

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 730


SBOM_URI result does not contain the actual SBOM artifact reference—violates ADR-001 requirement.

The sbom_ref is set to only image_url, but ADR-001 specifies SBOM_URI must be an "OCI reference to attached SBOM" (see ArtifactRef.SBOMRef). When oras attach creates the referrer artifact, it outputs the SBOM artifact's digest, which must be captured and included in the result for full traceability.

The codebase already has a pattern for this in push_artifact.sh (line 339). Follow the same approach:

♻️ Proposed fix to capture actual SBOM digest
 # Use ORAS to attach the SBOM as a referrer (OCI 1.1 referrers API)
-DOCKER_CONFIG="${DOCKER_CONFIG:-}" oras attach \
+attach_output=$(DOCKER_CONFIG="${DOCKER_CONFIG:-}" oras attach \
   --artifact-type "${sbom_media_type}" \
   "${image_ref}" \
-  "${sbom_file}:${sbom_media_type}" 2>&1 || {
+  "${sbom_file}:${sbom_media_type}" 2>&1) || {
   echo "ERROR: Failed to attach SBOM to artifact" >&2
   exit 1
 }
 
+# Extract SBOM digest from oras output (format: "Digest: sha256:abc123...")
+sbom_digest=$(echo "$attach_output" | grep -i '^Digest:' | awk '{print $2}' | head -1)
+
 # Write the SBOM reference as a result (image_url with SBOM digest)
-sbom_ref="${image_url}"
+sbom_ref="${image_url}@${sbom_digest:-unknown}"
 printf '%s' "${sbom_ref}" > "${result_path}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/common/tasks/scripts/sbom_generate.sh` around lines 54 - 56, The
SBOM result currently writes only image_url to result_path; change
sbom_generate.sh to capture the actual SBOM artifact reference produced by the
attach operation and write that full OCI ref to SBOM_URI: run the oras attach
command (or reuse the existing variable that captures its stdout), parse its
output to extract the SBOM digest (as done in push_artifact.sh), then set
sbom_ref to the combined reference (e.g., image_url@<digest>) and write sbom_ref
to result_path instead of just image_url; look for symbols sbom_ref, image_url,
result_path and the oras attach invocation in sbom_generate.sh to implement this
parsing and assignment.

Comment on lines +1475 to +1484
Volumes: []corev1.Volume{
{
Name: "docker-config",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "$(params.IMAGE_URL)",
Optional: ptr.To(true),
},
},
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Incorrect secret name for docker-config volume.

The SecretName is set to $(params.IMAGE_URL), which will be an OCI image reference (e.g., quay.io/org/repo:tag), not a valid Kubernetes secret name. This will cause the task to fail at runtime when trying to mount the volume.

Compare with GeneratePushArtifactRegistryTask (lines 269-273) which correctly uses $(params.secret-ref) as the secret name.

🐛 Proposed fix: Add secret-ref parameter and use it for docker-config
 			Params: []tektonv1.ParamSpec{
 				{
 					Name:        "IMAGE_URL",
 					Type:        tektonv1.ParamTypeString,
 					Description: "OCI reference to the artifact to scan",
 				},
 				{
 					Name:        "IMAGE_DIGEST",
 					Type:        tektonv1.ParamTypeString,
 					Description: "Digest of the artifact to scan (sha256:...)",
 				},
 				{
 					Name:        "sbom-format",
 					Type:        tektonv1.ParamTypeString,
 					Description: "SBOM output format (spdx-json or cyclonedx-json)",
 					Default: &tektonv1.ParamValue{
 						Type:      tektonv1.ParamTypeString,
 						StringVal: automotivev1alpha1.DefaultSBOMFormat,
 					},
 				},
+				{
+					Name:        "secret-ref",
+					Type:        tektonv1.ParamTypeString,
+					Description: "Name of the secret containing registry credentials",
+					Default: &tektonv1.ParamValue{
+						Type:      tektonv1.ParamTypeString,
+						StringVal: "",
+					},
+				},
 			},

And update the volume:

 			Volumes: []corev1.Volume{
 				{
 					Name: "docker-config",
 					VolumeSource: corev1.VolumeSource{
 						Secret: &corev1.SecretVolumeSource{
-							SecretName: "$(params.IMAGE_URL)",
+							SecretName: "$(params.secret-ref)",
 							Optional:   ptr.To(true),
 						},
 					},
 				},
 			},

Also update the pipeline task binding (lines 1348-1352) to pass the secret-ref:

 			Params: []tektonv1.Param{
 				{Name: "IMAGE_URL", Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "$(tasks.push-disk-artifact.results.IMAGE_URL)"}},
 				{Name: "IMAGE_DIGEST", Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "$(tasks.push-disk-artifact.results.IMAGE_DIGEST)"}},
 				{Name: "sbom-format", Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "$(params.sbom-format)"}},
+				{Name: "secret-ref", Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "$(params.secret-ref)"}},
 			},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/common/tasks/tasks.go` around lines 1475 - 1484, The docker-config
volume uses an OCI image ref as SecretName ("$(params.IMAGE_URL)"), which is
invalid; add a parameter named secret-ref (like in
GeneratePushArtifactRegistryTask) and change the Volume's SecretName to
"$(params.secret-ref)"; also update the corresponding PipelineTask binding that
creates this task to pass the secret-ref parameter (replacing the IMAGE_URL
usage) so the task receives a valid Kubernetes secret name for the docker-config
volume.

Comment on lines +653 to +658
// Wire compliance configuration into build config
if config.Spec.Compliance != nil && config.Spec.Compliance.Enabled {
buildConfig.ComplianceEnabled = true
buildConfig.SyftImage = config.Spec.Compliance.GetSyftImage()
buildConfig.SBOMFormat = config.Spec.Compliance.GetSBOMFormat()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Usages of compliance URL/policy fields:"
rg -n --type=go '\b(RekorURL|FulcioURL|ECPolicyRef)\b'

echo
echo "Usages of compliance settings propagated into build/task generation:"
rg -n --type=go '\b(ComplianceEnabled|SBOMFormat|SyftImage|RekorURL|FulcioURL|ECPolicyRef)\b'

Repository: centos-automotive-suite/automotive-dev-operator

Length of output: 3397


rekorURL, fulcioURL, and ecPolicyRef are defined but unused configuration fields.

These fields are exposed in the OperatorConfig API (api/v1alpha1/operatorconfig_types.go:457-467) but never read or passed to task generation. Only Enabled, SyftImage, and SBOMFormat are wired into BuildConfig and consumed by SBOM task generation. The URL fields (intended for Tekton Chains configuration per their comments) and ECPolicyRef (for Enterprise Contract gate enforcement) have no effect when set by users.

Add these fields to BuildConfig, propagate them in both compliance wiring locations (operatorconfig/controller.go and imagebuild/controller.go), and ensure task generation code consumes them appropriately.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/controller/operatorconfig/controller.go` around lines 653 - 658, Add
the missing compliance fields to the build pipeline by (1) adding rekorURL,
fulcioURL, and ecPolicyRef to the BuildConfig struct; (2) wiring
config.Spec.Compliance.GetRekorURL(), GetFulcioURL(), and GetECPolicyRef() into
buildConfig in both operatorconfig/controller.go and imagebuild/controller.go
(alongside ComplianceEnabled, SyftImage, SBOMFormat); and (3) update the task
generation code that produces SBOM/compliance tasks (the routines that create
SBOM tasks and the Enterprise Contract gate—e.g., the
generateTasks/createSBOMTask/createECGate call sites) to read
BuildConfig.rekorURL, BuildConfig.fulcioURL and BuildConfig.ecPolicyRef and pass
them into Tekton Chains / EC gate task params so those operator API fields
actually affect execution.

Comment on lines +668 to +670
if buildConfig.ComplianceEnabled {
tektonTasks = append(tektonTasks, tasks.GenerateSBOMTask(config.Namespace, buildConfig))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prune sbom-generate when compliance is disabled.

Once this task has been created, turning spec.compliance.enabled back to false stops reconciling it but never deletes it. cleanupOSBuilds() also omits sbom-generate, so managed cluster state drifts after disable/cleanup.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/controller/operatorconfig/controller.go` around lines 668 - 670, The
code only appends tasks.GenerateSBOMTask when buildConfig.ComplianceEnabled is
true, but provides no removal when it flips to false; update the
reconcile/cleanup path to prune the sbom-generate Tekton Task so cluster state
doesn't drift. Add logic either in the same branch (an else that schedules a
deletion/prune for the sbom-generate Task) or modify cleanupOSBuilds() to
include sbom-generate removal, referencing the existing symbols
tasks.GenerateSBOMTask, buildConfig.ComplianceEnabled, tektonTasks and
cleanupOSBuilds() so the controller explicitly deletes the sbom-generate Task
when compliance is disabled.

@bennyz

bennyz commented Apr 12, 2026

Copy link
Copy Markdown
Contributor

This is being worked on in #197

- Fix critical: SBOM task volume now uses a dedicated secret-ref param
  instead of IMAGE_URL as the Secret name
- Fix major: sbom_generate.sh captures actual referrer digest from
  oras attach output for accurate SBOM_URI result
- Fix major: push_artifact.sh validates parsed digest before writing
  Tekton results (both multi-layer and single-file paths)
- Fix minor: ArtifactRef doc comments no longer wrongly scope fields
  to "when compliance is enabled"
- Fix minor: OperatorConfig reconciler cleans up sbom-generate task
  when compliance is toggled off
- Fix minor: ADR ComplianceConfig struct updated to match implementation
  (SyftImage instead of SBOMTaskBundle, drop TrustedArtifactSignerURL)

Made-with: Cursor
@vtz

vtz commented Apr 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @bennyz -- yes, I saw #197 overlaps on the IMAGE_URL/IMAGE_DIGEST pipeline results and digest capture.

This PR builds on top of that by adding the compliance layer (SBOM generation, ArtifactRef status, ComplianceConfig in OperatorConfig). Keeping it as a draft for now; once #197 is merged into main we'll rebase, drop the duplicated plumbing, and mark it ready for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integrate Red Hat Trusted Software Supply Chain (RHTSSC/TSSF)

2 participants