mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
As discussed in opentofu/opentofu#2656, this consolidates the two concerns of the PackageAuthentication interface into a single function that deals both with package authentication _and_ with reporting all of the package hashes that were used to make the authentication decision. This means that any .zip archive that OpenTofu directly verifies during installation can now have its hash recorded in the dependency lock file even if that package didn't come from the provider's origin registry, which is beneficial when the first installation of a provider comes from a secondary ("mirror") source because it creates an additional hook by which that dependency lock file entry can be "upgraded" to be complete in a future "tofu init" run against the origin registry, or by the "tofu providers lock" command. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
84 lines
3.3 KiB
Go
84 lines
3.3 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package getproviders
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
|
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
|
)
|
|
|
|
// This file contains only some helper functions for the tests in package_authentication_test.go.
|
|
// There are not actually any tests in here.
|
|
//
|
|
// We use these helpers sparingly to minimize the number of opaque-to-humans artifacts
|
|
// we need to include as hard-coded constants, instead deriving the opaque artifacts from
|
|
// more human-accessible artifacts where possible. However, we must be careful to make sure
|
|
// that our use of these helpers does not cause a test to effectively "cheat" by creating
|
|
// a situation that could not possibly occur in realistic use.
|
|
|
|
// pgpTestEntity returns a freshly-generated [openpgp.Entity] with the given name and
|
|
// a hard-coded comment and fake email address. The private key is generated randomly
|
|
// on request.
|
|
//
|
|
// We generate keys on the fly, rather than hard-coding them, to avoid dealiing with the
|
|
// noise generated by zealous security scanners that get (justifyably) nervous when
|
|
// they find a private key included directly in the source code of a codebase. However,
|
|
// this just-in-time generation does unfortunately come at a small performance cost,
|
|
// so tests should avoid calling this from inside a loop.
|
|
func pgpTestEntity(t *testing.T, name string) *openpgp.Entity {
|
|
t.Helper()
|
|
|
|
entity, err := openpgp.NewEntity(name, "throwaway key used only for testing", "testing@invalid", nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to generate a PGP key for testing: %s", err)
|
|
}
|
|
return entity
|
|
}
|
|
|
|
// pgpPublicKeyForTestEntity returns an "armored" representation of the public key
|
|
// of the given entity, as we'd expect to obtain from an OpenTofu provider
|
|
// registry when performing GPG verification of a provider release, and
|
|
// a hex representation of the key's ID that we'd use to report the use of
|
|
// the key in a successful authentication result.
|
|
func pgpPublicKeyForTestEntity(t *testing.T, entity *openpgp.Entity) ([]byte, string) {
|
|
// The "armored" representation, described in RFC 4880 chapter 6,
|
|
// is a PEM-like ASCII-only representation of key data. Therefore
|
|
// we have two layers to deal with here: the armor encoding, and
|
|
// the inner raw representation of the public key.
|
|
|
|
var buf bytes.Buffer
|
|
w, err := armor.Encode(&buf, "PGP PUBLIC KEY BLOCK", nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to begin ASCII-armored public key block: %s", err)
|
|
}
|
|
err = entity.Serialize(w)
|
|
if err != nil {
|
|
t.Fatalf("failed to serialize the public key part of the PGP entity: %s", err)
|
|
}
|
|
err = w.Close()
|
|
if err != nil {
|
|
t.Fatalf("failed to add ASCII-armor footer: %s", err)
|
|
}
|
|
return buf.Bytes(), entity.PrimaryKey.KeyIdString()
|
|
}
|
|
|
|
// pgpSignForTesting generates a signature for the given message using the private
|
|
// key from the given signer, in the raw binary format we'd normally expect to
|
|
// receive from an artifact linked in an OpenTofu provider registry.
|
|
func pgpSignForTesting(t *testing.T, message []byte, signer *openpgp.Entity) []byte {
|
|
t.Helper()
|
|
|
|
var buf bytes.Buffer
|
|
err := openpgp.DetachSign(&buf, signer, bytes.NewReader(message), nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to PGP sign message for testing: %s", err)
|
|
}
|
|
return buf.Bytes()
|
|
}
|