*: Add functionality to export attestations for a commit

This commit is contained in:
Pat Zielinski 2025-11-07 01:00:48 -05:00
parent fc8143ab66
commit 0eb88c989d
4 changed files with 118 additions and 3 deletions

View file

@ -19,6 +19,7 @@ import (
"github.com/gittuf/gittuf/internal/attestations/github"
githubv01 "github.com/gittuf/gittuf/internal/attestations/github/v01"
"github.com/gittuf/gittuf/internal/gitinterface"
"github.com/gittuf/gittuf/internal/policy"
"github.com/gittuf/gittuf/internal/rsl"
"github.com/gittuf/gittuf/internal/signerverifier/dsse"
sslibdsse "github.com/gittuf/gittuf/internal/third_party/go-securesystemslib/dsse"
@ -550,6 +551,54 @@ func (r *Repository) DismissGitHubPullRequestApprover(ctx context.Context, signe
return currentAttestations.Commit(r.r, commitMessage, options.CreateRSLEntry, signCommit)
}
func (r *Repository) ExportAttestationsForRevision(ctx context.Context, target gitinterface.Hash, path string) error {
//currentAttestations, err := attestations.LoadCurrentAttestations(r.r)
//if err != nil {
// return err
//}
entry, err := rsl.GetLatestEntry(r.r)
if err != nil {
return err
}
var targetEntry rsl.ReferenceUpdaterEntry
for {
if entry, ok := entry.(rsl.ReferenceUpdaterEntry); ok {
if entry.GetTargetID().Equal(target) {
targetEntry = entry
break
}
}
entry, err = rsl.GetParentForEntry(r.r, entry)
if err != nil {
return errors.New("exhausted all entries in the RSL")
}
}
fmt.Println(targetEntry.GetID())
state, err := policy.LoadCurrentState(ctx, r.r, policy.PolicyRef)
if err != nil {
return err
}
attestationsState, err := attestations.LoadCurrentAttestations(r.r)
if err != nil {
return err
}
_, attestationHashes, _, err := policy.GetApproverAttestationAndKeyIDs(ctx, r.r, state, attestationsState, targetEntry.(*rsl.ReferenceEntry))
if err != nil {
return err
}
return r.exportAttestations(attestationHashes, path)
}
func (r *Repository) addGitHubPullRequestAttestation(ctx context.Context, signer sslibdsse.SignerVerifier, githubBaseURL, owner, repository string, pullRequest *gogithub.PullRequest, createRSLEntry, signCommit bool) error {
var (
targetRef string

View file

@ -6,6 +6,7 @@ package attest
import (
"github.com/gittuf/gittuf/internal/cmd/attest/apply"
"github.com/gittuf/gittuf/internal/cmd/attest/authorize"
"github.com/gittuf/gittuf/internal/cmd/attest/export"
"github.com/gittuf/gittuf/internal/cmd/attest/github"
"github.com/gittuf/gittuf/internal/cmd/attest/persistent"
"github.com/spf13/cobra"
@ -23,6 +24,7 @@ func New() *cobra.Command {
cmd.AddCommand(apply.New())
cmd.AddCommand(authorize.New(o))
cmd.AddCommand(export.New(o))
cmd.AddCommand(github.New(o))
return cmd

View file

@ -0,0 +1,64 @@
// Copyright The gittuf Authors
// SPDX-License-Identifier: Apache-2.0
package export
import (
"github.com/gittuf/gittuf/experimental/gittuf"
"github.com/gittuf/gittuf/internal/cmd/attest/persistent"
"github.com/gittuf/gittuf/internal/gitinterface"
"github.com/spf13/cobra"
)
type options struct {
target string
attestationsExportPath string
}
func (o *options) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVarP(
&o.target,
"target",
"t",
"",
"commit to export related attestations from",
)
cmd.MarkFlagRequired("target")
cmd.Flags().StringVar(
&o.attestationsExportPath,
"export-attestations",
"",
"path to export attestations used in verification",
)
cmd.MarkFlagRequired("export-attestations")
}
func (o *options) Run(cmd *cobra.Command, args []string) error {
repo, err := gittuf.LoadRepository(".")
if err != nil {
return err
}
hash, err := gitinterface.NewHash(o.target)
if err != nil {
return err
}
return repo.ExportAttestationsForRevision(cmd.Context(), hash, o.attestationsExportPath)
}
func New(_ *persistent.Options) *cobra.Command {
o := &options{}
cmd := &cobra.Command{
Use: "export",
Short: "Export the attestations for a certain revision of the repository",
Long: "Export the attestations related to a certain revision of the repository. This is useful for scenarios where manual inspection of metadata is desired, or for proving compliance with standards such as the SLSA Source Track.",
RunE: o.Run,
DisableAutoGenTag: true,
}
o.AddFlags(cmd)
return cmd
}

View file

@ -774,7 +774,7 @@ func verifyEntry(ctx context.Context, repo *gitinterface.Repository, policy *Sta
// Load the applicable reference authorization and approvals from trusted
// code review systems
slog.Debug("Searching for applicable reference authorizations and code reviews...")
authorizationAttestation, attestationHashes, approverKeyIDs, err := getApproverAttestationAndKeyIDs(ctx, repo, policy, attestationsState, entry)
authorizationAttestation, attestationHashes, approverKeyIDs, err := GetApproverAttestationAndKeyIDs(ctx, repo, policy, attestationsState, entry)
if err != nil {
return nil, err
}
@ -836,7 +836,7 @@ func verifyTagEntry(ctx context.Context, repo *gitinterface.Repository, policy *
return nil, fmt.Errorf("verifying RSL entry failed, tag reference set to unexpected target")
}
authorizationAttestation, attestationHashes, approverKeyIDs, err := getApproverAttestationAndKeyIDs(ctx, repo, policy, attestationsState, entry)
authorizationAttestation, attestationHashes, approverKeyIDs, err := GetApproverAttestationAndKeyIDs(ctx, repo, policy, attestationsState, entry)
if err != nil {
return nil, err
}
@ -848,7 +848,7 @@ func verifyTagEntry(ctx context.Context, repo *gitinterface.Repository, policy *
return attestationHashes, nil
}
func getApproverAttestationAndKeyIDs(ctx context.Context, repo *gitinterface.Repository, policy *State, attestationsState *attestations.Attestations, entry *rsl.ReferenceEntry) (*sslibdsse.Envelope, []gitinterface.Hash, *set.Set[string], error) {
func GetApproverAttestationAndKeyIDs(ctx context.Context, repo *gitinterface.Repository, policy *State, attestationsState *attestations.Attestations, entry *rsl.ReferenceEntry) (*sslibdsse.Envelope, []gitinterface.Hash, *set.Set[string], error) {
if attestationsState == nil {
return nil, nil, nil, nil
}