Skip to content

Introduce a "PR mode" for attestations #3265

Description

@migmartri

Context / problem

When an attestation runs as part of a pull request / merge request, Chainloop today treats it the same as a build on main/a release. That causes two side-effects we don't want for PR builds:

  1. Latest promotion — PR builds get promoted to the project's "latest" version. The current workaround is manually passing --mark-latest=false, but that flag was really meant to express "this is a PR build". We're overloading a low-level flag to express a higher-level concept.
  2. Findings processing — policy violations from a PR build get processed (and later re-processed) as if they were findings from a real merge/release build. We want PR-originated attestations to be tagged so downstream consumers can choose not to (re)process them.

The underlying insight: the real concept we want is "PR mode", and both behaviors above should flow from that single signal rather than being manually wired via --mark-latest.

Decision (simplified)

After discussion, we're simplifying the original proposal. Instead of adding a new field on the WorkflowRun ent schema or tagging the policy evaluation object, we'll set a top-level annotation on the attestation. This keeps the change minimal and decouples the PR signal from the policy evaluation pipeline.

Well-known annotation key: chainloop.dev/is-pull-request with value "true".

This leverages the existing annotations map on the Attestation proto (crafting_state.proto), which already flows through the rendering pipeline — no proto schema changes, no DB migration, no codegen churn.

Detection — auto-detect + explicit override

  • Auto-detect from the CI runner environment (already implemented in DetectPRContext / prmetadata.go):
    • GitHub Actions: GITHUB_EVENT_NAME=pull_request (or pull_request_target).
    • GitLab: CI_PIPELINE_SOURCE=merge_request_event / CI_MERGE_REQUEST_IID.
    • Dagger: delegates to the parent CI env vars.
  • Explicit --pr / --pr=false flag on chainloop attestation init overrides auto-detection (zero-config in CI, escapable for edge cases / self-hosted / generic runner).

Behavior when in PR mode (by default)

  • Skip latest promotion — default to mark-latest=false. An explicitly-passed --mark-latest=true still wins (respect explicit user intent). This replaces the manual --mark-latest=false workaround.
  • Set the chainloop.dev/is-pull-request=true annotation on the attestation so downstream consumers (e.g. findings processing) can detect PR-originated attestations and skip (re)processing.

Scope split

  • OSS (this issue): capture & propagate the PR signal as a top-level annotation on the attestation; wire --pr flag and mark-latest default behavior.
  • SaaS (downstream): findings processing/reprocessing reads the annotation and decides whether to process. Not in scope for this issue.

Relevant code pointers

  • PR detection (existing): pkg/attestation/crafter/prmetadata.go (DetectPRContext), pkg/attestation/crafter/collector_prmetadata.go.
  • Runner env vars: pkg/attestation/crafter/runners/githubaction.go, gitlabpipeline.go, daggerpipeline.go.
  • CLI flags: app/cli/cmd/attestation_init.go (--mark-latest).
  • Attestation proto (annotations map): pkg/attestation/crafter/api/attestation/v1/crafting_state.proto (Attestation.annotations, field 5).
  • Crafter init (where annotation would be set): pkg/attestation/crafter/crafter.go (initialCraftingState).
  • Action layer: app/cli/pkg/action/attestation_init.go.

🤖 Posted by Maximus bot (Claude Code) on behalf of @migmartri

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions