From cb4237a84451f9a151558d924bba448dd2985eba Mon Sep 17 00:00:00 2001 From: qingliu Date: Sat, 9 May 2026 10:03:48 -0500 Subject: [PATCH] chore(deps): upgrade in-toto-golang and refresh vendored sources - bump github.com/in-toto/in-toto-golang from v0.9.0 to v0.11.0 - update Go toolchain patch version to 1.26.3 in module and image build args - refresh vendored in-toto files and checksums to match the dependency upgrade --- contrib/tkn-image/Dockerfile | 2 +- go.mod | 4 +- go.sum | 4 +- .../in-toto-golang/in_toto/attestations.go | 36 ++- .../in-toto/in-toto-golang/in_toto/keylib.go | 216 +----------------- .../in-toto/in-toto-golang/in_toto/match.go | 8 +- .../in-toto/in-toto-golang/in_toto/model.go | 51 ++++- .../in-toto/in-toto-golang/in_toto/runlib.go | 92 +++++++- .../in_toto/slsa_provenance/common/common.go | 2 +- .../slsa_provenance/v0.1/provenance.go | 4 +- .../slsa_provenance/v0.2/provenance.go | 4 +- .../in_toto/slsa_provenance/v1/provenance.go | 36 ++- .../in-toto/in-toto-golang/in_toto/util.go | 4 +- .../in-toto-golang/in_toto/verifylib.go | 90 ++++++-- vendor/modules.txt | 4 +- 15 files changed, 281 insertions(+), 276 deletions(-) diff --git a/contrib/tkn-image/Dockerfile b/contrib/tkn-image/Dockerfile index c00aa0c696..b2c299b6e5 100644 --- a/contrib/tkn-image/Dockerfile +++ b/contrib/tkn-image/Dockerfile @@ -1,4 +1,4 @@ -ARG GOLANG_VERSION=1.26.2 +ARG GOLANG_VERSION=1.26.3 ARG DEBIAN_VERSION=10 FROM golang:${GOLANG_VERSION} as builder diff --git a/go.mod b/go.mod index aa2dca2c61..0605534042 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/tektoncd/cli -go 1.26.2 +go 1.26.3 require ( github.com/AlecAivazis/survey/v2 v2.3.7 @@ -214,7 +214,7 @@ require ( github.com/hashicorp/vault/api v1.22.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/in-toto/attestation v1.1.2 // indirect - github.com/in-toto/in-toto-golang v0.9.0 // indirect + github.com/in-toto/in-toto-golang v0.11.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index bfebe3a7c2..11e848c8a4 100644 --- a/go.sum +++ b/go.sum @@ -1473,8 +1473,8 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E= github.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM= -github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= -github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= +github.com/in-toto/in-toto-golang v0.11.0 h1:nfidMYBFx+E0lnmX5KUnN2Pdm8zdNKal1ayjJuzzRoA= +github.com/in-toto/in-toto-golang v0.11.0/go.mod h1:u3PjTnwFKjp5a1YCcw8SJg0G+tMeKfVoWsWeFMDCMtw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/attestations.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/attestations.go index 73aafe7e1c..b03871cbf4 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/attestations.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/attestations.go @@ -1,6 +1,7 @@ package in_toto import ( + ita1 "github.com/in-toto/attestation/go/v1" "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" slsa01 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1" slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" @@ -11,6 +12,11 @@ const ( // StatementInTotoV01 is the statement type for the generalized link format // containing statements. This is constant for all predicate types. StatementInTotoV01 = "https://in-toto.io/Statement/v0.1" + + // StatementInTotoV1 is the type URI for ITE-6 v1 Statements. + // This is constant for all predicate types. + StatementInTotoV1 = ita1.StatementTypeUri + // PredicateSPDX represents a SBOM using the SPDX standard. // The SPDX mandates 'spdxVersion' field, so predicate type can omit // version. @@ -22,12 +28,28 @@ const ( ) // Subject describes the set of software artifacts the statement applies to. +// +// Deprecated: This implementation of Subject exists for historical +// compatibility and should not be used. This implementation has been +// superseded by a ResourceDescriptor struct generated from the Protobuf +// definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/v1. +// To generate an ITE-6 v1 Statement subject, use the ResourceDescriptor Go +// APIs provided in https://github.com/in-toto/attestation/tree/main/go/v1. type Subject struct { Name string `json:"name"` Digest common.DigestSet `json:"digest"` } // StatementHeader defines the common fields for all statements +// +// Deprecated: This implementation of StatementHeader exists for historical +// compatibility and should not be used. This implementation has been +// superseded by the Statement struct generated from the Protobuf +// definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/v1. +// To generate an ITE-6 v1 Statement, use the Go APIs provided in +// https://github.com/in-toto/attestation/tree/main/go/v1. type StatementHeader struct { Type string `json:"_type"` PredicateType string `json:"predicateType"` @@ -38,9 +60,16 @@ type StatementHeader struct { Statement binds the attestation to a particular subject and identifies the of the predicate. This struct represents a generic statement. */ +// Deprecated: This implementation of Statement exists for historical +// compatibility and should not be used. This implementation has been +// superseded by the Statement struct generated from the Protobuf +// definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/v1. +// To generate an ITE-6 v1 Statement, use the Go APIs provided in +// https://github.com/in-toto/attestation/tree/main/go/v1. type Statement struct { StatementHeader - // Predicate contains type speficic metadata. + // Predicate contains type specific metadata. Predicate interface{} `json:"predicate"` } @@ -57,6 +86,11 @@ type ProvenanceStatementSLSA02 struct { } // ProvenanceStatementSLSA1 is the definition for an entire provenance statement with SLSA 1.0 predicate. +// +// Deprecated: ProvenanceStatementSLSA1 exists for historical +// compatibility and should not be used. To generate an ITE-6 v1 Statement +// with an ITE-9 Provenance v1 predicate, use the Go APIs provided in +// https://github.com/in-toto/attestation/tree/main/go. type ProvenanceStatementSLSA1 struct { StatementHeader Predicate slsa1.ProvenancePredicate `json:"predicate"` diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/keylib.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/keylib.go index 52429ca44b..a3994c8472 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/keylib.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/keylib.go @@ -1,10 +1,8 @@ package in_toto import ( - "crypto" "crypto/ecdsa" "crypto/ed25519" - "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" @@ -407,7 +405,11 @@ func (k *Key) loadKey(keyObj interface{}, pemData *pem.Block, scheme string, key } case ed25519.PrivateKey: pubKeyBytes := key.Public() - if err := k.setKeyComponents(pubKeyBytes.(ed25519.PublicKey), key, ed25519KeyType, scheme, keyIDHashAlgorithms); err != nil { + publicKey, ok := pubKeyBytes.(ed25519.PublicKey) + if !ok { + return fmt.Errorf("pubKeyBytes must be ed25519.PublicKey") + } + if err := k.setKeyComponents(publicKey, key, ed25519KeyType, scheme, keyIDHashAlgorithms); err != nil { return err } case *ecdsa.PrivateKey: @@ -442,214 +444,6 @@ func (k *Key) loadKey(keyObj interface{}, pemData *pem.Block, scheme string, key return nil } -/* -GenerateSignature will automatically detect the key type and sign the signable data -with the provided key. If everything goes right GenerateSignature will return -a for the key valid signature and err=nil. If something goes wrong it will -return a not initialized signature and an error. Possible errors are: - - - ErrNoPEMBlock - - ErrUnsupportedKeyType - -Currently supported is only one scheme per key. - -Note that in-toto-golang has different requirements to an ecdsa key. -In in-toto-golang we use the string 'ecdsa' as string for the key type. -In the key scheme we use: ecdsa-sha2-nistp256. -*/ -func GenerateSignature(signable []byte, key Key) (Signature, error) { - err := validateKey(key) - if err != nil { - return Signature{}, err - } - var signature Signature - var signatureBuffer []byte - hashMapping := getHashMapping() - // The following switch block is needed for keeping interoperability - // with the securesystemslib and the python implementation - // in which we are storing RSA keys in PEM format, but ed25519 keys hex encoded. - switch key.KeyType { - case rsaKeyType: - // We do not need the pemData here, so we can throw it away via '_' - _, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Private)) - if err != nil { - return Signature{}, err - } - parsedKey, ok := parsedKey.(*rsa.PrivateKey) - if !ok { - return Signature{}, ErrKeyKeyTypeMismatch - } - switch key.Scheme { - case rsassapsssha256Scheme: - hashed := hashToHex(hashMapping["sha256"](), signable) - // We use rand.Reader as secure random source for rsa.SignPSS() - signatureBuffer, err = rsa.SignPSS(rand.Reader, parsedKey.(*rsa.PrivateKey), crypto.SHA256, hashed, - &rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256}) - if err != nil { - return signature, err - } - default: - // supported key schemes will get checked in validateKey - panic("unexpected Error in GenerateSignature function") - } - case ecdsaKeyType: - // We do not need the pemData here, so we can throw it away via '_' - _, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Private)) - if err != nil { - return Signature{}, err - } - parsedKey, ok := parsedKey.(*ecdsa.PrivateKey) - if !ok { - return Signature{}, ErrKeyKeyTypeMismatch - } - curveSize := parsedKey.(*ecdsa.PrivateKey).Curve.Params().BitSize - var hashed []byte - if err := matchEcdsaScheme(curveSize, key.Scheme); err != nil { - return Signature{}, ErrCurveSizeSchemeMismatch - } - // implement https://tools.ietf.org/html/rfc5656#section-6.2.1 - // We determine the curve size and choose the correct hashing - // method based on the curveSize - switch { - case curveSize <= 256: - hashed = hashToHex(hashMapping["sha256"](), signable) - case 256 < curveSize && curveSize <= 384: - hashed = hashToHex(hashMapping["sha384"](), signable) - case curveSize > 384: - hashed = hashToHex(hashMapping["sha512"](), signable) - default: - panic("unexpected Error in GenerateSignature function") - } - // Generate the ecdsa signature on the same way, as we do in the securesystemslib - // We are marshalling the ecdsaSignature struct as ASN.1 INTEGER SEQUENCES - // into an ASN.1 Object. - signatureBuffer, err = ecdsa.SignASN1(rand.Reader, parsedKey.(*ecdsa.PrivateKey), hashed[:]) - if err != nil { - return signature, err - } - case ed25519KeyType: - // We do not need a scheme switch here, because ed25519 - // only consist of sha256 and curve25519. - privateHex, err := hex.DecodeString(key.KeyVal.Private) - if err != nil { - return signature, ErrInvalidHexString - } - // Note: We can directly use the key for signing and do not - // need to use ed25519.NewKeyFromSeed(). - signatureBuffer = ed25519.Sign(privateHex, signable) - default: - // We should never get here, because we call validateKey in the first - // line of the function. - panic("unexpected Error in GenerateSignature function") - } - signature.Sig = hex.EncodeToString(signatureBuffer) - signature.KeyID = key.KeyID - signature.Certificate = key.KeyVal.Certificate - return signature, nil -} - -/* -VerifySignature will verify unverified byte data via a passed key and signature. -Supported key types are: - - - rsa - - ed25519 - - ecdsa - -When encountering an RSA key, VerifySignature will decode the PEM block in the key -and will call rsa.VerifyPSS() for verifying the RSA signature. -When encountering an ed25519 key, VerifySignature will decode the hex string encoded -public key and will use ed25519.Verify() for verifying the ed25519 signature. -When the given key is an ecdsa key, VerifySignature will unmarshall the ASN1 object -and will use the retrieved ecdsa components 'r' and 's' for verifying the signature. -On success it will return nil. In case of an unsupported key type or any other error -it will return an error. - -Note that in-toto-golang has different requirements to an ecdsa key. -In in-toto-golang we use the string 'ecdsa' as string for the key type. -In the key scheme we use: ecdsa-sha2-nistp256. -*/ -func VerifySignature(key Key, sig Signature, unverified []byte) error { - err := validateKey(key) - if err != nil { - return err - } - sigBytes, err := hex.DecodeString(sig.Sig) - if err != nil { - return err - } - hashMapping := getHashMapping() - switch key.KeyType { - case rsaKeyType: - // We do not need the pemData here, so we can throw it away via '_' - _, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Public)) - if err != nil { - return err - } - parsedKey, ok := parsedKey.(*rsa.PublicKey) - if !ok { - return ErrKeyKeyTypeMismatch - } - switch key.Scheme { - case rsassapsssha256Scheme: - hashed := hashToHex(hashMapping["sha256"](), unverified) - err = rsa.VerifyPSS(parsedKey.(*rsa.PublicKey), crypto.SHA256, hashed, sigBytes, &rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256}) - if err != nil { - return fmt.Errorf("%w: %s", ErrInvalidSignature, err) - } - default: - // supported key schemes will get checked in validateKey - panic("unexpected Error in VerifySignature function") - } - case ecdsaKeyType: - // We do not need the pemData here, so we can throw it away via '_' - _, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Public)) - if err != nil { - return err - } - parsedKey, ok := parsedKey.(*ecdsa.PublicKey) - if !ok { - return ErrKeyKeyTypeMismatch - } - curveSize := parsedKey.(*ecdsa.PublicKey).Curve.Params().BitSize - var hashed []byte - if err := matchEcdsaScheme(curveSize, key.Scheme); err != nil { - return ErrCurveSizeSchemeMismatch - } - // implement https://tools.ietf.org/html/rfc5656#section-6.2.1 - // We determine the curve size and choose the correct hashing - // method based on the curveSize - switch { - case curveSize <= 256: - hashed = hashToHex(hashMapping["sha256"](), unverified) - case 256 < curveSize && curveSize <= 384: - hashed = hashToHex(hashMapping["sha384"](), unverified) - case curveSize > 384: - hashed = hashToHex(hashMapping["sha512"](), unverified) - default: - panic("unexpected Error in VerifySignature function") - } - if ok := ecdsa.VerifyASN1(parsedKey.(*ecdsa.PublicKey), hashed[:], sigBytes); !ok { - return ErrInvalidSignature - } - case ed25519KeyType: - // We do not need a scheme switch here, because ed25519 - // only consist of sha256 and curve25519. - pubHex, err := hex.DecodeString(key.KeyVal.Public) - if err != nil { - return ErrInvalidHexString - } - if ok := ed25519.Verify(pubHex, unverified, sigBytes); !ok { - return fmt.Errorf("%w: ed25519", ErrInvalidSignature) - } - default: - // We should never get here, because we call validateKey in the first - // line of the function. - panic("unexpected Error in VerifySignature function") - } - return nil -} - /* VerifyCertificateTrust verifies that the certificate has a chain of trust to a root in rootCertPool, possibly using any intermediates in diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/match.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/match.go index 52373aa75f..a581d00f71 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/match.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/match.go @@ -22,8 +22,12 @@ var errBadPattern = errors.New("syntax error in pattern") // term: // '*' matches any sequence of non-/ characters // '?' matches any single non-/ character -// '[' [ '^' ] { character-range } ']' +// '[' [ '!' ] { character-range } ']' // character class (must be non-empty) +// +// NOTE: Only '!' is supported for character class negation, not '^'. This is to +// ensure compatibility with in-toto-python. +// // c matches character c (c != '*', '?', '\\', '[') // '\\' c matches character c // @@ -141,7 +145,7 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) { chunk = chunk[1:] // possibly negated negated := false - if len(chunk) > 0 && chunk[0] == '^' { + if len(chunk) > 0 && chunk[0] == '!' { negated = true chunk = chunk[1:] } diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/model.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/model.go index f56b784ea0..4081535656 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/model.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/model.go @@ -1,9 +1,11 @@ package in_toto import ( + "context" "crypto/ecdsa" "crypto/rsa" "crypto/x509" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -18,6 +20,8 @@ import ( "github.com/secure-systems-lab/go-securesystemslib/dsse" ) +type HashObj = map[string]string + /* KeyVal contains the actual values of a key, as opposed to key metadata such as a key identifier or key type. For RSA keys, the key value is a pair of public @@ -337,8 +341,8 @@ writing to disk. type Link struct { Type string `json:"_type"` Name string `json:"name"` - Materials map[string]interface{} `json:"materials"` - Products map[string]interface{} `json:"products"` + Materials map[string]HashObj `json:"materials"` + Products map[string]HashObj `json:"products"` ByProducts map[string]interface{} `json:"byproducts"` Command []string `json:"command"` Environment map[string]interface{} `json:"environment"` @@ -347,12 +351,18 @@ type Link struct { /* validateArtifacts is a general function used to validate products and materials. */ -func validateArtifacts(artifacts map[string]interface{}) error { +func validateArtifacts(artifacts map[string]HashObj) error { for artifactName, artifact := range artifacts { artifactValue := reflect.ValueOf(artifact).MapRange() for artifactValue.Next() { - value := artifactValue.Value().Interface().(string) - hashType := artifactValue.Key().Interface().(string) + value, ok := artifactValue.Value().Interface().(string) + if !ok { + return fmt.Errorf("value is not string") + } + hashType, ok := artifactValue.Key().Interface().(string) + if !ok { + return fmt.Errorf("hash type is not string") + } if err := validateHexString(value); err != nil { return fmt.Errorf("in artifact '%s', %s hash value: %s", artifactName, hashType, err.Error()) @@ -896,14 +906,26 @@ func (mb *Metablock) VerifySignature(key Key) error { return err } - dataCanonical, err := mb.GetSignableRepresentation() + verifier, err := getSignerVerifierFromKey(key) if err != nil { return err } - if err := VerifySignature(key, sig, dataCanonical); err != nil { + payload, err := mb.GetSignableRepresentation() + if err != nil { return err } + + sigBytes, err := hex.DecodeString(sig.Sig) + if err != nil { + return err + } + + err = verifier.Verify(context.Background(), payload, sigBytes) + if err != nil { + return err + } + return nil } @@ -951,17 +973,26 @@ field as provided. It returns an error if the Signed object cannot be canonicalized, or if the key is invalid or not supported. */ func (mb *Metablock) Sign(key Key) error { + signer, err := getSignerVerifierFromKey(key) + if err != nil { + return err + } - dataCanonical, err := mb.GetSignableRepresentation() + payload, err := mb.GetSignableRepresentation() if err != nil { return err } - newSignature, err := GenerateSignature(dataCanonical, key) + signature, err := signer.Sign(context.Background(), payload) if err != nil { return err } - mb.Signatures = append(mb.Signatures, newSignature) + mb.Signatures = append(mb.Signatures, Signature{ + KeyID: key.KeyID, + Sig: hex.EncodeToString(signature), + Certificate: key.KeyVal.Certificate, + }) + return nil } diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/runlib.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/runlib.go index f0a55d8219..4cc0321667 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/runlib.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/runlib.go @@ -41,11 +41,11 @@ value is the error. NOTE: For cross-platform consistency Windows-style line separators (CRLF) are normalized to Unix-style line separators (LF) before hashing file contents. */ -func RecordArtifact(path string, hashAlgorithms []string, lineNormalization bool) (map[string]interface{}, error) { +func RecordArtifact(path string, hashAlgorithms []string, lineNormalization bool) (HashObj, error) { supportedHashMappings := getHashMapping() // Read file from passed path contents, err := os.ReadFile(path) - hashedContentsMap := make(map[string]interface{}) + hashedContentsMap := make(HashObj) if err != nil { return nil, err } @@ -92,12 +92,22 @@ the following format: If recording an artifact fails the first return value is nil and the second return value is the error. */ -func RecordArtifacts(paths []string, hashAlgorithms []string, gitignorePatterns []string, lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (evalArtifacts map[string]interface{}, err error) { +func RecordArtifacts(paths []string, hashAlgorithms []string, gitignorePatterns []string, lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (evalArtifacts map[string]HashObj, err error) { // Make sure to initialize a fresh hashset for every RecordArtifacts call visitedSymlinks = NewSet() - evalArtifacts, err = recordArtifacts(paths, hashAlgorithms, gitignorePatterns, lStripPaths, lineNormalization, followSymlinkDirs) - // pass result and error through - return evalArtifacts, err + evalArtifactsUnnormalized, err := recordArtifacts(paths, hashAlgorithms, gitignorePatterns, lStripPaths, lineNormalization, followSymlinkDirs) + if err != nil { + return nil, err + } + + // Normalize all paths in evalArtifactsUnnormalized. + evalArtifacts = make(map[string]HashObj, len(evalArtifactsUnnormalized)) + for key, value := range evalArtifactsUnnormalized { + // Convert windows filepath to unix filepath. + evalArtifacts[filepath.ToSlash(key)] = value + } + + return evalArtifacts, nil } /* @@ -118,8 +128,8 @@ the following format: If recording an artifact fails the first return value is nil and the second return value is the error. */ -func recordArtifacts(paths []string, hashAlgorithms []string, gitignorePatterns []string, lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (map[string]interface{}, error) { - artifacts := make(map[string]interface{}) +func recordArtifacts(paths []string, hashAlgorithms []string, gitignorePatterns []string, lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (map[string]HashObj, error) { + artifacts := make(map[string]HashObj) for _, path := range paths { err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { @@ -380,7 +390,7 @@ func InTotoRecordStart(name string, materialPaths []string, key Key, hashAlgorit Type: "link", Name: name, Materials: materials, - Products: map[string]interface{}{}, + Products: map[string]HashObj{}, ByProducts: map[string]interface{}{}, Command: []string{}, Environment: map[string]interface{}{}, @@ -413,9 +423,9 @@ func InTotoRecordStart(name string, materialPaths []string, key Key, hashAlgorit } /* -InTotoRecordStop ends the creation of a metatadata link file created by +InTotoRecordStop ends the creation of a metadata link file created by InTotoRecordStart. InTotoRecordStop takes in a signed unfinished link metablock -created by InTotoRecordStart and records the hashes of any products creted by +created by InTotoRecordStart and records the hashes of any products created by commands run between InTotoRecordStart and InTotoRecordStop. The resultant finished link metablock is then signed by the provided key and returned. */ @@ -460,3 +470,63 @@ func InTotoRecordStop(prelimLinkEnv Metadata, productPaths []string, key Key, ha return linkMb, nil } + +/* +InTotoMatchProducts checks if local artifacts match products in passed link. + +NOTE: Does not check integrity or authenticity of passed link! +*/ +func InTotoMatchProducts(link *Link, paths []string, hashAlgorithms []string, excludePatterns []string, lstripPaths []string) ([]string, []string, []string, error) { + if len(paths) == 0 { + paths = append(paths, ".") + } + + artifacts, err := RecordArtifacts(paths, hashAlgorithms, excludePatterns, lstripPaths, false, false) + if err != nil { + return nil, nil, nil, err + } + + artifactNames := []string{} + for name := range artifacts { + artifactNames = append(artifactNames, name) + } + artifactsSet := NewSet(artifactNames...) + + productNames := []string{} + for name := range link.Products { + productNames = append(productNames, name) + } + productsSet := NewSet(productNames...) + + onlyInProductsSet := productsSet.Difference(artifactsSet) + onlyInProducts := []string{} + for name := range onlyInProductsSet { + onlyInProducts = append(onlyInProducts, name) + } + + notInProductsSet := artifactsSet.Difference(productsSet) + notInProducts := []string{} + for name := range notInProductsSet { + notInProducts = append(notInProducts, name) + } + + inBothSet := artifactsSet.Intersection(productsSet) + differ := []string{} + for name := range inBothSet { + linkHashes := HashObj{} + for alg, val := range link.Products[name] { + linkHashes[alg] = val + } + + artifactHashes := HashObj{} + for alg, val := range artifacts[name] { + artifactHashes[alg] = val + } + + if !reflect.DeepEqual(linkHashes, artifactHashes) { + differ = append(differ, name) + } + } + + return onlyInProducts, notInProducts, differ, nil +} diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common/common.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common/common.go index a45a454634..ab6763e855 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common/common.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common/common.go @@ -4,7 +4,7 @@ package common // algorithm name to lowercase hex-encoded value. type DigestSet map[string]string -// ProvenanceBuilder idenfifies the entity that executed the build steps. +// ProvenanceBuilder identifies the entity that executed the build steps. type ProvenanceBuilder struct { ID string `json:"id"` } diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1/provenance.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1/provenance.go index 5978e9229d..4470723b8d 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1/provenance.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1/provenance.go @@ -40,8 +40,8 @@ type ProvenanceMetadata struct { Reproducible bool `json:"reproducible"` } -// ProvenanceComplete indicates wheter the claims in build/recipe are complete. -// For in depth information refer to the specifictaion: +// ProvenanceComplete indicates whether the claims in build/recipe are complete. +// For in depth information refer to the specification: // https://github.com/in-toto/attestation/blob/v0.1.0/spec/predicates/provenance.md type ProvenanceComplete struct { Arguments bool `json:"arguments"` diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2/provenance.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2/provenance.go index 40416e29a8..3efbb51e81 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2/provenance.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2/provenance.go @@ -127,8 +127,8 @@ type ProvenanceMetadata struct { Reproducible bool `json:"reproducible"` } -// ProvenanceComplete indicates wheter the claims in build/recipe are complete. -// For in depth information refer to the specifictaion: +// ProvenanceComplete indicates whether the claims in build/recipe are complete. +// For in depth information refer to the specification: // https://github.com/in-toto/attestation/blob/v0.1.0/spec/predicates/provenance.md type ProvenanceComplete struct { // Parameters if true, means the builder claims that [ProvenanceInvocation.Parameters] is diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1/provenance.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1/provenance.go index e849731dce..5a26445c5c 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1/provenance.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1/provenance.go @@ -12,6 +12,12 @@ const ( ) // ProvenancePredicate is the provenance predicate definition. +// +// Deprecated: ProvenancePredicate exists for historical compatibility +// and should not be used. This implementation has been superseded by the +// Provenance struct generated from the Protobuf definition provided +// by the in-toto Attestation Framework. +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/predicates/provenance/v1. type ProvenancePredicate struct { // The BuildDefinition describes all of the inputs to the build. The // accuracy and completeness are implied by runDetails.builder.id. @@ -25,6 +31,11 @@ type ProvenancePredicate struct { } // ProvenanceBuildDefinition describes the inputs to the build. +// +// Deprecated: ProvenanceBuildDefinition exists for historical compatibility +// and should not be used. This implementation has been superseded by the +// BuildDefinition struct generated from the Protobuf definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/predicates/provenance/v1. type ProvenanceBuildDefinition struct { // Identifies the template for how to perform the build and interpret the // parameters and dependencies. @@ -37,7 +48,7 @@ type ProvenanceBuildDefinition struct { // The parameters that are under external control, such as those set by a // user or tenant of the build system. They MUST be complete at SLSA Build - // L3, meaning that that there is no additional mechanism for an external + // L3, meaning that there is no additional mechanism for an external // party to influence the build. (At lower SLSA Build levels, the // completeness MAY be best effort.) @@ -66,6 +77,11 @@ type ProvenanceBuildDefinition struct { // ProvenanceRunDetails includes details specific to a particular execution of a // build. +// +// Deprecated: ProvenanceRunDetails exists for historical compatibility +// and should not be used. This implementation has been superseded by the +// RunDetails struct generated from the Protobuf definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/predicates/provenance/v1. type ProvenanceRunDetails struct { // Identifies the entity that executed the invocation, which is trusted to // have correctly performed the operation and populated this provenance. @@ -92,6 +108,12 @@ type ProvenanceRunDetails struct { // ResourceDescriptor describes a particular software artifact or resource // (mutable or immutable). // See https://github.com/in-toto/attestation/blob/main/spec/v1.0/resource_descriptor.md +// +// Deprecated: This implementation of ResoureDescriptor exists for +// historical compatibility and should not be used. This struct has been +// superseded by the ResourceDescriptor struct generated from the Protobuf +// definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/v1. type ResourceDescriptor struct { // A URI used to identify the resource or artifact globally. This field is // REQUIRED unless either digest or content is set. @@ -123,6 +145,11 @@ type ResourceDescriptor struct { // Builder represents the transitive closure of all the entities that are, by // necessity, trusted to faithfully run the build and record the provenance. +// +// Deprecated: This implementation of Builder exists for historical +// compatibility and should not be used. This implementation has been +// superseded by the Builder struct generated from the Protobuf definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/predicates/provenance/v1. type Builder struct { // URI indicating the transitive closure of the trusted builder. ID string `json:"id"` @@ -136,12 +163,17 @@ type Builder struct { BuilderDependencies []ResourceDescriptor `json:"builderDependencies,omitempty"` } +// Deprecated: This implementation of BuildMetadata exists for historical +// compatibility and should not be used. This implementation has been +// superseded by the BuildMetadata struct generated from the Protobuf +// definition in +// https://github.com/in-toto/attestation/tree/main/protos/in_toto_attestation/predicates/provenance/v1. type BuildMetadata struct { // Identifies this particular build invocation, which can be useful for // finding associated logs or other ad-hoc analysis. The exact meaning and // format is defined by builder.id; by default it is treated as opaque and // case-sensitive. The value SHOULD be globally unique. - InvocationID string `json:"invocationID,omitempty"` + InvocationID string `json:"invocationId,omitempty"` // The timestamp of when the build started. StartedOn *time.Time `json:"startedOn,omitempty"` diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/util.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/util.go index 5c36dede13..01421afebf 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/util.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/util.go @@ -121,10 +121,10 @@ func (s Set) Slice() []string { } /* -InterfaceKeyStrings returns string keys of passed interface{} map in an +artifactsDictKeyStrings returns string keys of passed HashObj map in an unordered string slice. */ -func InterfaceKeyStrings(m map[string]interface{}) []string { +func artifactsDictKeyStrings(m map[string]HashObj) []string { res := make([]string, len(m)) i := 0 for k := range m { diff --git a/vendor/github.com/in-toto/in-toto-golang/in_toto/verifylib.go b/vendor/github.com/in-toto/in-toto-golang/in_toto/verifylib.go index 2564bd47eb..de9dfa7e64 100644 --- a/vendor/github.com/in-toto/in-toto-golang/in_toto/verifylib.go +++ b/vendor/github.com/in-toto/in-toto-golang/in_toto/verifylib.go @@ -59,7 +59,11 @@ func RunInspections(layout Layout, runDir string, lineNormalization bool, useDSS return nil, err } - retVal := linkEnv.GetPayload().(Link).ByProducts["return-value"] + link, ok := linkEnv.GetPayload().(Link) + if !ok { + return nil, fmt.Errorf("invalid metadata") + } + retVal := link.ByProducts["return-value"] if retVal != float64(0) { return nil, fmt.Errorf("inspection command '%s' of inspection '%s'"+ " returned a non-zero value: %d", inspection.Run, inspection.Name, @@ -80,7 +84,7 @@ func RunInspections(layout Layout, runDir string, lineNormalization bool, useDSS // verifyMatchRule is a helper function to process artifact rules of // type MATCH. See VerifyArtifacts for more details. func verifyMatchRule(ruleData map[string]string, - srcArtifacts map[string]interface{}, srcArtifactQueue Set, + srcArtifacts map[string]HashObj, srcArtifactQueue Set, itemsMetadata map[string]Metadata) Set { consumed := NewSet() // Get destination link metadata @@ -91,13 +95,19 @@ func verifyMatchRule(ruleData map[string]string, return consumed } + dstLink, ok := dstLinkEnv.GetPayload().(Link) + if !ok { + fmt.Printf("invalid metadata") + return consumed + } + // Get artifacts from destination link metadata - var dstArtifacts map[string]interface{} + var dstArtifacts map[string]HashObj switch ruleData["dstType"] { case "materials": - dstArtifacts = dstLinkEnv.GetPayload().(Link).Materials + dstArtifacts = dstLink.Materials case "products": - dstArtifacts = dstLinkEnv.GetPayload().(Link).Products + dstArtifacts = dstLink.Products } // cleanup paths in pattern and artifact maps @@ -216,18 +226,22 @@ func VerifyArtifacts(items []interface{}, // Create shortcuts to materials and products (including hashes) reported // by the item's link, required to verify "match" rules - materials := srcLinkEnv.GetPayload().(Link).Materials - products := srcLinkEnv.GetPayload().(Link).Products + link, ok := srcLinkEnv.GetPayload().(Link) + if !ok { + return fmt.Errorf("invalid metadata") + } + materials := link.Materials + products := link.Products // All other rules only require the material or product paths (without // hashes). We extract them from the corresponding maps and store them as // sets for convenience in further processing materialPaths := NewSet() - for _, p := range InterfaceKeyStrings(materials) { + for _, p := range artifactsDictKeyStrings(materials) { materialPaths.Add(path.Clean(p)) } productPaths := NewSet() - for _, p := range InterfaceKeyStrings(products) { + for _, p := range artifactsDictKeyStrings(products) { productPaths.Add(path.Clean(p)) } @@ -269,17 +283,24 @@ func VerifyArtifacts(items []interface{}, // TODO: Add logging library (see in-toto/in-toto-golang#4) // fmt.Printf("%s...\n", verificationData["srcType"]) - rules := verificationData["rules"].([][]string) - artifacts := verificationData["artifacts"].(map[string]interface{}) - + rules, ok := verificationData["rules"].([][]string) + if !ok { + return fmt.Errorf(`rules must be of type [][]string`) + } + artifacts, ok := verificationData["artifacts"].(map[string]HashObj) + if !ok { + return fmt.Errorf(`artifacts must be of type map[string]HashObj`) + } // Use artifacts (without hashes) as base queue. Each rule only operates // on artifacts in that queue. If a rule consumes an artifact (i.e. can // be applied successfully), the artifact is removed from the queue. By // applying a DISALLOW rule eventually, verification may return an error, // if the rule matches any artifacts in the queue that should have been // consumed earlier. - queue := verificationData["artifactPaths"].(Set) - + queue, ok := verificationData["artifactPaths"].(Set) + if !ok { + return fmt.Errorf(`queue must be of type Set`) + } // TODO: Add logging library (see in-toto/in-toto-golang#4) // fmt.Printf("Initial state\nMaterials: %s\nProducts: %s\nQueue: %s\n\n", // materialPaths.Slice(), productPaths.Slice(), queue.Slice()) @@ -398,10 +419,16 @@ func ReduceStepsMetadata(layout Layout, // threshold requires, but not all of them are equal? Right now we would // also error. for keyID, linkEnv := range linksPerStep { - if !reflect.DeepEqual(linkEnv.GetPayload().(Link).Materials, - referenceLinkEnv.GetPayload().(Link).Materials) || - !reflect.DeepEqual(linkEnv.GetPayload().(Link).Products, - referenceLinkEnv.GetPayload().(Link).Products) { + link, ok := linkEnv.GetPayload().(Link) + if !ok { + return nil, fmt.Errorf("invalid metadata") + } + refLink, ok := referenceLinkEnv.GetPayload().(Link) + if !ok { + return nil, fmt.Errorf("invalid metadata") + } + if !reflect.DeepEqual(link.Materials, refLink.Materials) || + !reflect.DeepEqual(link.Products, refLink.Products) { return nil, fmt.Errorf("link '%s' and '%s' have different"+ " artifacts", fmt.Sprintf(LinkNameFormat, step.Name, referenceKeyID), @@ -432,8 +459,13 @@ func VerifyStepCommandAlignment(layout Layout, } for signerKeyID, linkEnv := range linksPerStep { + link, ok := linkEnv.GetPayload().(Link) + if !ok { + fmt.Printf("invalid metadata") + return + } expectedCommandS := strings.Join(step.ExpectedCommand, " ") - executedCommandS := strings.Join(linkEnv.GetPayload().(Link).Command, " ") + executedCommandS := strings.Join(link.Command, " ") if expectedCommandS != executedCommandS { linkName := fmt.Sprintf(LinkNameFormat, step.Name, signerKeyID) @@ -708,16 +740,24 @@ func GetSummaryLink(layout Layout, stepsMetadataReduced map[string]Metadata, firstStepLink := stepsMetadataReduced[layout.Steps[0].Name] lastStepLink := stepsMetadataReduced[layout.Steps[len(layout.Steps)-1].Name] - summaryLink.Materials = firstStepLink.GetPayload().(Link).Materials + firstStepPayloadLink, ok := firstStepLink.GetPayload().(Link) + if !ok { + return nil, fmt.Errorf("invalid metadata") + } + summaryLink.Materials = firstStepPayloadLink.Materials summaryLink.Name = stepName - summaryLink.Type = firstStepLink.GetPayload().(Link).Type + summaryLink.Type = firstStepPayloadLink.Type - summaryLink.Products = lastStepLink.GetPayload().(Link).Products - summaryLink.ByProducts = lastStepLink.GetPayload().(Link).ByProducts + lastStepPayloadLink, ok := lastStepLink.GetPayload().(Link) + if !ok { + return nil, fmt.Errorf("invalid metadata") + } + summaryLink.Products = lastStepPayloadLink.Products + summaryLink.ByProducts = lastStepPayloadLink.ByProducts // Using the last command of the sublayout as the command // of the summary link can be misleading. Is it necessary to // include all the commands executed as part of sublayout? - summaryLink.Command = lastStepLink.GetPayload().(Link).Command + summaryLink.Command = lastStepPayloadLink.Command } if useDSSE { @@ -845,7 +885,7 @@ the in-toto specification. It requires the metadata of the root layout, a map that contains public keys to verify the root layout signatures, a path to a directory from where it can load link metadata files, which are treated as signed evidence for the steps defined in the layout, a step name, and a -paramater dictionary used for parameter substitution. The step name only +parameter dictionary used for parameter substitution. The step name only matters for sublayouts, where it's important to associate the summary of that step with a unique name. The verification routine is as follows: diff --git a/vendor/modules.txt b/vendor/modules.txt index f3a49f1f6a..85bf6c261e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1015,8 +1015,8 @@ github.com/imdario/mergo # github.com/in-toto/attestation v1.1.2 ## explicit; go 1.22 github.com/in-toto/attestation/go/v1 -# github.com/in-toto/in-toto-golang v0.9.0 -## explicit; go 1.20 +# github.com/in-toto/in-toto-golang v0.11.0 +## explicit; go 1.24.0 github.com/in-toto/in-toto-golang/in_toto github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1