Files
Packer-Cn/command/verify_attestation.go
fb8fa2b0fe [COMPLIANCE] Add/Update Copyright Headers (#13699)
* [COMPLIANCE] Add/Update Copyright Headers

* make generate update

* make generate

---------

Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: sanya <[email protected]>
Co-authored-by: Sanya <[email protected]>
2026-09-15 17:10:54 +05:30

156 lines
5.9 KiB
Go

// Copyright IBM Corp. 2024, 2026
// SPDX-License-Identifier: BUSL-1.1
package command
import (
"context"
"strings"
internalattestation "github.com/hashicorp/packer/internal/attestation"
"github.com/posener/complete"
)
type VerifyAttestationCommand struct {
Meta
}
type VerifyAttestationArgs struct {
AttestationPath string
SigningMode string
Key string
Verifier string
PredicateType string
BuilderID string
SourceURI string
ArtifactPath string
TrustedRootPath string
KeylessIdentity string
KeylessOIDCIssuer string
SigstoreBundlePath string
RequireTransparencyLog bool
RequireObserverTimestamp bool
}
func (c *VerifyAttestationCommand) Run(args []string) int {
ctx, cleanup := handleTermInterrupt(c.Ui)
defer cleanup()
cfg, ret := c.ParseArgs(args)
if ret != 0 {
return ret
}
return c.RunContext(ctx, cfg)
}
func (c *VerifyAttestationCommand) ParseArgs(args []string) (*VerifyAttestationArgs, int) {
var cfg VerifyAttestationArgs
flags := c.FlagSet("verify-attestation")
flags.Usage = func() { c.Ui.Say(c.Help()) }
flags.StringVar(&cfg.SigningMode, "signing-mode", "", "Signing mode used for the attestation")
flags.StringVar(&cfg.Key, "key", "", "PEM path or KMS/Vault URI")
flags.StringVar(&cfg.Verifier, "verifier", "", "PEM verifier path")
flags.StringVar(&cfg.PredicateType, "predicate-type", "", "Expected attestation predicate type")
flags.StringVar(&cfg.BuilderID, "builder-id", "", "Expected SLSA builder ID")
flags.StringVar(&cfg.SourceURI, "source-uri", "", "Expected resolved source URI")
flags.StringVar(&cfg.ArtifactPath, "artifact", "", "Artifact path to match against attestation subjects")
flags.StringVar(&cfg.TrustedRootPath, "trusted-root-path", "", "Optional Sigstore trusted-root JSON file")
flags.StringVar(&cfg.KeylessIdentity, "keyless-identity", "", "Expected keyless signing identity")
flags.StringVar(&cfg.KeylessOIDCIssuer, "keyless-oidc-issuer", "", "Expected keyless OIDC issuer")
flags.StringVar(&cfg.SigstoreBundlePath, "bundle", "", "Optional Sigstore bundle JSON file for Rekor or timestamp verification")
flags.BoolVar(&cfg.RequireTransparencyLog, "require-rekor", false, "Require Rekor transparency log verification using the Sigstore bundle")
flags.BoolVar(&cfg.RequireObserverTimestamp, "require-timestamp", false, "Require a trusted observer timestamp from Rekor integrated time or RFC3161 timestamp evidence")
if err := flags.Parse(args); err != nil {
return &cfg, 1
}
args = flags.Args()
if len(args) != 1 {
flags.Usage()
return &cfg, 1
}
cfg.AttestationPath = args[0]
return &cfg, 0
}
func (c *VerifyAttestationCommand) RunContext(ctx context.Context, cfg *VerifyAttestationArgs) int {
_, err := internalattestation.VerifyAttestationFile(ctx, cfg.AttestationPath, internalattestation.BackendConfig{
Mode: cfg.SigningMode,
SignerRef: cfg.Key,
VerifierRef: cfg.Verifier,
TrustedRootPath: cfg.TrustedRootPath,
KeylessIdentity: cfg.KeylessIdentity,
KeylessOIDCIssuer: cfg.KeylessOIDCIssuer,
}, internalattestation.VerificationPolicy{
PredicateType: cfg.PredicateType,
BuilderID: cfg.BuilderID,
SourceURI: cfg.SourceURI,
ArtifactPath: cfg.ArtifactPath,
SigstoreBundlePath: cfg.SigstoreBundlePath,
RequireTransparencyLog: cfg.RequireTransparencyLog,
RequireObserverTimestamp: cfg.RequireObserverTimestamp,
})
if err != nil {
c.Ui.Error(err.Error())
return 1
}
c.Ui.Say("Attestation verified.")
return 0
}
func (*VerifyAttestationCommand) Help() string {
helpText := `
Usage: packer verify-attestation [options] ATTESTATION
Verifies a signed DSSE attestation and optionally enforces policy checks
such as predicate type, builder identity, source URI, and subject digest.
Options:
-signing-mode=MODE Signing mode: key, kms, keyless. Auto-detected when possible.
-key=PATH_OR_URI PEM key path or KMS/Vault URI used for verification when no verifier is supplied.
-verifier=PATH PEM verifier path.
-predicate-type=TYPE Expected attestation predicate type.
-builder-id=ID Expected SLSA builder ID.
-source-uri=URI Expected resolved source URI.
-artifact=PATH Artifact path to match against attestation subjects.
-trusted-root-path=PATH Optional Sigstore trusted-root JSON for keyless verification.
-keyless-identity=IDENTITY Expected keyless signing identity.
-keyless-oidc-issuer=ISSUER Expected keyless OIDC issuer.
-bundle=PATH Optional Sigstore bundle JSON for Rekor or timestamp verification.
-require-rekor Require Rekor transparency log verification from the bundle.
-require-timestamp Require a trusted observer timestamp from Rekor integrated time or RFC3161 evidence.
`
return strings.TrimSpace(helpText)
}
func (*VerifyAttestationCommand) Synopsis() string {
return "verify a signed attestation against policy"
}
func (*VerifyAttestationCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictNothing
}
func (*VerifyAttestationCommand) AutocompleteFlags() complete.Flags {
return complete.Flags{
"-signing-mode": complete.PredictNothing,
"-key": complete.PredictNothing,
"-verifier": complete.PredictNothing,
"-predicate-type": complete.PredictNothing,
"-builder-id": complete.PredictNothing,
"-source-uri": complete.PredictNothing,
"-artifact": complete.PredictNothing,
"-trusted-root-path": complete.PredictNothing,
"-keyless-identity": complete.PredictNothing,
"-keyless-oidc-issuer": complete.PredictNothing,
"-bundle": complete.PredictNothing,
"-require-rekor": complete.PredictNothing,
"-require-timestamp": complete.PredictNothing,
}
}