Skip to content

trusted_task_rules: Add per-allow-rule signature verification - #1680

Draft
arewm wants to merge 1 commit into
conforma:mainfrom
arewm:ec-1545/signature-verification-trusted-task-rules
Draft

trusted_task_rules: Add per-allow-rule signature verification#1680
arewm wants to merge 1 commit into
conforma:mainfrom
arewm:ec-1545/signature-verification-trusted-task-rules

Conversation

@arewm

@arewm arewm commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Today, trusted_task_rules trusts task bundles based solely on URL pattern matching — if the bundle ref matches oci://quay.io/konflux-ci/tekton-catalog/*, it's trusted. This PR adds an optional signature_verification field on allow rules so that matching bundles must also have a verified sigstore signature from a specific identity.

This is per-allow-rule because different catalogs may be signed by different parties (e.g., Konflux catalog vs. a third-party catalog). Rules without the field work exactly as before.

Changes:

  • Add optional signature_verification config to allow rules in trusted_task_rules
  • Git-resolved tasks are exempt (ec.sigstore.verify_image only works on OCI refs)
  • New signature_verification_failed denial reason type with proper error formatting

Companion CLI PR: conforma/cli#3136 (caches ec.sigstore.verify_image results across component evaluations for performance).

Ref: EC-1545

Test plan

  • All tests pass (868/868, 100% coverage)
  • Manual testing with real signed/unsigned task bundles
  • Verify backward compatibility with existing policy configurations

@codecov

codecov Bot commented Feb 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Flag Coverage Δ
unit-tests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
policy/lib/tekton/trusted.rego 100.00% <100.00%> (ø)
policy/lib/tekton/trusted_test.rego 100.00% <100.00%> (ø)
policy/release/trusted_task/trusted_task_test.rego 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@arewm
arewm marked this pull request as ready for review February 28, 2026 02:51
@arewm

arewm commented Apr 10, 2026

Copy link
Copy Markdown
Contributor Author

@simonbaird @joejstuart , is this something that you are interested in?

@arewm
arewm force-pushed the ec-1545/signature-verification-trusted-task-rules branch from f066bc2 to d757058 Compare May 7, 2026 17:09
@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Trusted Tekton task evaluation now supports Sigstore signature verification for OCI bundles. The schema accepts credential selectors and verification options, trust decisions incorporate verification results, and denial responses identify failed patterns. Unit and release tests cover these behaviors.

Changes

Trusted task signature verification

Layer / File(s) Summary
Signature verification policy
policy/lib/tekton/trusted.rego
Allow-rule schemas accept Sigstore settings; OCI bundle signatures are verified during trust evaluation, git tasks remain exempt, and failures produce signature_verification_failed denial details.
Signature verification validation
policy/lib/tekton/trusted_test.rego, policy/release/trusted_task/trusted_task_test.rego
Tests cover verification outcomes, schema validation, multiple matching allow rules, git exemptions, failure reporting, and mocked verification or manifest lookups.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TrustedTaskRules
  participant OCIBundle
  participant Sigstore
  TrustedTaskRules->>OCIBundle: Resolve bundle manifests
  TrustedTaskRules->>Sigstore: Verify bundle with rule options
  Sigstore-->>TrustedTaskRules: Return verification result
  TrustedTaskRules-->>TrustedTaskRules: Trust task or report signature_verification_failed
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main change: per-allow-rule signature verification for trusted task rules.
Description check ✅ Passed The description includes the change summary, rationale, ticket reference, and test plan, though it doesn't use the exact template headings.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

@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: 1

🧹 Nitpick comments (1)
policy/lib/tekton/trusted.rego (1)

337-353: 💤 Low value

Denial-reason branch logic looks correct, but consider deduplicating the matching predicate.

The new signature_verification_failed branch is reached only when no deny rule matches, some allow rule matches pattern+version, and _task_matches_allow_rule still fails — i.e., signature verification is the only remaining failure cause. Git-resolved refs continue to short-circuit through _signature_verified_for_rule(ref, _) if { not ref.bundle }, so they do not surface this denial reason.

One minor refactor opportunity: the pattern+version matching block here duplicates the predicate inside _task_matches_allow_rule minus the signature check. Extracting a helper like _task_matches_allow_rule_without_signature(ref, rule, bundle_manifests) would keep the two call sites aligned if pattern/version semantics ever evolve. Optional under the chill profile.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@policy/lib/tekton/trusted.rego` around lines 337 - 353, The denial branch for
"signature_verification_failed" duplicates the pattern+version matching logic
that also exists inside _task_matches_allow_rule; extract that shared predicate
into a helper (e.g., _task_matches_allow_rule_without_signature(ref, rule,
bundle_manifests)) and replace the duplicated checks in the
signature_verification_failed branch and inside _task_matches_allow_rule so both
call the new helper and only differ by the signature verification step (keeping
existing short-circuit behavior from _signature_verified_for_rule(ref, _) when
not ref.bundle intact).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@policy/lib/tekton/trusted.rego`:
- Around line 405-441: The current _sigstore_opts_for_rule(rule) returns opts
with certificate/issuer keys set to empty strings which makes
signature_verification: {} permissive; update _sigstore_opts_for_rule to remove
any keys whose value is "" (and/or false when appropriate) before returning so
ec.sigstore.verify_image(bundle, opts) only receives explicitly configured
constraints, and/or add schema changes to require at least one identity and at
least one issuer field in signature_verification; ensure references to
_sigstore_opts_for_rule, _signature_verified_for_rule,
_sigstore_verify_has_errors and ec.sigstore.verify_image are updated to use the
stripped/validated opts.

---

Nitpick comments:
In `@policy/lib/tekton/trusted.rego`:
- Around line 337-353: The denial branch for "signature_verification_failed"
duplicates the pattern+version matching logic that also exists inside
_task_matches_allow_rule; extract that shared predicate into a helper (e.g.,
_task_matches_allow_rule_without_signature(ref, rule, bundle_manifests)) and
replace the duplicated checks in the signature_verification_failed branch and
inside _task_matches_allow_rule so both call the new helper and only differ by
the signature verification step (keeping existing short-circuit behavior from
_signature_verified_for_rule(ref, _) when not ref.bundle intact).
🪄 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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: f7470a8e-3be9-4ee1-9d4a-b86852829975

📥 Commits

Reviewing files that changed from the base of the PR and between db56628 and d757058.

📒 Files selected for processing (4)
  • policy/lib/tekton/trusted.rego
  • policy/lib/tekton/trusted_test.rego
  • policy/release/trusted_task/trusted_task.rego
  • policy/release/trusted_task/trusted_task_test.rego

Comment thread policy/lib/tekton/trusted.rego Outdated
@arewm
arewm force-pushed the ec-1545/signature-verification-trusted-task-rules branch from d757058 to 47e49fc Compare May 8, 2026 12:38
@github-actions github-actions Bot added size: XL and removed size: L labels May 9, 2026
@st3penta
st3penta marked this pull request as draft June 10, 2026 12:42
@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from 8b470e8 to 0221318 Compare June 23, 2026 15:58
@simonbaird

Copy link
Copy Markdown
Member

Gave it a fresh rebase.

My plan is to re-review with the goal of getting it merged. Maybe we'll get some agentic reviews triggered also.

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 23, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:01 PM UTC · Completed 4:12 PM UTC
Commit: 47d3320 · View workflow run →

@simonbaird

Copy link
Copy Markdown
Member

I'm not certain, but I think we want to merge conforma/cli#3136 before merging this.

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [schema-validation-gap] policy/lib/tekton/trusted.rego — The _trusted_task_rules_schema (including the new signature_verification anyOf constraint requiring at least one identity/key field) is only validated against rule_data. Rules loaded via data.trusted_task_rules bypass schema validation. A signature_verification config supplied through data.trusted_task_rules with an empty object {} or only non-identity fields (e.g., {"ignore_rekor": true}) could call ec.sigstore.verify_image with no identity constraints. This is a pre-existing gap that this PR widens.
    Remediation: Add schema validation for data.trusted_task_rules alongside the existing rule_data validation, or validate that signature_verification objects contain at least one identity/key field before calling ec.sigstore.verify_image.

  • [new-enum-variant] policy/lib/tekton/trusted.rego:425denial_reason now returns a new type value: "signature_verification_failed". The in-repo consumer _format_denial_reason handles it generically via its else clause, but any external downstream consumer that exhaustively matches on reason.type values will not handle this new variant.
    Remediation: Document the new signature_verification_failed denial type in API documentation or changelog.

  • [cross-repo-dependency] policy/lib/tekton/trusted.rego:538_sigstore_verify_has_errors calls ec.sigstore.verify_image, a built-in function from the companion CLI PR sigstore: Cache verify_image results across policy evaluations cli#3136. If this policy is evaluated against a CLI version without that built-in, OPA evaluation will fail. This creates a hard deployment ordering requirement.
    Remediation: Ensure coordinated release of sigstore: Cache verify_image results across policy evaluations cli#3136 and this policy change. Consider adding a guard for graceful degradation, or document the minimum CLI version requirement.

  • [missing-doc] antora/docs/modules/ROOT/pages/trusted_tasks.adoc — This page documents trusted tasks but does not mention trusted_task_rules at all. The trusted_task_rules feature — including allow/deny pattern matching, version constraints, and now signature verification — has no user-facing documentation. Users discovering the signature_verification feature would have no documentation to reference.
    Remediation: Add a section documenting the trusted_task_rules configuration format, including the new signature_verification fields.

Low

  • [consumer-completeness] policy/lib/tekton/trusted.rego:388 — The denial_reason function's doc comment enumerates possible denial types (deny_rule, not_allowed, no_effective_rules) but does not list signature_verification_failed.

  • [consumer-completeness] policy/lib/tekton/trusted.rego:466_trusted_task_rule_entry_schema is shared by both allow and deny rule types. signature_verification is accepted on deny rules by the schema, but the code never inspects it on deny rules — a deny rule with signature_verification set would have the field silently ignored.

  • [edge-case] policy/lib/tekton/trusted.rego:495_signature_verified_for_rules returns true if ANY matching allow rule lacks signature_verification (OPA OR semantics). Overlapping allow rules — one signed, one unsigned — allow bypassing signature verification. This is tested (test_multiple_allow_rules_different_sig_configs) and intentional, but the implicit bypass through overlapping rules could be surprising to operators.

  • [information-disclosure] policy/lib/tekton/trusted.rego:421 — The denial message for signature_verification_failed includes the full sigstore options object via %v formatting, exposing certificate identity and OIDC issuer configuration in user-facing error messages.

  • [naming-consistency] policy/lib/tekton/trusted.rego:498_signature_verified_for_rules uses OR semantics across matching rules; the function name could be clearer about this behavior.

  • [comment-capitalization] policy/lib/tekton/trusted.rego:519 — Comment uses # Todo: while the codebase predominantly uses # TODO: for action items.

  • [comment-numbering] policy/lib/tekton/trusted.rego:405 — The new signature_verification_failed else-clause is inserted between existing cases without updating the case numbering comments downstream.

  • [missing-doc] antora/docs/modules/ROOT/pages/packages/release_trusted_task.adoc — Auto-generated documentation doesn't mention signature verification; run make generate-docs after updating METADATA annotations.

Previous run

Review

Findings

Medium

  • [fail-open] policy/lib/tekton/trusted.rego:489 — The _signature_verified_for_rules function uses OPA disjunction (OR) across three definitions. Definition 1 succeeds if ANY matching allow rule lacks a signature_verification field, meaning a broad allow rule without signature_verification will bypass the signature verification requirement imposed by a more specific overlapping rule. The PR description confirms this is intentional per-allow-rule design ("Rules without the field work exactly as before"), but the behavior may surprise administrators who expect a narrower rule's signature_verification to apply when a broader rule without it also matches. Consider documenting this interaction explicitly.

  • [fail-open] policy/lib/tekton/trusted.rego:507 — If signature_verification is set to a non-object value (e.g., true), _sigstore_opts_for_rule returns undefined because is_object(sv) fails. In this case the task is actually marked UNTRUSTED (fail-closed), which is safe, but the error is silent — the user gets no indication that their malformed configuration is being ignored rather than applied. The JSON schema validation would flag this, but consider an explicit guard for clearer error reporting.

  • [missing-doc] antora/docs/modules/ROOT/pages/trusted_tasks.adoc — The trusted_tasks.adoc page does not document the trusted_task_rules system, including the new signature_verification configuration option. Users encountering signature_verification_failed errors will have no documentation to guide configuration. Note: the absence of trusted_task_rules documentation is a pre-existing gap; only the signature_verification extension is new to this PR.

Low

  • [stale-reference] policy/lib/tekton/trusted.rego:388 — The denial_reason comment block listing possible denial types does not include the new signature_verification_failed type.

  • [comment-convention] policy/lib/tekton/trusted.rego:489 — The _signature_verified_for_rules helper has three definitions without a dedicated leading comment. The semantics are documented on the parent _task_bundle_sig_check_okay, but a brief comment on the helper itself would aid readability.

  • [comment-convention] policy/lib/tekton/trusted.rego:510 — The _sigstore_opts_for_rule comment describes rationale rather than using the # Returns ... pattern common elsewhere in the file.

  • [missing-authorization] No linked GitHub issue. The PR references Jira EC-1545, which is not accessible for external verification.

  • [missing-doc] antora/docs/modules/ROOT/pages/packages/release_trusted_task.adoc — The new signature_verification_failed denial reason type is not mentioned in the package documentation. This is consistent with the existing pattern (other denial reason subtypes are also not enumerated in docs).

Previous run (2)

Review

Findings

Medium

  • [comment-conventions] policy/lib/tekton/trusted.rego:393 — The doc comment for denial_reason enumerates possible denial types (deny_rule, not_allowed, no_effective_rules) but does not include the new signature_verification_failed type. The established pattern documents all possible return types in this comment block. Downstream consumers (e.g., conforma/cli) that switch on reason.type should be aware of the new value; the companion PR cli#3136 suggests coordination is happening.
    Remediation: Add "signature_verification_failed" - matches allow rule but fails signature verification to the doc comment listing at line 393.

  • [stale-doc] antora/docs/modules/ROOT/pages/trusting_tasks.adoc — The PR adds a new signature_verification field to trusted_task_rules allow rules with sub-fields (certificate_identity, certificate_identity_regexp, certificate_oidc_issuer, certificate_oidc_issuer_regexp, ignore_rekor, public_key, rekor_url). The trusted_task_rules feature has no user-facing documentation anywhere in the repo — the trusting_tasks.adoc guide only covers the legacy trusted_tasks workflow. This gap predates this PR but the new field makes it more impactful.
    Remediation: Add a section documenting the trusted_task_rules data format including the new signature_verification field with its properties and validation constraints.

Low

  • [comment-accuracy] policy/lib/tekton/trusted.rego:472 — The doc comment says "No matching allow rule has a signature_verification config" but the Rego semantics are "at least one matching allow rule lacks a signature_verification config" (existential some rule in matching_rules; not rule.signature_verification). The behavior is intentional and tested (test_multiple_allow_rules_different_sig_configs), but the comment could be more precise.

  • [test-inadequate] policy/lib/tekton/trusted_test.rego — No test for ec.sigstore.verify_image returning a result without an errors key (e.g., {"success": true} without "errors"). In this case _sigstore_verify_has_errors would be undefined and verification would pass, which is correct behavior but should be codified in a test.

  • [comment-conventions] policy/lib/tekton/trusted.rego:409 — The existing denial_reason chain uses numbered case comments (# Case 2, # Case 3). The newly inserted clause uses an unnumbered # Case: label, and the subsequent cases are now misnumbered.

  • [defense-in-depth] policy/lib/tekton/trusted.rego:501_sigstore_opts_for_rule filters empty-string and false values. While the JSON schema's anyOf with minLength: 1 prevents empty strings at validation time, a defensive guard ensuring count(opts) > 0 before calling ec.sigstore.verify_image would make the fail-closed behavior explicit regardless of whether schema validation runs first.

Previous run (3)

Review — approve

Note: This PR is a GitHub Draft. The draft: true status was verified via the GitHub API. Findings below are provided for early feedback.

Summary

This PR adds optional per-allow-rule signature verification to the trusted_task_rules system. The implementation is well-structured, backward-compatible, and follows existing codebase patterns. Key changes:

  1. trusted.rego — Refactors _task_matches_allow_rule to separate pattern+version matching from signature verification. Adds _signature_verified_for_rule with three branches (no config → pass through, git tasks → exempt, OCI bundles → verify via ec.sigstore.verify_image). Adds _sigstore_opts_for_rule to build sigstore options from per-rule config. Extends the JSON schema with a signature_verification object definition using anyOf to require at least one identity mechanism.

  2. trusted_task.rego — Adds formatting for the new signature_verification_failed denial reason type.

  3. Tests — Comprehensive coverage including backward compatibility, valid/invalid signatures, multiple-rule interaction, git task exemption, denial reason formatting, schema validation (accepts valid config, rejects empty config, rejects config without identity).

Correctness

  • The else if chain ordering in denial_reason is correct: deny_rulesignature_verification_failednot_allowedno_effective_rules. The new case correctly fires only when pattern+version matches but signature verification fails across ALL matching rules.
  • Multiple-rule interaction is sound: if ANY allow rule matches without requiring signature verification, the task is trusted. This is intentional, tested, and important for operators to understand.
  • Git task exemption is correct — ec.sigstore.verify_image only works on OCI image references.
  • The _sigstore_opts_for_rule comprehension that filters empty/false values avoids passing ambiguous defaults to the sigstore built-in.
  • Schema's anyOf constraint requiring certificate_identity, certificate_identity_regexp, or public_key prevents empty signature_verification objects that would be silently permissive — this is a critical safety guard.
  • Fail-closed behavior: if ec.sigstore.verify_image returns errors, the task is untrusted. ✓

Security

  • The design correctly applies the principle of fail-closed: missing or failed signature verification blocks the task.
  • The additionalProperties: false in the schema prevents typos that could silently bypass verification.
  • One operational consideration: adding a broad unsigned allow rule (e.g., pattern: "oci://quay.io/*" without signature_verification) would effectively bypass signature requirements of more specific rules for matching tasks. This is inherent to the "any rule can pass" design and is not a defect, but operators should be aware.

Findings

# Severity File Description
1 low policy/lib/tekton/trusted.rego The signature_verification_failed denial reason message ("Task bundle %s failed signature verification") reports only the bundle ref, not which rule(s) were attempted or which verification constraints failed. When debugging signature issues across multiple allow rules, including the rule's identity constraints in the message would speed troubleshooting.
2 low antora/docs/ No documentation update accompanies the new signature_verification field. The existing Antora docs describe the legacy trusted_tasks system but not the trusted_task_rules system or its new signature verification capability. Before merging, consider adding at least a brief section to trusting_tasks.adoc or trusted_tasks.adoc.
3 low policy/lib/tekton/trusted.rego The _sigstore_opts_for_rule function strips empty strings and false values, producing a sparse options object. The existing sigstore.opts always passes all keys with defaults. While functionally equivalent for ec.sigstore.verify_image, a brief inline comment noting why sparse opts are used (to avoid empty strings being interpreted as "no constraint") would help future maintainers.

Labels: PR adds signature verification configuration to trusted task allow rules

Previous run (4)

Review

Findings

Medium

  • [fail-open] policy/lib/tekton/trusted.rego_sigstore_opts_for_rule builds opts by filtering signature_verification fields (removing empty strings and false). If all values are filtered out, the resulting empty {} object is passed to ec.sigstore.verify_image. If verify_image with empty opts returns no errors, this is a fail-open — the rule has a signature_verification field present but no actual verification constraints are enforced. The schema's anyOf + minLength: 1 constraints should prevent this at validation time, but there is no runtime guard in the verification path itself.
    Remediation: Add an explicit guard in _signature_verified_for_rule requiring filtered opts to be non-empty before calling verify_image (e.g. count(opts) > 0). If opts is empty after filtering, verification should fail (deny), not pass.

  • [fail-open] policy/lib/tekton/trusted.rego_sigstore_verify_has_errors uses some _ in info.errors which is undefined when ec.sigstore.verify_image returns unexpected output (missing errors field or function failure). Due to OPA's undefined-is-false semantics, not _sigstore_verify_has_errors(...) would then evaluate to true, silently passing verification. This is a fail-open risk on a security-critical path.
    Remediation: Consider requiring a positive verification signal (e.g. checking info.success == true or count(info.errors) == 0 explicitly) rather than relying on double negation of undefined.

Low

  • [fail-open] policy/lib/tekton/trusted.rego — The filter in _sigstore_opts_for_rule rejects empty strings and false but not whitespace-only strings. The JSON schema uses minLength: 1 which also accepts whitespace-only values. In practice, a whitespace-only certificate_identity would likely fail actual sigstore verification, so exploit risk is negligible.

  • [schema-validation-gap] policy/lib/tekton/trusted.rego — The parent _trusted_task_rule_entry_schema has additionalProperties: true, so a typo like signature_verifiction would be silently ignored at the top level, causing the rule to have no signature verification. The signature_verification sub-schema itself correctly uses additionalProperties: false. This is a pre-existing design choice, not introduced by this PR.

  • [consumer-completeness] policy/lib/tekton/trusted.regosignature_verification is added to the shared _trusted_task_rule_entry_schema used by both allow and deny rules. Deny rules do not call _signature_verified_for_rule, so signature_verification on a deny rule would be silently accepted by schema validation but ignored at runtime. This is a minor usability issue — deny rules deny regardless of signature.

  • [test-inadequate] policy/lib/tekton/trusted.rego:410 — The mixed-rule denial_reason scenario (one allow rule with signature_verification that fails, one without) is not explicitly tested for denial_reason output. The existing test_multiple_allow_rules_different_sig_configs tests is_trusted_task only. In the mixed scenario, _task_matches_allow_rule succeeds via the unsigned rule so denial_reason returns nothing — this is implicitly correct but untested.

  • [edge-case] policy/lib/tekton/trusted.rego:476 — The opts object constructed by _sigstore_opts_for_rule is passed to ec.sigstore.verify_image without validating compatibility with the external function's expected API contract. Tests mock this function, so the real opts shape is not validated.

Info

  • [sub-agent-failure] N/A — The intent-coherence, style-conventions, docs-currency, and cross-repo-contracts sub-agents could not run (model unavailable). These dimensions were not evaluated in this review.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jun 23, 2026
@arewm

arewm commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

It shouldn't matter whether this or the CLI change is merged first. This rule shouldn't be hit yet so it shouldn't be required to have the CLI fix in. Before leveraging this rule, however, we should make sure that the CLI is updated.

@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from 0221318 to a160a5a Compare July 7, 2026 20:54
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 8:54 PM UTC · Ended 9:01 PM UTC
Commit: 7c8ccca · View workflow run →

@simonbaird

Copy link
Copy Markdown
Member

Rebased again. FWIW conforma/cli#3136 is merged now.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge enhancement New feature or request and removed requires-manual-review Review requires human judgment labels Jul 7, 2026
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:54 PM UTC · Completed 9:01 PM UTC
Commit: 7c8ccca · View workflow run →

@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from a160a5a to 6f37270 Compare July 28, 2026 19:00
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 28, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 7:01 PM UTC · Ended 7:08 PM UTC
Commit: 87c4a29 · View workflow run →

@simonbaird

Copy link
Copy Markdown
Member

I rebased and did a little refactoring. No functional change, just IMO slightly easier to follow logic. One more round of agentic review I guess, then I'd be happy to merge.

@simonbaird

simonbaird commented Jul 28, 2026

Copy link
Copy Markdown
Member

It would be good to test this with a real signature. I haven't done that as yet.

Update: Created https://redhat.atlassian.net/browse/EC-2030 to track doing that.

@simonbaird
simonbaird marked this pull request as ready for review July 28, 2026 19:07
@qodo-for-conforma

Copy link
Copy Markdown

PR Summary by Qodo

Add Per-Rule Sigstore Verification for Trusted Tasks

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add per-rule Sigstore verification requirements for trusted OCI task bundles.
• Preserve pattern-only rules and exempt Git-resolved tasks from OCI verification.
• Report and format signature-verification failures with comprehensive policy tests.
Diagram

graph TD
  A["Task Reference"] --> B["Rule Evaluation"] --> C{"Rules Permit?"} -->|yes| D{"Signature Required?"} -->|"yes, OCI"| E["Sigstore Verify"] --> F{"Trust Result?"}
  D -->|"no or Git"| F
  C -->|no| G["Denial Reason"] --> H["Release Message"]
  F -->|failed| G
Loading
High-Level Assessment

The per-allow-rule approach is appropriate because signing identities can differ between catalogs while existing pattern-only rules remain backward compatible. A global signature policy would lose that catalog-to-identity association, while pre-verifying every task would add unnecessary OCI calls and would not naturally support Git exemptions.

Files changed (4) +261 / -3

Enhancement (2) +91 / -3
trusted.regoEnforce optional Sigstore checks on matching allow rules +86/-3

Enforce optional Sigstore checks on matching allow rules

• Extends trusted-task evaluation so matching OCI allow rules can require successful Sigstore verification with rule-specific options. Adds schema validation, Git-reference exemption, option filtering, and a structured signature_verification_failed denial reason while preserving unsigned allow-rule behavior.

policy/lib/tekton/trusted.rego

trusted_task.regoFormat signature-verification denial messages +5/-0

Format signature-verification denial messages

• Adds release-policy formatting for signature_verification_failed reasons, including the task-bundle verification message in user-facing trust errors.

policy/release/trusted_task/trusted_task.rego

Tests (2) +170 / -0
trusted_test.regoCover signature-aware trusted-task rule behavior +138/-0

Cover signature-aware trusted-task rule behavior

• Adds tests for successful and failed verification, backward compatibility, overlapping signed and unsigned rules, Git exemptions, denial reasons, and schema validation. Mock Sigstore responses isolate policy behavior from external verification.

policy/lib/tekton/trusted_test.rego

trusted_task_test.regoVerify release errors expose signature failures +32/-0

Verify release errors expose signature failures

• Adds an end-to-end policy test confirming that failed bundle verification produces a denial containing the new signature-verification reason.

policy/release/trusted_task/trusted_task_test.rego

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 28, 2026

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 7:08 PM UTC · Ended 7:27 PM UTC
Commit: 87c4a29 · View workflow run →

@qodo-for-conforma

qodo-for-conforma Bot commented Jul 28, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 15 rules

Grey Divider


Action required

1. Direct rules bypass signature schema 🐞 Bug ⛨ Security
Description
data.trusted_task_rules is merged without schema validation, so a rule containing
"signature_verification": false reaches this branch and treats verification as optional. A
matching OCI bundle is then trusted without calling Sigstore even though the new schema forbids that
value.
Code

policy/lib/tekton/trusted.rego[484]

+	not rule.signature_verification
Relevance

●●● Strong

PRs 1574 and 1609 show acceptance of schema hardening to prevent trusted-task policy gaps.

PR-#1574
PR-#1609
PR-#1740

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The direct data source is flattened into effective allow rules, while schema validation only
examines lib_rule_data("trusted_task_rules"). The existing test explicitly documents that direct
data bypasses schema validation, and the new falsy branch accepts signature_verification: false
without invoking Sigstore.

policy/lib/tekton/trusted.rego[154-164]
policy/lib/tekton/trusted.rego[282-295]
policy/lib/tekton/trusted.rego[482-506]
policy/lib/tekton/trusted_test.rego[846-856]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rules supplied through `data.trusted_task_rules` bypass the signature-verification schema. A malformed value such as `signature_verification: false` is consequently interpreted as an unsigned allow rule and trusts matching OCI bundles without verification.

## Issue Context
Both `data.trusted_task_rules` and `data.rule_data.trusted_task_rules` feed effective allow rules, but only the latter receives JSON Schema validation. Validate both inputs and make the unsigned branch require that the property is absent rather than merely false.

## Fix Focus Areas
- policy/lib/tekton/trusted.rego[154-188]
- policy/lib/tekton/trusted.rego[282-327]
- policy/lib/tekton/trusted.rego[482-506]
- policy/lib/tekton/trusted_test.rego[1289-1322]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Signature check evaluated twice 🐞 Bug ➹ Performance
Description
The release path evaluates signature verification while collecting untrusted tasks, then the added
denial branch evaluates the same check again; without external caching, each rejected task performs
duplicate verification. If the verifier result changes between evaluations, denial_reason can
become undefined and the release error can disappear.
Code

policy/lib/tekton/trusted.rego[411]

+	not _task_bundle_sig_check_okay(ref, bundle_manifests)
Relevance

●●● Strong

PRs 1616 and 1697 show strong acceptance of eliminating repeated expensive trust lookups.

PR-#1616
PR-#1697
PR-#1407

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Untrusted-task collection invokes is_trusted_task_rules, which now performs the signature check.
The release formatter then calls denial_reason, whose new branch performs that check again before
it can construct the error.

policy/lib/tekton/trusted.rego[120-140]
policy/lib/tekton/trusted.rego[398-417]
policy/release/trusted_task/trusted_task.rego[442-446]
policy/release/trusted_task/trusted_task.rego[490-503]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Signature verification is evaluated once to classify a task as untrusted and again to generate its denial reason. This permits duplicate expensive verifier calls and allows classification and diagnostics to observe different results.

## Issue Context
The release policy computes `untrusted_task_refs_rules` and subsequently calls `denial_reason` for every returned task. Preserve or cache one verification result so both decisions use the same outcome, without relying on a companion client-side cache.

## Fix Focus Areas
- policy/lib/tekton/trusted.rego[120-140]
- policy/lib/tekton/trusted.rego[398-417]
- policy/release/trusted_task/trusted_task.rego[420-446]
- policy/release/trusted_task/trusted_task.rego[490-506]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread policy/lib/tekton/trusted.rego Outdated
Comment thread policy/lib/tekton/trusted.rego

@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.

🧹 Nitpick comments (3)
policy/lib/tekton/trusted.rego (2)

473-497: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Matching-rules logic is duplicated between allow-rule matching and signature-check gating.

_task_bundle_sig_check_okay re-derives matching_rules via the same pattern+version filtering criteria that _task_matches_allow_rule presumably applies (used in is_trusted_task_rules at Line 138). Keeping two independent implementations of "which allow rules match this ref" risks silent drift if one is updated without the other (e.g., a future change to version-constraint semantics).

#!/bin/bash
# Confirm whether _task_matches_allow_rule duplicates the same filter logic.
rg -nP -A15 '_task_matches_allow_rule\(ref, bundle_manifests\) if' policy/lib/tekton/trusted.rego
♻️ Suggested extraction
+_matching_allow_rules(ref, bundle_manifests) := [rule |
+	some rule in _effective_allow_rules
+	_pattern_matches(ref.key, rule.pattern)
+	_version_satisfies_all_rule_constraints(ref, rule, bundle_manifests)
+]
+
 _task_bundle_sig_check_okay(ref, bundle_manifests) if {
-	matching_rules := [rule |
-		some rule in _effective_allow_rules
-		_pattern_matches(ref.key, rule.pattern)
-		_version_satisfies_all_rule_constraints(ref, rule, bundle_manifests)
-	]
-	_signature_verified_for_rules(ref, matching_rules)
+	_signature_verified_for_rules(ref, _matching_allow_rules(ref, bundle_manifests))
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@policy/lib/tekton/trusted.rego` around lines 473 - 497, Update
_task_bundle_sig_check_okay to reuse _task_matches_allow_rule for determining
matching allow rules instead of independently applying _pattern_matches and
_version_satisfies_all_rule_constraints. Preserve the existing matching_rules
input expected by _signature_verified_for_rules, ensuring pattern and version
filtering has a single shared implementation.

553-573: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Enforce mutually exclusive Sigstore credential selectors.

The signature_verification schema allows combining public_key with one or more certificate identity fields because anyOf only requires at least one option. If those modes are meant to be exclusive, switch to oneOf so conflicting combinations fail validation instead of being passed to ec.sigstore.verify_image.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@policy/lib/tekton/trusted.rego` around lines 553 - 573, Update the
signature_verification schema’s credential selector constraint from anyOf to
oneOf, ensuring exactly one of certificate_identity,
certificate_identity_regexp, or public_key is accepted while conflicting
combinations fail validation before ec.sigstore.verify_image.
policy/release/trusted_task/trusted_task_test.rego (1)

1361-1392: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assertion is looser than the rest of the file's test conventions.

Every other test here uses assertions.assert_equal_results(trusted_task.deny, expected) with an exact expected set. This new test only checks count(results) > 0 and that some message contains a substring, so it wouldn't catch a wrong code/term, an incorrectly formatted message, or unexpected additional denials. Consider asserting the exact expected result set for consistency and stronger regression protection, matching the style of test_deny_takes_precedence_over_allow etc.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@policy/release/trusted_task/trusted_task_test.rego` around lines 1361 - 1392,
Strengthen test_signature_verification_failed_error_rules by replacing the count
and substring checks with assertions.assert_equal_results against the exact
expected trusted_task.deny result set. Include the expected denial’s code, term,
and fully formatted message, following the assertion style used by
test_deny_takes_precedence_over_allow and nearby tests, while preserving the
existing mocked verification failure setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@policy/lib/tekton/trusted.rego`:
- Around line 473-497: Update _task_bundle_sig_check_okay to reuse
_task_matches_allow_rule for determining matching allow rules instead of
independently applying _pattern_matches and
_version_satisfies_all_rule_constraints. Preserve the existing matching_rules
input expected by _signature_verified_for_rules, ensuring pattern and version
filtering has a single shared implementation.
- Around line 553-573: Update the signature_verification schema’s credential
selector constraint from anyOf to oneOf, ensuring exactly one of
certificate_identity, certificate_identity_regexp, or public_key is accepted
while conflicting combinations fail validation before ec.sigstore.verify_image.

In `@policy/release/trusted_task/trusted_task_test.rego`:
- Around line 1361-1392: Strengthen
test_signature_verification_failed_error_rules by replacing the count and
substring checks with assertions.assert_equal_results against the exact expected
trusted_task.deny result set. Include the expected denial’s code, term, and
fully formatted message, following the assertion style used by
test_deny_takes_precedence_over_allow and nearby tests, while preserving the
existing mocked verification failure setup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4a1a7a42-6531-4aa2-a780-52b5ec7c7493

📥 Commits

Reviewing files that changed from the base of the PR and between 8b470e8 and 6f37270.

📒 Files selected for processing (4)
  • policy/lib/tekton/trusted.rego
  • policy/lib/tekton/trusted_test.rego
  • policy/release/trusted_task/trusted_task.rego
  • policy/release/trusted_task/trusted_task_test.rego
🚧 Files skipped from review as they are similar to previous changes (2)
  • policy/release/trusted_task/trusted_task.rego
  • policy/lib/tekton/trusted_test.rego

@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure · Started 7:08 PM UTC · Completed 7:27 PM UTC
Commit: 87c4a29 · View workflow run →

@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from 6f37270 to 6577722 Compare July 28, 2026 19:43
@simonbaird

Copy link
Copy Markdown
Member

Addressed some more review-bot feedback.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 28, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure · Started 7:44 PM UTC · Completed 8:02 PM UTC
Commit: 87c4a29 · View workflow run →

@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from 6577722 to e0d416e Compare July 29, 2026 15:08
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 29, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 3:09 PM UTC · Ended 3:14 PM UTC
Commit: 87c4a29 · View workflow run →

@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from e0d416e to a5a0f98 Compare July 29, 2026 15:13
@simonbaird

Copy link
Copy Markdown
Member

Fixing a line-too-long lint. No other changes.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 29, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:15 PM UTC · Completed 3:34 PM UTC
Commit: 87c4a29 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed ready-for-merge All reviewers approved — ready to merge labels Jul 29, 2026
@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from a5a0f98 to 5edd37b Compare July 30, 2026 19:41
Add optional `signature_verification` configuration to allow rules in
trusted_task_rules, enabling sigstore-based signature verification as an
additional trust dimension for task bundles.

When an allow rule includes `signature_verification`, matching bundles
must also pass sigstore verification with the configured identity/key.
Rules without the field continue to work as before (pattern-only trust).
Git-resolved tasks are exempt since ec.sigstore.verify_image only works
on OCI refs.

A new denial reason type `signature_verification_failed` is surfaced
when a task matches an allow rule's pattern/version constraints but
fails signature verification.

Ref: EC-1545

Assisted-by: Claude Code (Opus 4.6)
@simonbaird
simonbaird force-pushed the ec-1545/signature-verification-trusted-task-rules branch from 5edd37b to c116a14 Compare July 30, 2026 19:42
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 30, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure · Started 7:43 PM UTC · Completed 7:44 PM UTC
Commit: 87c4a29 · View workflow run →

v != ""
v != false
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Actually it might be possible for this part to go away once Joe's other PR is merged.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤔

@simonbaird

Copy link
Copy Markdown
Member

Probably want to rebase this on #1780 also.

@simonbaird
simonbaird marked this pull request as draft August 5, 2026 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request requires-manual-review Review requires human judgment size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants