Skip to content

fix(signing): aggregate no-signer-configured errors into MarkSigned decision#1834

Open
pujitha24 wants to merge 2 commits into
tektoncd:mainfrom
pujitha24:auto/issue-858
Open

fix(signing): aggregate no-signer-configured errors into MarkSigned decision#1834
pujitha24 wants to merge 2 commits into
tektoncd:mainfrom
pujitha24:auto/issue-858

Conversation

@pujitha24

Copy link
Copy Markdown

Motivation:
When no signer (e.g. no x509.pem/cosign.key) is configured for a
required signer type, ObjectSigner.Sign() logs "No signer %s
configured for %s" and continues, but never records this as a
failure. Since the aggregate merr stays nil, Sign() falls through
to annotations.MarkSigned(), which sets
chains.tekton.dev/signed=true even though nothing was signed. That
annotation is treated as terminal, so the TaskRun/PipelineRun is
never retried once a signer becomes available. This is the exact
scenario reported in #858: no signing key configured, yet Chains
marks the run as signed.

Note: user-visible behavior for legitimate Signer: "none"
configurations (intentional opt-out of signing for an artifact
type) is unchanged - Artifact.Enabled() short-circuits before the
signer lookup for that case, so this only affects the genuine
misconfiguration path.

Approach:
Append an error to the existing merr aggregate in the
"no signer configured" branch of ObjectSigner.Sign(), matching the
same multierror.Append pattern already used a few lines below for
storage failures. This makes Sign() return an error and take the
existing HandleRetry path instead of MarkSigned, so the resource is
retried on the next reconciliation rather than being permanently
marked signed.

Validation:
Added a table-driven case to TestSigner_Sign that points SecretPath
at a directory with no key material, reproducing the no-signer
scenario, and asserts the object is NOT marked signed. Verified the
new case fails without the fix (IsSigned()=true, wanted false) and
passes with it.

go build ./...
go test ./pkg/chains/...
make golangci-lint PKG=./pkg/chains/...

All pass with zero failures and zero lint issues.

Fixes #858

Signed-off-by: Pujitha Paladugu 10557236+pujitha24@users.noreply.github.com


AI assistance: this change was drafted with Claude Code.

…ecision

Motivation:
When no signer (e.g. no x509.pem/cosign.key) is configured for a
required signer type, ObjectSigner.Sign() logs "No signer %s
configured for %s" and continues, but never records this as a
failure. Since the aggregate `merr` stays nil, Sign() falls through
to annotations.MarkSigned(), which sets
chains.tekton.dev/signed=true even though nothing was signed. That
annotation is treated as terminal, so the TaskRun/PipelineRun is
never retried once a signer becomes available. This is the exact
scenario reported in tektoncd#858: no signing key configured, yet Chains
marks the run as signed.

Note: user-visible behavior for legitimate `Signer: "none"`
configurations (intentional opt-out of signing for an artifact
type) is unchanged - Artifact.Enabled() short-circuits before the
signer lookup for that case, so this only affects the genuine
misconfiguration path.

Approach:
Append an error to the existing `merr` aggregate in the
"no signer configured" branch of ObjectSigner.Sign(), matching the
same multierror.Append pattern already used a few lines below for
storage failures. This makes Sign() return an error and take the
existing HandleRetry path instead of MarkSigned, so the resource is
retried on the next reconciliation rather than being permanently
marked signed.

Validation:
Added a table-driven case to TestSigner_Sign that points SecretPath
at a directory with no key material, reproducing the no-signer
scenario, and asserts the object is NOT marked signed. Verified the
new case fails without the fix (IsSigned()=true, wanted false) and
passes with it.

  go build ./...
  go test ./pkg/chains/...
  make golangci-lint PKG=./pkg/chains/...

All pass with zero failures and zero lint issues.

Fixes tektoncd#858

Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 25, 2026 22:39
@tekton-robot
tekton-robot requested a review from ab-ghosh July 25, 2026 22:39
@tekton-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please assign puneetpunamiya after the PR has been reviewed.
You can assign the PR to them by writing /assign @puneetpunamiya in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot
tekton-robot requested a review from ngelman1 July 25, 2026 22:39
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 25, 2026

Copy link
Copy Markdown

CLA Not Signed

@tekton-robot tekton-robot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Jul 25, 2026

Copilot AI 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.

⚠️ Not ready to approve

The new missing-signer error aggregation can balloon into many duplicate aggregated errors/log spam for multi-object artifacts unless the per-object loop exits on first missing signer.

Pull request overview

This PR fixes a misconfiguration edge case in Chains signing where missing signer configuration could still result in chains.tekton.dev/signed=true, preventing future retries once a signer/key becomes available.

Changes:

  • Aggregate “no signer configured” as an error in ObjectSigner.Sign() so signing failures take the retry path instead of falling through to MarkSigned.
  • Add a unit test case to reproduce the “no signer configured” scenario and assert the object is not marked signed.
File summaries
File Description
pkg/chains/signing.go Appends missing-signer errors into the existing multierror aggregate so signing failures trigger retries instead of MarkSigned.
pkg/chains/signing_test.go Adds a regression test case covering the missing-signer scenario and validates the object is not marked signed.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Low

Note

Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/chains/signing.go Outdated
if !ok {
logger.Warnf("No signer %s configured for %s", signerType, signableType.Type())
merr = multierror.Append(merr, fmt.Errorf("no signer %s configured for %s", signerType, signableType.Type()))
continue

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch, thank you. Since signerType := signableType.Signer(cfg) only depends on signableType/cfg and not on the individual object, the missing-signer condition really is invariant across every object extracted for that signable type. I changed the continue to break on this branch, so we now record at most one "no signer configured" error per signable type per Sign() call and stop creating payloads for the remaining objects of that type, instead of repeating the warning/error for each one. It still falls through to the existing retry/annotation handling right after the loop, so that behavior is unchanged.

go build ./..., go test ./pkg/chains/..., and make golangci-lint PKG=./pkg/chains/... all pass with this change.

Break out of the per-object loop on the first missing-signer
occurrence instead of continuing, since the signer type is
determined by the signable type/config and does not vary per
object. This avoids appending duplicate identical errors to the
aggregate and skips unnecessary payload creation for the remaining
objects of that signable type.

Addressed per Copilot review feedback on PR tektoncd#1834.

Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
@tekton-robot tekton-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chains adds chains.tekton.dev/signed=true annotation even if no keys supplied

3 participants