Skip to content

✨ Add GitHub artifact attestation for Signed-Releases#5001

Open
martincostello wants to merge 1 commit intoossf:mainfrom
martincostello:gh-4667
Open

✨ Add GitHub artifact attestation for Signed-Releases#5001
martincostello wants to merge 1 commit intoossf:mainfrom
martincostello:gh-4667

Conversation

@martincostello
Copy link
Copy Markdown
Contributor

@martincostello martincostello commented Apr 5, 2026

What kind of change does this PR introduce?

New feature

What is the current behavior?

GitHub attestations are not considered.

What is the new behavior (if this is a feature change)?

Consider a GitHub release signed if all assets a digest with a matching GitHub attestation.

  • Tests for the changes have been added (for bug fixes/features)

Which issue(s) this PR fixes

Fixes #4667

Special notes for your reviewer

None.

Does this PR introduce a user-facing change?

Consider a release signed if all assets a digest with a matching GitHub attestation.

Consider a release signed if all assets a digest with a matching GitHub attestation.

Signed-off-by: martincostello <martin@martincostello.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 5, 2026

Codecov Report

❌ Patch coverage is 89.58333% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.25%. Comparing base (353ed60) to head (8bb14b5).
⚠️ Report is 346 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5001      +/-   ##
==========================================
+ Coverage   66.80%   68.25%   +1.44%     
==========================================
  Files         230      252      +22     
  Lines       16602    15743     -859     
==========================================
- Hits        11091    10745     -346     
+ Misses       4808     4156     -652     
- Partials      703      842     +139     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@martincostello martincostello marked this pull request as ready for review April 5, 2026 12:13
@martincostello martincostello requested a review from a team as a code owner April 5, 2026 12:13
@martincostello martincostello requested review from AdamKorcz, Copilot and spencerschrock and removed request for a team April 5, 2026 12:13
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Apr 5, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for treating GitHub Artifact Attestations as an alternative “signed release” signal in the Signed-Releases check, using GitHub release asset digests + attestations API lookups.

Changes:

  • Extend release assets to carry Digest and HasAttestation, populated by the GitHub repo client via attestations API calls.
  • Add a new releasesHaveAttestation probe (plus docs/tests) and wire it into the Signed-Releases probe set.
  • Update Signed-Releases evaluation logic and documentation to award max score when attestations cover all assets.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
probes/releasesHaveAttestation/impl.go New probe that reports per-release whether all assets have digests + attestations.
probes/releasesHaveAttestation/impl_test.go Unit tests for the new attestation probe behavior and lookback.
probes/releasesHaveAttestation/def.yml Probe metadata definition for documentation/remediation text.
probes/entries.go Registers the new probe under the Signed-Releases check.
docs/probes.md Documents the new probe and its outcomes.
docs/checks/internal/checks.yaml Updates Signed-Releases check definition to include attestations as a max-score path.
docs/checks.md Updates public Signed-Releases documentation to include attestations guidance.
clients/release.go Adds Digest and HasAttestation fields to ReleaseAsset.
clients/githubrepo/releases.go Populates digest from release assets and queries attestations API to set HasAttestation.
clients/githubrepo/releases_test.go Adds tests for digest parsing and attestations API behavior.
checks/evaluation/signed_releases.go Incorporates the attestation probe into scoring/log suppression logic.
checks/evaluation/signed_releases_test.go Extends evaluation tests to cover attestation-driven scoring/logging.

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

Comment on lines +94 to +96
loc := &finding.Location{
Type: finding.FileTypeURL,
Path: release.URL,
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

The failing-case finding uses release.URL, which is the GitHub API URL (r.GetURL()), while the success-case uses asset.URL (HTML URL). This yields inconsistent/unfriendly links in findings; since len(release.Assets) > 0 here, consider using the release HTML URL consistently (e.g., reusing release.Assets[0].URL or storing HTMLURL on clients.Release).

Suggested change
loc := &finding.Location{
Type: finding.FileTypeURL,
Path: release.URL,
// Use the first asset URL as a representative HTML URL for the release,
// matching the success case and avoiding the GitHub API URL in findings.
loc := &finding.Location{
Type: finding.FileTypeURL,
Path: release.Assets[0].URL,

Copilot uses AI. Check for mistakes.

if len(findings) == 0 {
f, err := finding.NewWith(fs, Probe,
"no GitHub releases found",
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

When findings is empty this reports "no GitHub releases found", but findings can also be empty when releases exist but all of them have zero assets (those are continued above). Consider adjusting the message (or emitting OutcomeNotApplicable per asset-less release) so the result is accurate.

Suggested change
"no GitHub releases found",
"no GitHub releases with assets found",

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +83
func (handler *releasesHandler) resolveOwnerEndpointPrefix() string {
user, _, err := handler.client.Users.Get(handler.ctx, handler.repourl.owner)
if err != nil {
// Fall back to users; hasAttestation will skip on 404.
return ownerEndpointUser
}
if strings.EqualFold(user.GetType(), "Organization") {
return ownerEndpointOrg
}
return ownerEndpointUser
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

The comment says "hasAttestation will skip on 404", but hasAttestation currently returns false for all errors and does not special-case 404s. This also means if Users.Get fails (rate limit/network) for an org-owned repo, the fallback to users/... can cause all attestation checks to incorrectly return false due to hitting the wrong endpoint. Consider either (a) updating the comment, or (b) handling 404 by retrying the alternate users/orgs prefix once before returning false.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to 69
handler.ownerEndpointPrefix = handler.resolveOwnerEndpointPrefix()
handler.checkAttestations()
})
return handler.errSetup
}

Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

checkAttestations() is invoked unconditionally during ListReleases() setup and iterates over every release/asset returned by Repositories.ListReleases (default 30 releases). This adds a potentially large number of extra REST calls (and likely 401/403s without an auth token) even for checks that don't need attestations, which can noticeably increase runtime and risk API rate limiting. Consider deferring attestation lookups to the attestation probe (or gating/limiting them to the same lookback window the probe evaluates).

Suggested change
handler.ownerEndpointPrefix = handler.resolveOwnerEndpointPrefix()
handler.checkAttestations()
})
return handler.errSetup
}
})
return handler.errSetup
}
// setupAttestations lazily enriches the already-loaded releases with
// attestation metadata. This is intentionally separate from setup so that
// generic release listing does not incur the additional per-asset API calls.
func (handler *releasesHandler) setupAttestations() error {
if err := handler.setup(); err != nil {
return err
}
handler.ownerEndpointPrefix = handler.resolveOwnerEndpointPrefix()
handler.checkAttestations()
return nil
}

Copilot uses AI. Check for mistakes.
Comment on lines 124 to 133
logLevel = checker.DetailWarn
if f.Probe == releasesAreSigned.Probe && hasProvenance[releaseName] {
if f.Probe == releasesAreSigned.Probe && hasProvenanceOrAttestation[releaseName] {
continue
}
// Attestation is an optional alternative to signing or provenance.
// Suppress warnings when attestation is absent to avoid noise for projects
// that use other verification methods.
if f.Probe == releasesHaveAttestation.Probe {
continue
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

The code treats attestation as an alternative for scoring (sets 10) and suppresses warnings when the attestation probe is false, but it still logs a warning when provenance is false even if attestation is true for that release. If attestation is intended as an alternative to provenance, consider also suppressing the provenance warning for releases that already have an attestation OutcomeTrue to avoid confusing/noisy output when the check is already at max score.

Copilot uses AI. Check for mistakes.
@martincostello
Copy link
Copy Markdown
Contributor Author

Results from local manual run:

.\scorecard.exe --repo=github.com/open-telemetry/opentelemetry-dotnet

RESULTS
-------
Aggregate score: 9.2 / 10

Check scores:
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|  SCORE  |          NAME          |                                         REASON                                         |                                              DOCUMENTATION / REMEDIATION                                              |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Binary-Artifacts       | no binaries found in the repo                                                          | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#binary-artifacts       |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 5 / 10  | Branch-Protection      | branch protection is not maximal on development and all release branches               | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#branch-protection      |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | CI-Tests               | 30 out of 30 merged PRs checked by a CI test -- score normalized to 10                 | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#ci-tests               |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 5 / 10  | CII-Best-Practices     | badge detected: Passing                                                                | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#cii-best-practices     |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Code-Review            | all changesets reviewed                                                                | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#code-review            |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Contributors           | project has 37 contributing companies or organizations                                 | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#contributors           |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| ?       | Dangerous-Workflow     | no workflows found                                                                     | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#dangerous-workflow     |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Dependency-Update-Tool | update tool detected                                                                   | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#dependency-update-tool |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Fuzzing                | project is fuzzed                                                                      | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#fuzzing                |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | License                | license file detected                                                                  | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#license                |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Maintained             | 30 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10 | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#maintained             |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| ?       | Packaging              | packaging workflow not detected                                                        | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#packaging              |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Pinned-Dependencies    | all dependencies are pinned                                                            | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#pinned-dependencies    |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | SAST                   | SAST tool is run on all commits                                                        | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#sast                   |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Security-Policy        | security policy file detected                                                          | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#security-policy        |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 8 / 10  | Signed-Releases        | 4 out of the last 5 releases have a total of 4 signed artifacts.                       | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#signed-releases        |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| ?       | Token-Permissions      | No tokens found                                                                        | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#token-permissions      |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Vulnerabilities        | 0 existing vulnerabilities detected                                                    | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#vulnerabilities        |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|

.\scorecard.exe --repo=github.com/open-telemetry/opentelemetry-dotnet-contrib

RESULTS
-------
Aggregate score: 9.4 / 10

Check scores:
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|  SCORE  |          NAME          |                                         REASON                                         |                                              DOCUMENTATION / REMEDIATION                                              |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Binary-Artifacts       | no binaries found in the repo                                                          | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#binary-artifacts       |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 5 / 10  | Branch-Protection      | branch protection is not maximal on development and all release branches               | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#branch-protection      |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | CI-Tests               | 30 out of 30 merged PRs checked by a CI test -- score normalized to 10                 | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#ci-tests               |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 5 / 10  | CII-Best-Practices     | badge detected: Passing                                                                | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#cii-best-practices     |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Code-Review            | all changesets reviewed                                                                | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#code-review            |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Contributors           | project has 23 contributing companies or organizations                                 | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#contributors           |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| ?       | Dangerous-Workflow     | no workflows found                                                                     | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#dangerous-workflow     |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Dependency-Update-Tool | update tool detected                                                                   | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#dependency-update-tool |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Fuzzing                | project is fuzzed                                                                      | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#fuzzing                |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | License                | license file detected                                                                  | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#license                |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Maintained             | 30 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10 | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#maintained             |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| ?       | Packaging              | packaging workflow not detected                                                        | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#packaging              |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Pinned-Dependencies    | all dependencies are pinned                                                            | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#pinned-dependencies    |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | SAST                   | SAST tool is run on all commits                                                        | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#sast                   |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Security-Policy        | security policy file detected                                                          | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#security-policy        |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Signed-Releases        | 5 out of the last 5 releases have a total of 5 signed artifacts.                       | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#signed-releases        |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| ?       | Token-Permissions      | No tokens found                                                                        | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#token-permissions      |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| 10 / 10 | Vulnerabilities        | 0 existing vulnerabilities detected                                                    | https://github.com/ossf/scorecard/blob/8bb14b585bc277455ee31d0cbd2b0756208d793d/docs/checks.md#vulnerabilities        |
|---------|------------------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|

@github-actions
Copy link
Copy Markdown

This pull request has been marked stale because it has been open for 10 days with no activity

@github-actions github-actions Bot added the Stale label Apr 17, 2026
@martincostello
Copy link
Copy Markdown
Contributor Author

Not stale - waiting for feedback.

@github-actions github-actions Bot removed the Stale label Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[Feature] Support GitHub Attestations with artifacts for Signed-Releases

2 participants