Files
opentf/internal/getproviders/package_authentication_helper_test.go
Martin Atkins 55855fca70 getproviders: Unify package authentication with hash lock selection
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>
2025-04-14 08:31:40 -07:00

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()
}