Skip to content

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

Draft
arewm wants to merge 4 commits 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 4 commits 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.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

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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 275b8441-4e2e-4b0e-925c-af80bd83c115

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
📝 Walkthrough

Walkthrough

Allow-rule matching for Tekton trusted tasks now enforces Sigstore signature verification when a rule includes a signature_verification block (git-resolved tasks are exempt). New helpers build Sigstore options, perform verification, and denial_reason reports signature_verification_failed. Schema and tests are updated accordingly.

Changes

Signature Verification for Trusted Tasks

Layer / File(s) Summary
Data Shape & Schema
policy/lib/tekton/trusted.rego
Adds signature_verification object to _trusted_task_rule_entry_schema with additionalProperties: false and anyOf requiring one of certificate_identity, certificate_identity_regexp, or public_key.
Core Verification Helpers
policy/lib/tekton/trusted.rego
Adds _sigstore_opts_for_rule(rule) to build Sigstore options (filters out empty-string/false), _sigstore_verify_has_errors(bundle, opts) to inspect ec.sigstore.verify_image results, and _signature_verified_for_rule(ref, rule) to determine verification status (no block or non-OCI bundle = pass; otherwise verifies).
Allow-Rule Matching
policy/lib/tekton/trusted.rego
Splits prior allow matching into _task_matches_allow_rule_pattern_version(ref, rule, bundle_manifests) (pattern + version constraints) and requires _signature_verified_for_rule(ref, rule) in _task_matches_allow_rule.
Denial Reasoning
policy/lib/tekton/trusted.rego
denial_reason(task, bundle_manifests) gains a branch that emits type = "signature_verification_failed" when a rule’s pattern/version match but signature verification fails.
Formatting for Release Messages
policy/release/trusted_task/trusted_task.rego
_format_denial_reason extended to format signature_verification_failed with the type line plus indented bullet list of reason.messages when present.
Library Tests
policy/lib/tekton/trusted_test.rego
Adds “SIGNATURE VERIFICATION TESTS”: mocks for ec.sigstore.verify_image success/failure; tests for backward compatibility (no block), success, failure producing signature_verification_failed, multiple-allow-rule behavior, git-task exemption, and schema acceptance/rejection cases.
Release Tests
policy/release/trusted_task/trusted_task_test.rego
Adds test_signature_verification_failed_error_rules and local mocks (_mock_verify_image_failure, _mock_empty_manifests) asserting trusted_task.deny includes signature_verification_failed when verification is mocked to fail.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding optional signature verification configuration to allow rules in trusted task rules.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation, implementation details, and test coverage for the signature verification feature added to trusted task rules.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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
@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
arewm and others added 4 commits June 23, 2026 11:13
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)
Deduplicate the pattern+version matching logic shared between
_task_matches_allow_rule and the signature_verification_failed
denial_reason branch into _task_matches_allow_rule_pattern_version.

No behavior change — pure refactor.

Assisted-by: Claude Code (Opus 4.6)
An empty `signature_verification: {}` block would silently become
permissive because empty-string defaults are treated as "no constraint"
by Sigstore. Fix this in two ways:

- _sigstore_opts_for_rule now passes through only explicitly-set
  non-default values instead of emitting empty-string defaults
- Schema requires at least one of certificate_identity,
  certificate_identity_regexp, or public_key via anyOf, and enforces
  minLength: 1 on all string fields

Assisted-by: Claude Code (Opus 4.6)
@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

Copy link
Copy Markdown

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.

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

Labels

requires-manual-review Review requires human judgment size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants