Repository navigation
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
/kind bug |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Re-signing creates duplicate signature keys, and inserted annotations do not consistently preserve CRLF endings.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
What changed in this PR
Preserves Task and Pipeline YAML formatting when adding trusted-resource signatures.
Changes:
- Inserts signature annotations directly into source YAML.
- Passes original document bytes through signing call sites.
- Adds preservation and verification tests.
- Promotes YAML v3 to a direct dependency.
| File | Description |
|---|---|
pkg/trustedresources/sign.go |
Signs while preserving the source document. |
pkg/trustedresources/sign_test.go |
Tests preservation and verification. |
pkg/trustedresources/annotation.go |
Implements insertion; must replace existing signatures and preserve CRLF endings. |
pkg/trustedresources/annotation_test.go |
Tests insertion; preservation checks should be order-sensitive. |
pkg/cmd/task/sign.go |
Passes Task source bytes. |
pkg/cmd/pipeline/sign.go |
Passes Pipeline source bytes. |
go.mod |
Declares YAML v3 as a direct dependency. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
/retest |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Critical issues with YAML aliases and unsigned unknown fields must be resolved.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 2
Open (2)
Resolved since last review (1)
12e7210 to
a2cb92f
Compare
tkn task sign and tkn pipeline sign marshalled the parsed resource back
to YAML, which rewrote the whole document: it reordered keys, reflowed
sequences, and emitted zero valued fields of the embedded Kubernetes
types, including the resources: {} that Tekton rejects on apply.
Sign now takes the document the resource was read from and inserts the
signature annotation into it, so the signed file differs from the input
by that annotation alone. The document is parsed only to locate the
insertion point: re-serializing the parsed tree collapses the line
breaks of a folded scalar such as description: >-.
Fixes tektoncd#2895
Fixes tektoncd#2894
Signed-off-by: somaz <genius5711@gmail.com>
Assisted-by: Claude Opus 5 (via Claude Code)
Signing a document that already carried a signature inserted a second tekton.dev/signature key, which strict YAML decoders reject. Replace the existing entry instead, and refuse one that spans several lines rather than rewrite part of it. The new signature was also computed with the old annotation still on the object, while Verify removes it before checking, so a re-signed file did not verify. Drop the old signature before signing. Inserted lines now use the document's own line ending, so a CRLF file is not left with mixed endings, and the preservation tests compare whole documents, so a reordered line fails them too. Signed-off-by: somaz <genius5711@gmail.com> Assisted-by: Claude Opus 5.5 (via Claude Code)
Sign writes the input document with the signature added, but the signature covers only the object decoded from it, and that decode drops any field the Tekton type does not define. Such a field reached the signed file unsigned, and verify decodes the same way, so changing it did not invalidate the signature. Decode the document strictly before signing and return an error for it instead. Adding the annotation to an anchored metadata or annotations mapping also changed every alias of that mapping, so a `labels: *common` alias gained a signature entry the signed object never had, and the file failed verification. Return an error rather than edit an anchored node. Signed-off-by: somaz <genius5711@gmail.com> Assisted-by: Claude Opus 5.5 (via Claude Code)
a2cb92f to
3bed96c
Compare
| "strings" | ||
|
|
||
| yaml "go.yaml.in/yaml/v3" | ||
| ) | ||
|
|
||
| // insertAnnotation sets key: value in metadata.annotations of doc, replacing an | ||
| // existing entry for key, and returns the result, leaving every other byte of | ||
| // the document untouched. | ||
| // | ||
| // The document is parsed only to locate the insertion point. Re-serializing the | ||
| // parsed tree would be simpler, but it does not round-trip: a folded scalar | ||
| // (`description: >-`) comes back with its line breaks collapsed, which is | ||
| // exactly the kind of unrelated diff this is meant to avoid. | ||
| // | ||
| // An error is returned when the document is not a mapping with a metadata | ||
| // mapping in it, when either mapping is written in flow style, where there | ||
| // is no line to insert, when an existing entry for key spans several lines, | ||
| // or when a node it would edit carries a YAML anchor, since the edit would | ||
| // then change every alias of that node too. | ||
| func insertAnnotation(doc []byte, key, value string) ([]byte, error) { | ||
| var root yaml.Node | ||
| if err := yaml.Unmarshal(doc, &root); err != nil { | ||
| return nil, fmt.Errorf("error parsing document: %w", err) | ||
| } |
| if metadata == nil { | ||
| return nil, fmt.Errorf("document has no metadata") | ||
| } | ||
| if metadata.Kind != yaml.MappingNode || metadata.Style == yaml.FlowStyle || len(metadata.Content) == 0 { |
| annotationsKey, annotations := mappingEntry(metadata, "annotations") | ||
| if annotations != nil && annotations.Anchor != "" { | ||
| return nil, fmt.Errorf("annotations has a YAML anchor") | ||
| } |
| indent := indentOf(annotationsKey) | ||
| return replaceLine(doc, annotationsKey.Line, indent+"annotations:\n"+indent+" "+key+": "+encoded) |


Changes
tkn task signandtkn pipeline signmarshalled the parsed resource back toYAML, so the whole document was rewritten rather than annotated. Keys were
reordered, sequences reflowed, and zero valued fields of the embedded Kubernetes
types were emitted, including the
resources: {}that Tekton rejects on applywith
strict decoding error: unknown field "spec.steps[0].resources".Signnow takes the document the resource was read from and inserts thesignature annotation into it directly, so the signed file differs from the input
by that annotation alone. Both reported symptoms come from the same cause, so
this covers them together.
The document is parsed only to locate the insertion point. Re-serializing the
parsed tree was the simpler option but does not round trip: a folded scalar
(
description: >-) comes back with its line breaks collapsed, which is exactlythe kind of unrelated diff the catalog
verify-generatedcheck trips over.Two things worth flagging for review:
Signtakes an extra argument. All three call sites already had the filecontents to hand, so the change is one argument at each.
metadataorannotationsis written in flow style, since there is no lineto insert. Everything else is handled: existing annotations, no annotations,
annotations: {}, an emptyannotations:key, a leading---, and leadingcomments. Happy to fall back to the old behaviour there instead if you prefer.
go.yaml.in/yaml/v3was already vendored as an indirect dependency, sogo mod tidymoves one line andgo mod vendorproduces no change.Verified by reverting the fix: the new tests then report
resources: {}presentand the step sequence reformatted from
- name: echointo- image: ubuntu/name: echo, reproducing both issues exactly.Submitter Checklist
make checkmake generatedRelease Notes