mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
api: restructure api pkg (#1851)
* api: rename AttestationVersionRepo to Client * api: move client into separate subpkg for clearer import paths. * api: rename configapi -> attestationconfig * api: rename versionsapi -> versions * api: rename sut to client * api: split versionsapi client and make it public * api: split versionapi fetcher and make it public * config: move attestationversion type to config * api: fix attestationconfig client test Co-authored-by: Adrian Stobbe <stobbe.adrian@gmail.com>
This commit is contained in:
parent
289665eb22
commit
30f2b332b3
@ -48,8 +48,10 @@ go_library(
|
||||
"//cli/internal/terraform",
|
||||
"//cli/internal/upgrade",
|
||||
"//disk-mapper/recoverproto",
|
||||
"//internal/api/attestationconfig/fetcher",
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/api/versions/fetcher",
|
||||
"//internal/atls",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/azureshared",
|
||||
@ -135,8 +137,8 @@ go_test(
|
||||
"//cli/internal/terraform",
|
||||
"//cli/internal/upgrade",
|
||||
"//disk-mapper/recoverproto",
|
||||
"//internal/api/configapi",
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/api/versions",
|
||||
"//internal/atls",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
|
@ -15,8 +15,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -65,13 +65,13 @@ func runConfigFetchMeasurements(cmd *cobra.Command, _ []string) error {
|
||||
}
|
||||
cfm := &configFetchMeasurementsCmd{log: log, canFetchMeasurements: featureset.CanFetchMeasurements}
|
||||
|
||||
fetcher := fetcher.NewConfigAPIFetcherWithClient(http.DefaultClient)
|
||||
fetcher := attestationconfigfetcher.NewWithClient(http.DefaultClient)
|
||||
return cfm.configFetchMeasurements(cmd, sigstore.CosignVerifier{}, rekor, fileHandler, fetcher, http.DefaultClient)
|
||||
}
|
||||
|
||||
func (cfm *configFetchMeasurementsCmd) configFetchMeasurements(
|
||||
cmd *cobra.Command, cosign cosignVerifier, rekor rekorVerifier,
|
||||
fileHandler file.Handler, fetcher fetcher.ConfigAPIFetcher, client *http.Client,
|
||||
fileHandler file.Handler, fetcher attestationconfigfetcher.AttestationConfigAPIFetcher, client *http.Client,
|
||||
) error {
|
||||
flags, err := cfm.parseFetchMeasurementsFlags(cmd)
|
||||
if err != nil {
|
||||
|
@ -16,8 +16,8 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
@ -305,8 +305,10 @@ func (f fakeConfigFetcher) FetchAzureSEVSNPVersion(_ context.Context, _ configap
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f fakeConfigFetcher) FetchLatestAzureSEVSNPVersion(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersion, error) {
|
||||
return testCfg, nil
|
||||
func (f fakeConfigFetcher) FetchAzureSEVSNPVersionLatest(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersionGet, error) {
|
||||
return configapi.AzureSEVSNPVersionGet{
|
||||
AzureSEVSNPVersion: testCfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var testCfg = configapi.AzureSEVSNPVersion{
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
@ -59,11 +59,11 @@ func runCreate(cmd *cobra.Command, _ []string) error {
|
||||
fileHandler := file.NewHandler(afero.NewOsFs())
|
||||
creator := cloudcmd.NewCreator(spinner)
|
||||
c := &createCmd{log: log}
|
||||
fetcher := fetcher.NewConfigAPIFetcher()
|
||||
fetcher := attestationconfigfetcher.New()
|
||||
return c.create(cmd, creator, fileHandler, spinner, fetcher)
|
||||
}
|
||||
|
||||
func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler, spinner spinnerInterf, fetcher fetcher.ConfigAPIFetcher) (retErr error) {
|
||||
func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler, spinner spinnerInterf, fetcher attestationconfigfetcher.AttestationConfigAPIFetcher) (retErr error) {
|
||||
flags, err := c.parseCreateFlags(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
|
||||
@ -98,13 +98,13 @@ func runInitialize(cmd *cobra.Command, _ []string) error {
|
||||
defer cancel()
|
||||
cmd.SetContext(ctx)
|
||||
i := &initCmd{log: log, spinner: spinner, merger: &kubeconfigMerger{log: log}, fh: &fileHandler}
|
||||
fetcher := fetcher.NewConfigAPIFetcher()
|
||||
fetcher := attestationconfigfetcher.New()
|
||||
return i.initialize(cmd, newDialer, fileHandler, license.NewClient(), fetcher)
|
||||
}
|
||||
|
||||
// initialize initializes a Constellation.
|
||||
func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.Validator) *dialer.Dialer,
|
||||
fileHandler file.Handler, quotaChecker license.QuotaChecker, configFetcher fetcher.ConfigAPIFetcher,
|
||||
fileHandler file.Handler, quotaChecker license.QuotaChecker, configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher,
|
||||
) error {
|
||||
flags, err := i.evalFlagArgs(cmd)
|
||||
if err != nil {
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
@ -46,7 +46,7 @@ func newMiniUpCmd() *cobra.Command {
|
||||
|
||||
type miniUpCmd struct {
|
||||
log debugLog
|
||||
configFetcher fetcher.ConfigAPIFetcher
|
||||
configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher
|
||||
}
|
||||
|
||||
func runUp(cmd *cobra.Command, _ []string) error {
|
||||
@ -62,7 +62,7 @@ func runUp(cmd *cobra.Command, _ []string) error {
|
||||
defer spinner.Stop()
|
||||
creator := cloudcmd.NewCreator(spinner)
|
||||
|
||||
m := &miniUpCmd{log: log, configFetcher: fetcher.NewConfigAPIFetcher()}
|
||||
m := &miniUpCmd{log: log, configFetcher: attestationconfigfetcher.New()}
|
||||
return m.up(cmd, creator, spinner)
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
||||
"github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
@ -50,7 +50,7 @@ func NewRecoverCmd() *cobra.Command {
|
||||
|
||||
type recoverCmd struct {
|
||||
log debugLog
|
||||
configFetcher fetcher.ConfigAPIFetcher
|
||||
configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher
|
||||
}
|
||||
|
||||
func runRecover(cmd *cobra.Command, _ []string) error {
|
||||
@ -63,7 +63,7 @@ func runRecover(cmd *cobra.Command, _ []string) error {
|
||||
newDialer := func(validator atls.Validator) *dialer.Dialer {
|
||||
return dialer.New(nil, validator, &net.Dialer{})
|
||||
}
|
||||
r := &recoverCmd{log: log, configFetcher: fetcher.NewConfigAPIFetcher()}
|
||||
r := &recoverCmd{log: log, configFetcher: attestationconfigfetcher.New()}
|
||||
return r.recover(cmd, fileHandler, 5*time.Second, &recoverDoer{log: r.log}, newDialer)
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
@ -67,7 +67,7 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
||||
}
|
||||
|
||||
imagefetcher := imagefetcher.New()
|
||||
configFetcher := fetcher.NewConfigAPIFetcher()
|
||||
configFetcher := attestationconfigfetcher.New()
|
||||
|
||||
applyCmd := upgradeApplyCmd{upgrader: upgrader, log: log, imageFetcher: imagefetcher, configFetcher: configFetcher}
|
||||
return applyCmd.upgradeApply(cmd, fileHandler)
|
||||
@ -76,7 +76,7 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
||||
type upgradeApplyCmd struct {
|
||||
upgrader cloudUpgrader
|
||||
imageFetcher imageFetcher
|
||||
configFetcher fetcher.ConfigAPIFetcher
|
||||
configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher
|
||||
log debugLog
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,10 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
versionfetcher "github.com/edgelesssys/constellation/v2/internal/api/versions/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
@ -68,7 +70,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
versionListFetcher := fetcher.NewVersionAPIFetcher()
|
||||
versionListFetcher := versionfetcher.New()
|
||||
rekor, err := sigstore.NewRekor()
|
||||
if err != nil {
|
||||
return fmt.Errorf("constructing Rekor client: %w", err)
|
||||
@ -86,12 +88,12 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
||||
flags: flags,
|
||||
cliVersion: compatibility.EnsurePrefixV(constants.VersionInfo()),
|
||||
log: log,
|
||||
versionsapi: fetcher.NewVersionAPIFetcher(),
|
||||
versionsapi: versionfetcher.New(),
|
||||
},
|
||||
log: log,
|
||||
}
|
||||
|
||||
return up.upgradeCheck(cmd, fileHandler, fetcher.NewConfigAPIFetcher(), flags)
|
||||
return up.upgradeCheck(cmd, fileHandler, attestationconfigfetcher.New(), flags)
|
||||
}
|
||||
|
||||
func parseUpgradeCheckFlags(cmd *cobra.Command) (upgradeCheckFlags, error) {
|
||||
@ -131,7 +133,7 @@ type upgradeCheckCmd struct {
|
||||
}
|
||||
|
||||
// upgradePlan plans an upgrade of a Constellation cluster.
|
||||
func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Handler, fetcher fetcher.ConfigAPIFetcher, flags upgradeCheckFlags) error {
|
||||
func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Handler, fetcher attestationconfigfetcher.AttestationConfigAPIFetcher, flags upgradeCheckFlags) error {
|
||||
conf, err := config.New(fileHandler, flags.configPath, fetcher, flags.force)
|
||||
var configValidationErr *config.ValidationError
|
||||
if errors.As(err, &configValidationErr) {
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
@ -72,11 +72,11 @@ func runVerify(cmd *cobra.Command, _ []string) error {
|
||||
}
|
||||
|
||||
v := &verifyCmd{log: log}
|
||||
fetcher := fetcher.NewConfigAPIFetcher()
|
||||
fetcher := attestationconfigfetcher.New()
|
||||
return v.verify(cmd, fileHandler, verifyClient, formatter, fetcher)
|
||||
}
|
||||
|
||||
func (c *verifyCmd) verify(cmd *cobra.Command, fileHandler file.Handler, verifyClient verifyClient, formatter attestationDocFormatter, configFetcher fetcher.ConfigAPIFetcher) error {
|
||||
func (c *verifyCmd) verify(cmd *cobra.Command, fileHandler file.Handler, verifyClient verifyClient, formatter attestationDocFormatter, configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher) error {
|
||||
flags, err := c.parseVerifyFlags(cmd, fileHandler)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing flags: %w", err)
|
||||
|
@ -14,7 +14,7 @@ go_library(
|
||||
"//cli/internal/helm",
|
||||
"//cli/internal/terraform",
|
||||
"//cli/internal/upgrade",
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/compatibility",
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
|
@ -14,7 +14,7 @@ go_library(
|
||||
"//debugd/internal/filetransfer",
|
||||
"//debugd/internal/filetransfer/streamer",
|
||||
"//debugd/service",
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/attestationconfig/fetcher",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/file",
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/debugd/internal/filetransfer"
|
||||
"github.com/edgelesssys/constellation/v2/debugd/internal/filetransfer/streamer"
|
||||
pb "github.com/edgelesssys/constellation/v2/debugd/service"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -69,7 +69,7 @@ func runDeploy(cmd *cobra.Command, _ []string) error {
|
||||
fileHandler := file.NewHandler(fs)
|
||||
streamer := streamer.New(fs)
|
||||
transfer := filetransfer.New(log, streamer, filetransfer.ShowProgress)
|
||||
constellationConfig, err := config.New(fileHandler, configName, fetcher.NewConfigAPIFetcher(), force)
|
||||
constellationConfig, err := config.New(fileHandler, configName, attestationconfigfetcher.New(), force)
|
||||
var configValidationErr *config.ValidationError
|
||||
if errors.As(err, &configValidationErr) {
|
||||
cmd.PrintErrln(configValidationErr.LongMessage())
|
||||
|
@ -11,7 +11,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/e2e/internal/upgrade",
|
||||
visibility = ["//e2e:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/constants",
|
||||
@ -26,6 +26,7 @@ go_library(
|
||||
go_test(
|
||||
name = "upgrade_test",
|
||||
srcs = ["upgrade_test.go"],
|
||||
# keep
|
||||
count = 1,
|
||||
data = [
|
||||
"//cli:cli_oss_linux_amd64",
|
||||
@ -34,11 +35,12 @@ go_test(
|
||||
env = {
|
||||
"PATH_CLI": "$(location //cli:cli_oss_linux_amd64)",
|
||||
},
|
||||
# keep
|
||||
gotags = ["e2e"],
|
||||
tags = ["manual"],
|
||||
deps = [
|
||||
"//e2e/internal/kubectl",
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/attestationconfig/fetcher",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/file",
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/e2e/internal/kubectl"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -233,7 +233,7 @@ func testNodesEventuallyAvailable(t *testing.T, k *kubernetes.Clientset, wantCon
|
||||
|
||||
func writeUpgradeConfig(require *require.Assertions, image string, kubernetes string, microservices string) versionContainer {
|
||||
fileHandler := file.NewHandler(afero.NewOsFs())
|
||||
fetcher := fetcher.NewConfigAPIFetcher()
|
||||
fetcher := attestationconfigfetcher.New()
|
||||
cfg, err := config.New(fileHandler, constants.ConfigFilename, fetcher, true)
|
||||
var cfgErr *config.ValidationError
|
||||
var longMsg string
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/hack/azure-snp-report-verify",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//internal/api/configapi",
|
||||
"//internal/api/attestationconfig",
|
||||
"@in_gopkg_square_go_jose_v2//:go-jose_v2",
|
||||
"@in_gopkg_square_go_jose_v2//jwt",
|
||||
],
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
)
|
||||
|
@ -6,8 +6,8 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/hack/cli-k8s-compatibility",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versionsapi/client",
|
||||
"//internal/api/versions",
|
||||
"//internal/api/versions/client",
|
||||
"//internal/logger",
|
||||
"//internal/versions",
|
||||
"@org_uber_go_zap//zapcore",
|
||||
|
@ -11,8 +11,8 @@ import (
|
||||
"context"
|
||||
"flag"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versions/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
@ -6,7 +6,8 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/hack/configapi/cmd",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//internal/api/configapi",
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/api/attestationconfig/client",
|
||||
"//internal/staticupload",
|
||||
"@com_github_spf13_cobra//:cobra",
|
||||
],
|
||||
|
@ -12,7 +12,8 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
attestationconfigclient "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/staticupload"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -75,7 +76,7 @@ func runCmd(cmd *cobra.Command, _ []string) error {
|
||||
return fmt.Errorf("unmarshalling version file: %w", err)
|
||||
}
|
||||
|
||||
sut, err := configapi.NewAttestationVersionRepo(ctx, cfg, []byte(cosignPwd), privateKey)
|
||||
sut, err := attestationconfigclient.New(ctx, cfg, []byte(cosignPwd), privateKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating repo: %w", err)
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/image/upload/internal/cmd",
|
||||
visibility = ["//image/upload:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/logger",
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||
)
|
||||
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
infoupload "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||
)
|
||||
|
||||
|
15
internal/api/attestationconfig/BUILD.bazel
Normal file
15
internal/api/attestationconfig/BUILD.bazel
Normal file
@ -0,0 +1,15 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "attestationconfig",
|
||||
srcs = [
|
||||
"azure.go",
|
||||
"configapi.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/constants",
|
||||
"//internal/variant",
|
||||
],
|
||||
)
|
@ -3,7 +3,8 @@ Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package configapi
|
||||
|
||||
package attestationconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
@ -2,16 +2,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "configapi",
|
||||
srcs = [
|
||||
"attestation.go",
|
||||
"attestationversion.go",
|
||||
"configapi.go",
|
||||
"repo.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/configapi",
|
||||
name = "client",
|
||||
srcs = ["client.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/client",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/constants",
|
||||
"//internal/kms/storage",
|
||||
"//internal/sigstore",
|
||||
@ -22,15 +18,18 @@ go_library(
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "configapi_test",
|
||||
srcs = [
|
||||
"attestationversion_test.go",
|
||||
"repo_test.go",
|
||||
],
|
||||
embed = [":configapi"],
|
||||
name = "client_test",
|
||||
srcs = ["client_test.go"],
|
||||
# keep
|
||||
count = 1,
|
||||
# keep
|
||||
gotags = ["e2e"],
|
||||
# keep
|
||||
tags = ["manual"],
|
||||
deps = [
|
||||
":client",
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/staticupload",
|
||||
"@com_github_stretchr_testify//require",
|
||||
"@in_gopkg_yaml_v3//:yaml_v3",
|
||||
],
|
||||
)
|
@ -3,7 +3,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package configapi
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -17,30 +17,32 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/storage"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/edgelesssys/constellation/v2/internal/staticupload"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
)
|
||||
|
||||
// AttestationVersionRepo manages (modifies) the version information for the attestation variants.
|
||||
type AttestationVersionRepo struct {
|
||||
// Client manages (modifies) the version information for the attestation variants.
|
||||
type Client struct {
|
||||
*staticupload.Client
|
||||
cosignPwd []byte // used to decrypt the cosign private key
|
||||
privKey []byte // used to sign
|
||||
}
|
||||
|
||||
// NewAttestationVersionRepo returns a new AttestationVersionRepo.
|
||||
func NewAttestationVersionRepo(ctx context.Context, cfg staticupload.Config, cosignPwd, privateKey []byte) (*AttestationVersionRepo, error) {
|
||||
// New returns a new Client.
|
||||
func New(ctx context.Context, cfg staticupload.Config, cosignPwd, privateKey []byte) (*Client, error) {
|
||||
client, err := staticupload.New(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create s3 storage: %w", err)
|
||||
}
|
||||
return &AttestationVersionRepo{client, cosignPwd, privateKey}, nil
|
||||
return &Client{client, cosignPwd, privateKey}, nil
|
||||
}
|
||||
|
||||
// UploadAzureSEVSNP uploads the latest version numbers of the Azure SEVSNP.
|
||||
func (a AttestationVersionRepo) UploadAzureSEVSNP(ctx context.Context, versions AzureSEVSNPVersion, date time.Time) error {
|
||||
func (a Client) UploadAzureSEVSNP(ctx context.Context, versions attestationconfig.AzureSEVSNPVersion, date time.Time) error {
|
||||
versionBytes, err := json.Marshal(versions)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -48,7 +50,7 @@ func (a AttestationVersionRepo) UploadAzureSEVSNP(ctx context.Context, versions
|
||||
variant := variant.AzureSEVSNP{}
|
||||
fname := date.Format("2006-01-02-15-04") + ".json"
|
||||
|
||||
filePath := fmt.Sprintf("%s/%s/%s", attestationURLPath, variant.String(), fname)
|
||||
filePath := fmt.Sprintf("%s/%s/%s", constants.CDNAttestationConfigPrefixV1, variant.String(), fname)
|
||||
err = put(ctx, a.Client, filePath, versionBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -62,7 +64,7 @@ func (a AttestationVersionRepo) UploadAzureSEVSNP(ctx context.Context, versions
|
||||
}
|
||||
|
||||
// createAndUploadSignature signs the given content and uploads the signature to the given filePath with the .sig suffix.
|
||||
func (a AttestationVersionRepo) createAndUploadSignature(ctx context.Context, content []byte, filePath string) error {
|
||||
func (a Client) createAndUploadSignature(ctx context.Context, content []byte, filePath string) error {
|
||||
signature, err := sigstore.SignContent(a.cosignPwd, a.privKey, content)
|
||||
if err != nil {
|
||||
return fmt.Errorf("sign version file: %w", err)
|
||||
@ -75,8 +77,8 @@ func (a AttestationVersionRepo) createAndUploadSignature(ctx context.Context, co
|
||||
}
|
||||
|
||||
// List returns the list of versions for the given attestation type.
|
||||
func (a AttestationVersionRepo) List(ctx context.Context, attestation variant.Variant) ([]string, error) {
|
||||
key := path.Join(attestationURLPath, attestation.String(), "list")
|
||||
func (a Client) List(ctx context.Context, attestation variant.Variant) ([]string, error) {
|
||||
key := path.Join(constants.CDNAttestationConfigPrefixV1, attestation.String(), "list")
|
||||
bt, err := get(ctx, a.Client, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -89,18 +91,18 @@ func (a AttestationVersionRepo) List(ctx context.Context, attestation variant.Va
|
||||
}
|
||||
|
||||
// DeleteList empties the list of versions for the given attestation type.
|
||||
func (a AttestationVersionRepo) DeleteList(ctx context.Context, attestation variant.Variant) error {
|
||||
func (a Client) DeleteList(ctx context.Context, attestation variant.Variant) error {
|
||||
versions := []string{}
|
||||
bt, err := json.Marshal(&versions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return put(ctx, a.Client, path.Join(attestationURLPath, attestation.String(), "list"), bt)
|
||||
return put(ctx, a.Client, path.Join(constants.CDNAttestationConfigPrefixV1, attestation.String(), "list"), bt)
|
||||
}
|
||||
|
||||
func (a AttestationVersionRepo) addVersionToList(ctx context.Context, attestation variant.Variant, fname string) error {
|
||||
func (a Client) addVersionToList(ctx context.Context, attestation variant.Variant, fname string) error {
|
||||
versions := []string{}
|
||||
key := path.Join(attestationURLPath, attestation.String(), "list")
|
||||
key := path.Join(constants.CDNAttestationConfigPrefixV1, attestation.String(), "list")
|
||||
bt, err := get(ctx, a.Client, key)
|
||||
if err == nil {
|
||||
if err := json.Unmarshal(bt, &versions); err != nil {
|
@ -5,7 +5,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package configapi_test
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -16,7 +16,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/staticupload"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -64,7 +65,7 @@ func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
var versionValues = configapi.AzureSEVSNPVersion{
|
||||
var versionValues = attestationconfig.AzureSEVSNPVersion{
|
||||
Bootloader: 2,
|
||||
TEE: 0,
|
||||
SNP: 6,
|
||||
@ -73,8 +74,8 @@ var versionValues = configapi.AzureSEVSNPVersion{
|
||||
|
||||
func TestUploadAzureSEVSNPVersions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
sut, err := configapi.NewAttestationVersionRepo(ctx, cfg, []byte(*cosignPwd), privateKey)
|
||||
client, err := client.New(ctx, cfg, []byte(*cosignPwd), privateKey)
|
||||
require.NoError(t, err)
|
||||
d := time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC)
|
||||
require.NoError(t, sut.UploadAzureSEVSNP(ctx, versionValues, d))
|
||||
require.NoError(t, client.UploadAzureSEVSNP(ctx, versionValues, d))
|
||||
}
|
23
internal/api/attestationconfig/configapi.go
Normal file
23
internal/api/attestationconfig/configapi.go
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
# AttestationConfig API
|
||||
|
||||
The AttestationConfig API provides values for the attestation key in the Constellation config.
|
||||
|
||||
This package defines API types that represents objects of the AttestationConfig API.
|
||||
The types provide helper methods for validation and commonly used operations on the
|
||||
information contained in the objects. Especially the paths used for the API are defined
|
||||
in these helper methods.
|
||||
|
||||
Regarding the decision to implement new types over using the existing types from internal/config:
|
||||
AttesationCfg objects for AttestationCfg API need to hold some version information (for sorting, recognizing latest).
|
||||
Thus, existing config types (AWSNitroTPM, AzureSEVSNP, ...) can not be extended to implement apiObject interface.
|
||||
Instead, we need a separate type that wraps _all_ attestation types. In the codebase this is done using the AttestationCfg interface.
|
||||
The new type AttestationCfgGet needs to be located inside internal/config in order to implement UnmarshalJSON.
|
||||
*/
|
||||
package attestationconfig
|
27
internal/api/attestationconfig/fetcher/BUILD.bazel
Normal file
27
internal/api/attestationconfig/fetcher/BUILD.bazel
Normal file
@ -0,0 +1,27 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "fetcher",
|
||||
srcs = ["fetcher.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/versions",
|
||||
"//internal/sigstore",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "fetcher_test",
|
||||
srcs = ["fetcher_test.go"],
|
||||
embed = [":fetcher"],
|
||||
deps = [
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/api/versions",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
)
|
120
internal/api/attestationconfig/fetcher/fetcher.go
Normal file
120
internal/api/attestationconfig/fetcher/fetcher.go
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package fetcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
)
|
||||
|
||||
// AttestationConfigAPIFetcher fetches config API resources without authentication.
|
||||
type AttestationConfigAPIFetcher interface {
|
||||
FetchAzureSEVSNPVersion(ctx context.Context, azureVersion attestationconfig.AzureSEVSNPVersionGet, version versionsapi.Version) (attestationconfig.AzureSEVSNPVersionGet, error)
|
||||
FetchAzureSEVSNPVersionList(ctx context.Context, attestation attestationconfig.AzureSEVSNPVersionList) (attestationconfig.AzureSEVSNPVersionList, error)
|
||||
FetchAzureSEVSNPVersionLatest(ctx context.Context, version versionsapi.Version) (attestationconfig.AzureSEVSNPVersionGet, error)
|
||||
}
|
||||
|
||||
// Fetcher fetches AttestationCfg API resources without authentication.
|
||||
type Fetcher struct {
|
||||
fetcher.HTTPClient
|
||||
}
|
||||
|
||||
// New returns a new Fetcher.
|
||||
func New() *Fetcher {
|
||||
return NewWithClient(fetcher.NewHTTPClient())
|
||||
}
|
||||
|
||||
// NewWithClient returns a new Fetcher with custom http client.
|
||||
func NewWithClient(client fetcher.HTTPClient) *Fetcher {
|
||||
return &Fetcher{client}
|
||||
}
|
||||
|
||||
// FetchAzureSEVSNPVersionList fetches the version list information from the config API.
|
||||
func (f *Fetcher) FetchAzureSEVSNPVersionList(ctx context.Context, attestation attestationconfig.AzureSEVSNPVersionList) (attestationconfig.AzureSEVSNPVersionList, error) {
|
||||
return fetcher.Fetch(ctx, f.HTTPClient, attestation)
|
||||
}
|
||||
|
||||
// FetchAzureSEVSNPVersion fetches the version information from the config API.
|
||||
func (f *Fetcher) FetchAzureSEVSNPVersion(ctx context.Context, attestation attestationconfig.AzureSEVSNPVersionGet, version versionsapi.Version) (attestationconfig.AzureSEVSNPVersionGet, error) {
|
||||
cosignPublicKey, err := sigstore.CosignPublicKeyForVersion(version)
|
||||
if err != nil {
|
||||
return attestationconfig.AzureSEVSNPVersionGet{}, fmt.Errorf("get public key for config: %w", err)
|
||||
}
|
||||
urlString, err := attestation.URL()
|
||||
if err != nil {
|
||||
return attestationconfig.AzureSEVSNPVersionGet{}, err
|
||||
}
|
||||
fetchedVersion, err := fetcher.Fetch(ctx, f.HTTPClient, attestation)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("fetch version %s: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
versionBytes, err := json.Marshal(fetchedVersion)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("marshal version for verify %s: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
|
||||
signature, err := fetchBytesFromRawURL(ctx, fmt.Sprintf("%s.sig", urlString), f.HTTPClient)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("fetch version %s signature: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
|
||||
err = sigstore.CosignVerifier{}.VerifySignature(versionBytes, signature, cosignPublicKey)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("verify version %s signature: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
return fetchedVersion, nil
|
||||
}
|
||||
|
||||
// FetchAzureSEVSNPVersionLatest returns the latest versions of the given type.
|
||||
func (f *Fetcher) FetchAzureSEVSNPVersionLatest(ctx context.Context, version versionsapi.Version) (res attestationconfig.AzureSEVSNPVersionGet, err error) {
|
||||
var list attestationconfig.AzureSEVSNPVersionList
|
||||
list, err = f.FetchAzureSEVSNPVersionList(ctx, list)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf("fetching versions list: %w", err)
|
||||
}
|
||||
get := attestationconfig.AzureSEVSNPVersionGet{Version: list[0]} // get latest version (as sorted reversely alphanumerically)
|
||||
get, err = f.FetchAzureSEVSNPVersion(ctx, get, version)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf("failed fetching version: %w", err)
|
||||
}
|
||||
return get, nil
|
||||
}
|
||||
|
||||
func fetchBytesFromRawURL(ctx context.Context, urlString string, client fetcher.HTTPClient) ([]byte, error) {
|
||||
url, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse version url %s: %w", urlString, err)
|
||||
}
|
||||
return getFromURL(ctx, client, url)
|
||||
}
|
||||
|
||||
// getFromURL fetches the content from the given URL and returns the content as a byte slice.
|
||||
func getFromURL(ctx context.Context, client fetcher.HTTPClient, sourceURL *url.URL) ([]byte, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, sourceURL.String(), http.NoBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("http status code: %d", resp.StatusCode)
|
||||
}
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
@ -14,24 +14,26 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testCfg = configapi.AzureSEVSNPVersion{
|
||||
Microcode: 93,
|
||||
TEE: 0,
|
||||
SNP: 6,
|
||||
Bootloader: 2,
|
||||
var testCfg = configapi.AzureSEVSNPVersionGet{
|
||||
AzureSEVSNPVersion: configapi.AzureSEVSNPVersion{
|
||||
Microcode: 93,
|
||||
TEE: 0,
|
||||
SNP: 6,
|
||||
Bootloader: 2,
|
||||
},
|
||||
}
|
||||
|
||||
func TestFetchLatestAzureSEVSNPVersion(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
signature []byte
|
||||
wantErr bool
|
||||
want configapi.AzureSEVSNPVersion
|
||||
want configapi.AzureSEVSNPVersionGet
|
||||
}{
|
||||
"get version with valid signature": {
|
||||
signature: []byte("MEUCIQDNn6wiSh9Nz9mtU9RvxvfkH3fNDFGeqopjTIRoBNkyrAIgSsKgdYNQXvPevaLWmmpnj/9WcgrltAQ+KfI+bQfklAo="),
|
||||
@ -52,10 +54,10 @@ func TestFetchLatestAzureSEVSNPVersion(t *testing.T) {
|
||||
require := require.New(t)
|
||||
version, err := versionsapi.NewVersionFromShortPath("stream/debug/v9.9.9", versionsapi.VersionKindImage)
|
||||
require.NoError(err)
|
||||
fetcher := NewConfigAPIFetcherWithClient(client)
|
||||
fetcher := NewWithClient(client)
|
||||
|
||||
assert := assert.New(t)
|
||||
res, err := fetcher.FetchLatestAzureSEVSNPVersion(context.Background(), version)
|
||||
res, err := fetcher.FetchAzureSEVSNPVersionLatest(context.Background(), version)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
@ -3,11 +3,9 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
go_library(
|
||||
name = "client",
|
||||
srcs = ["client.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client",
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/client",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/constants",
|
||||
"//internal/logger",
|
||||
"@com_github_aws_aws_sdk_go_v2//aws",
|
||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
||||
@ -16,6 +14,6 @@ go_library(
|
||||
"@com_github_aws_aws_sdk_go_v2_service_cloudfront//types",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_s3//:s3",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_s3//types",
|
||||
"@org_golang_x_mod//semver",
|
||||
"@org_uber_go_zap//:zap",
|
||||
],
|
||||
)
|
291
internal/api/client/client.go
Normal file
291
internal/api/client/client.go
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
Package client provides a client for the versions API.
|
||||
|
||||
The client needs to be authenticated with AWS. It should be used in internal
|
||||
development and CI tools for administrative tasks. For just fetching information
|
||||
from the API, use the fetcher package instead.
|
||||
|
||||
Needed IAM permissions for read mode:
|
||||
- "s3:GetObject"
|
||||
- "s3:ListBucket"
|
||||
|
||||
Additional needed IAM permissions for write mode:
|
||||
- "s3:PutObject"
|
||||
- "s3:DeleteObject"
|
||||
- "cloudfront:CreateInvalidation"
|
||||
|
||||
Thread-safety of the bucket is not guaranteed. The client is not thread-safe.
|
||||
|
||||
Each sub-API included in the Constellation Resource API should define it's resources by implementing types that implement apiObject.
|
||||
The new package can then call this package's Fetch and Update functions to get/modify resources from the API.
|
||||
*/
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/cloudfront"
|
||||
cftypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Client is the client for the versions API.
|
||||
type Client struct {
|
||||
config aws.Config
|
||||
cloudfrontClient *cloudfront.Client
|
||||
s3Client *s3.Client
|
||||
uploadClient *s3manager.Uploader
|
||||
bucket string
|
||||
distributionID string
|
||||
cacheInvalidationWaitTimeout time.Duration
|
||||
|
||||
dirtyPaths []string // written paths to be invalidated
|
||||
DryRun bool // no write operations are performed
|
||||
|
||||
Log *logger.Logger
|
||||
}
|
||||
|
||||
// NewReadOnlyClient creates a new read-only client.
|
||||
// This client can be used to fetch objects but cannot write updates.
|
||||
func NewReadOnlyClient(ctx context.Context, region, bucket, distributionID string,
|
||||
log *logger.Logger,
|
||||
) (*Client, error) {
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(region))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s3c := s3.NewFromConfig(cfg)
|
||||
|
||||
return &Client{
|
||||
config: cfg,
|
||||
s3Client: s3c,
|
||||
bucket: bucket,
|
||||
distributionID: distributionID,
|
||||
DryRun: true,
|
||||
Log: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewClient creates a new client for the versions API.
|
||||
func NewClient(ctx context.Context, region, bucket, distributionID string, dryRun bool,
|
||||
log *logger.Logger,
|
||||
) (*Client, error) {
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(region))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cloudfrontC := cloudfront.NewFromConfig(cfg)
|
||||
s3C := s3.NewFromConfig(cfg)
|
||||
uploadC := s3manager.NewUploader(s3C)
|
||||
|
||||
return &Client{
|
||||
config: cfg,
|
||||
cloudfrontClient: cloudfrontC,
|
||||
s3Client: s3C,
|
||||
uploadClient: uploadC,
|
||||
bucket: bucket,
|
||||
distributionID: distributionID,
|
||||
DryRun: dryRun,
|
||||
Log: log,
|
||||
cacheInvalidationWaitTimeout: 10 * time.Minute,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// InvalidateCache invalidates the CDN cache for the paths that have been written.
|
||||
// The function should be deferred after the client has been created.
|
||||
func (c *Client) InvalidateCache(ctx context.Context) error {
|
||||
if len(c.dirtyPaths) == 0 {
|
||||
c.Log.Debugf("No dirty paths, skipping cache invalidation")
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.DryRun {
|
||||
c.Log.With(zap.String("distributionID", c.distributionID), zap.Strings("dirtyPaths", c.dirtyPaths)).Debugf("DryRun: cloudfront create invalidation")
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Log.Debugf("Paths to invalidate: %v", c.dirtyPaths)
|
||||
|
||||
in := &cloudfront.CreateInvalidationInput{
|
||||
DistributionId: &c.distributionID,
|
||||
InvalidationBatch: &cftypes.InvalidationBatch{
|
||||
CallerReference: ptr(fmt.Sprintf("%d", time.Now().Unix())),
|
||||
Paths: &cftypes.Paths{
|
||||
Items: c.dirtyPaths,
|
||||
Quantity: ptr(int32(len(c.dirtyPaths))),
|
||||
},
|
||||
},
|
||||
}
|
||||
invalidation, err := c.cloudfrontClient.CreateInvalidation(ctx, in)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating invalidation: %w", err)
|
||||
}
|
||||
|
||||
c.Log.Debugf("Waiting for invalidation %s to complete", *invalidation.Invalidation.Id)
|
||||
waiter := cloudfront.NewInvalidationCompletedWaiter(c.cloudfrontClient)
|
||||
waitIn := &cloudfront.GetInvalidationInput{
|
||||
DistributionId: &c.distributionID,
|
||||
Id: invalidation.Invalidation.Id,
|
||||
}
|
||||
if err := waiter.Wait(ctx, waitIn, c.cacheInvalidationWaitTimeout); err != nil {
|
||||
return fmt.Errorf("waiting for invalidation to complete: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePath deletes all objects at a given path from a s3 bucket.
|
||||
func (c *Client) DeletePath(ctx context.Context, path string) error {
|
||||
listIn := &s3.ListObjectsV2Input{
|
||||
Bucket: &c.bucket,
|
||||
Prefix: &path,
|
||||
}
|
||||
c.Log.Debugf("Listing objects in %s", path)
|
||||
objs := []s3types.Object{}
|
||||
out := &s3.ListObjectsV2Output{IsTruncated: true}
|
||||
for out.IsTruncated {
|
||||
var err error
|
||||
out, err = c.s3Client.ListObjectsV2(ctx, listIn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing objects in %s: %w", path, err)
|
||||
}
|
||||
objs = append(objs, out.Contents...)
|
||||
}
|
||||
c.Log.Debugf("Found %d objects in %s", len(objs), path)
|
||||
|
||||
if len(objs) == 0 {
|
||||
c.Log.Warnf("Path %s is already empty", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
objIDs := make([]s3types.ObjectIdentifier, len(objs))
|
||||
for i, obj := range objs {
|
||||
objIDs[i] = s3types.ObjectIdentifier{Key: obj.Key}
|
||||
}
|
||||
|
||||
if c.DryRun {
|
||||
c.Log.Debugf("DryRun: Deleting %d objects with IDs %v", len(objs), objIDs)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.dirtyPaths = append(c.dirtyPaths, "/"+path)
|
||||
|
||||
deleteIn := &s3.DeleteObjectsInput{
|
||||
Bucket: &c.bucket,
|
||||
Delete: &s3types.Delete{
|
||||
Objects: objIDs,
|
||||
},
|
||||
}
|
||||
c.Log.Debugf("Deleting %d objects in %s", len(objs), path)
|
||||
if _, err := c.s3Client.DeleteObjects(ctx, deleteIn); err != nil {
|
||||
return fmt.Errorf("deleting objects in %s: %w", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ptr[T any](t T) *T {
|
||||
return &t
|
||||
}
|
||||
|
||||
type apiObject interface {
|
||||
ValidateRequest() error
|
||||
Validate() error
|
||||
JSONPath() string
|
||||
}
|
||||
|
||||
// Fetch fetches the given apiObject from the public Constellation CDN.
|
||||
func Fetch[T apiObject](ctx context.Context, c *Client, obj T) (T, error) {
|
||||
if err := obj.ValidateRequest(); err != nil {
|
||||
return *new(T), fmt.Errorf("validating request for %T: %w", obj, err)
|
||||
}
|
||||
|
||||
in := &s3.GetObjectInput{
|
||||
Bucket: &c.bucket,
|
||||
Key: ptr(obj.JSONPath()),
|
||||
}
|
||||
|
||||
c.Log.Debugf("Fetching %T from s3: %s", obj, obj.JSONPath())
|
||||
out, err := c.s3Client.GetObject(ctx, in)
|
||||
var noSuchkey *s3types.NoSuchKey
|
||||
if errors.As(err, &noSuchkey) {
|
||||
return *new(T), &NotFoundError{err: err}
|
||||
} else if err != nil {
|
||||
return *new(T), fmt.Errorf("getting s3 object at %s: %w", obj.JSONPath(), err)
|
||||
}
|
||||
defer out.Body.Close()
|
||||
|
||||
var newObj T
|
||||
if err := json.NewDecoder(out.Body).Decode(&newObj); err != nil {
|
||||
return *new(T), fmt.Errorf("decoding %T: %w", obj, err)
|
||||
}
|
||||
|
||||
if newObj.Validate() != nil {
|
||||
return *new(T), fmt.Errorf("received invalid %T: %w", newObj, newObj.Validate())
|
||||
}
|
||||
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
// Update creates/updates the given apiObject in the public Constellation CDN.
|
||||
func Update[T apiObject](ctx context.Context, c *Client, obj T) error {
|
||||
if err := obj.Validate(); err != nil {
|
||||
return fmt.Errorf("validating %T struct: %w", obj, err)
|
||||
}
|
||||
|
||||
rawJSON, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshaling %T struct: %w", obj, err)
|
||||
}
|
||||
|
||||
if c.DryRun {
|
||||
c.Log.With(zap.String("bucket", c.bucket), zap.String("key", obj.JSONPath()), zap.String("body", string(rawJSON))).Debugf("DryRun: s3 put object")
|
||||
return nil
|
||||
}
|
||||
|
||||
in := &s3.PutObjectInput{
|
||||
Bucket: &c.bucket,
|
||||
Key: ptr(obj.JSONPath()),
|
||||
Body: bytes.NewBuffer(rawJSON),
|
||||
}
|
||||
|
||||
c.dirtyPaths = append(c.dirtyPaths, "/"+obj.JSONPath())
|
||||
|
||||
c.Log.Debugf("Uploading %T to s3: %v", obj, obj.JSONPath())
|
||||
if _, err := c.uploadClient.Upload(ctx, in); err != nil {
|
||||
return fmt.Errorf("uploading %T: %w", obj, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotFoundError is an error that is returned when a resource is not found.
|
||||
type NotFoundError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *NotFoundError) Error() string {
|
||||
return fmt.Sprintf("the requested resource was not found: %s", e.err.Error())
|
||||
}
|
||||
|
||||
func (e *NotFoundError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
# Config API
|
||||
|
||||
The Config API provides information about versions of Constellation components.
|
||||
|
||||
This package defines API types that represents objects of the config API.
|
||||
The types provide helper methods for validation and commonly used operations on the
|
||||
information contained in the objects. Especially the paths used for the API are defined
|
||||
in these helper methods.
|
||||
|
||||
The package also provides helper functions that can be used in context of the config API,
|
||||
e.g. to validate versions.
|
||||
*/
|
||||
package configapi
|
@ -1,34 +1,8 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "fetcher",
|
||||
srcs = [
|
||||
"configapi.go",
|
||||
"fetcher.go",
|
||||
"versionapi.go",
|
||||
],
|
||||
srcs = ["fetcher.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/fetcher",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/configapi",
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/sigstore",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "fetcher_test",
|
||||
srcs = [
|
||||
"configapi_test.go",
|
||||
"versionapi_test.go",
|
||||
],
|
||||
embed = [":fetcher"],
|
||||
deps = [
|
||||
"//internal/api/configapi",
|
||||
"//internal/api/versionsapi",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
"@org_uber_go_goleak//:goleak",
|
||||
],
|
||||
)
|
||||
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package fetcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
)
|
||||
|
||||
// ConfigAPIFetcher fetches config API resources without authentication.
|
||||
type ConfigAPIFetcher interface {
|
||||
FetchAzureSEVSNPVersionList(ctx context.Context, attestation configapi.AzureSEVSNPVersionList) (configapi.AzureSEVSNPVersionList, error)
|
||||
FetchAzureSEVSNPVersion(ctx context.Context, azureVersion configapi.AzureSEVSNPVersionGet, version versionsapi.Version) (configapi.AzureSEVSNPVersionGet, error)
|
||||
FetchLatestAzureSEVSNPVersion(ctx context.Context, version versionsapi.Version) (configapi.AzureSEVSNPVersion, error)
|
||||
}
|
||||
|
||||
// configAPIFetcher fetches config API resources without authentication.
|
||||
type configAPIFetcher struct {
|
||||
*fetcher
|
||||
}
|
||||
|
||||
// NewConfigAPIFetcher returns a new Fetcher.
|
||||
func NewConfigAPIFetcher() ConfigAPIFetcher {
|
||||
return NewConfigAPIFetcherWithClient(NewHTTPClient())
|
||||
}
|
||||
|
||||
// NewConfigAPIFetcherWithClient returns a new Fetcher with custom http client.
|
||||
func NewConfigAPIFetcherWithClient(client HTTPClient) ConfigAPIFetcher {
|
||||
return &configAPIFetcher{
|
||||
fetcher: newFetcherWith(client),
|
||||
}
|
||||
}
|
||||
|
||||
// FetchAzureSEVSNPVersionList fetches the version list information from the config API.
|
||||
func (f *configAPIFetcher) FetchAzureSEVSNPVersionList(ctx context.Context, attestation configapi.AzureSEVSNPVersionList) (configapi.AzureSEVSNPVersionList, error) {
|
||||
return fetch(ctx, f.httpc, attestation)
|
||||
}
|
||||
|
||||
// FetchAzureSEVSNPVersion fetches the version information from the config API.
|
||||
func (f *configAPIFetcher) FetchAzureSEVSNPVersion(ctx context.Context, azureVersion configapi.AzureSEVSNPVersionGet, version versionsapi.Version) (configapi.AzureSEVSNPVersionGet, error) {
|
||||
cosignPublicKey, err := sigstore.CosignPublicKeyForVersion(version)
|
||||
if err != nil {
|
||||
return azureVersion, fmt.Errorf("get public key for config: %w", err)
|
||||
}
|
||||
urlString, err := azureVersion.URL()
|
||||
if err != nil {
|
||||
return azureVersion, err
|
||||
}
|
||||
fetchedVersion, err := fetch(ctx, f.httpc, azureVersion)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("fetch version %s: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
versionBytes, err := json.Marshal(fetchedVersion)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("marshal version for verify %s: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
|
||||
signature, err := fetchBytesFromRawURL(ctx, fmt.Sprintf("%s.sig", urlString), f.httpc)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("fetch version %s signature: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
|
||||
err = sigstore.CosignVerifier{}.VerifySignature(versionBytes, signature, cosignPublicKey)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("verify version %s signature: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
return fetchedVersion, nil
|
||||
}
|
||||
|
||||
// FetchLatestAzureSEVSNPVersion returns the latest versions of the given type.
|
||||
func (f *configAPIFetcher) FetchLatestAzureSEVSNPVersion(ctx context.Context, version versionsapi.Version) (res configapi.AzureSEVSNPVersion, err error) {
|
||||
var versions configapi.AzureSEVSNPVersionList
|
||||
versions, err = f.FetchAzureSEVSNPVersionList(ctx, versions)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf("fetching versions list: %w", err)
|
||||
}
|
||||
get := configapi.AzureSEVSNPVersionGet{Version: versions[0]} // get latest version (as sorted reversely alphanumerically)
|
||||
get, err = f.FetchAzureSEVSNPVersion(ctx, get, version)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf("failed fetching version: %w", err)
|
||||
}
|
||||
return get.AzureSEVSNPVersion, nil
|
||||
}
|
||||
|
||||
func fetchBytesFromRawURL(ctx context.Context, urlString string, client HTTPClient) ([]byte, error) {
|
||||
url, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse version url %s: %w", urlString, err)
|
||||
}
|
||||
return getFromURL(ctx, client, url)
|
||||
}
|
@ -5,11 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
Package fetcher implements a client for the versions API.
|
||||
Package fetcher implements a client for the Constellation Resource API.
|
||||
|
||||
The fetcher is used to get information from the versions API without having to
|
||||
authenticate with AWS, where the API is currently hosted. This package should be
|
||||
used in user-facing application code most of the time, like the CLI.
|
||||
|
||||
Each sub-API included in the Constellation Resource API should define it's resources by implementing types that implement apiObject.
|
||||
The new package can then call this package's Fetch function to get the resource from the API.
|
||||
To modify resources, pkg internal/api/client should be used in a similar fashion.
|
||||
*/
|
||||
package fetcher
|
||||
|
||||
@ -17,56 +21,17 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// fetcher fetches versions API resources without authentication.
|
||||
type fetcher struct {
|
||||
httpc HTTPClient
|
||||
}
|
||||
|
||||
// NewHTTPClient returns a new http client.
|
||||
func NewHTTPClient() HTTPClient {
|
||||
return &http.Client{Transport: &http.Transport{DisableKeepAlives: true}} // DisableKeepAlives fixes concurrency issue see https://stackoverflow.com/a/75816347
|
||||
}
|
||||
|
||||
func newFetcherWith(client HTTPClient) *fetcher {
|
||||
return &fetcher{
|
||||
httpc: client,
|
||||
}
|
||||
}
|
||||
|
||||
func newFetcher() *fetcher {
|
||||
return newFetcherWith(NewHTTPClient()) // DisableKeepAlives fixes concurrency issue see https://stackoverflow.com/a/75816347
|
||||
}
|
||||
|
||||
type apiObject interface {
|
||||
ValidateRequest() error
|
||||
Validate() error
|
||||
URL() (string, error)
|
||||
}
|
||||
|
||||
// getFromURL fetches the content from the given URL and returns the content as a byte slice.
|
||||
func getFromURL(ctx context.Context, client HTTPClient, sourceURL *url.URL) ([]byte, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, sourceURL.String(), http.NoBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("http status code: %d", resp.StatusCode)
|
||||
}
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func fetch[T apiObject](ctx context.Context, c HTTPClient, obj T) (T, error) {
|
||||
// Fetch fetches the given apiObject from the public Constellation CDN.
|
||||
// Fetch does not require authentication.
|
||||
func Fetch[T apiObject](ctx context.Context, c HTTPClient, obj T) (T, error) {
|
||||
if err := obj.ValidateRequest(); err != nil {
|
||||
return *new(T), fmt.Errorf("validating request for %T: %w", obj, err)
|
||||
}
|
||||
@ -123,3 +88,9 @@ func (e *NotFoundError) Unwrap() error {
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
type apiObject interface {
|
||||
ValidateRequest() error
|
||||
Validate() error
|
||||
URL() (string, error)
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package fetcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
)
|
||||
|
||||
// VersionAPIFetcher fetches version API resources without authentication.
|
||||
type VersionAPIFetcher struct {
|
||||
*fetcher
|
||||
}
|
||||
|
||||
// NewVersionAPIFetcher returns a new Fetcher.
|
||||
func NewVersionAPIFetcher() *VersionAPIFetcher {
|
||||
return &VersionAPIFetcher{newFetcher()}
|
||||
}
|
||||
|
||||
// FetchVersionList fetches the given version list from the versions API.
|
||||
func (f *VersionAPIFetcher) FetchVersionList(ctx context.Context, list versionsapi.List) (versionsapi.List, error) {
|
||||
return fetch(ctx, f.httpc, list)
|
||||
}
|
||||
|
||||
// FetchVersionLatest fetches the latest version from the versions API.
|
||||
func (f *VersionAPIFetcher) FetchVersionLatest(ctx context.Context, latest versionsapi.Latest) (versionsapi.Latest, error) {
|
||||
return fetch(ctx, f.httpc, latest)
|
||||
}
|
||||
|
||||
// FetchImageInfo fetches the given image info from the versions API.
|
||||
func (f *VersionAPIFetcher) FetchImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) (versionsapi.ImageInfo, error) {
|
||||
return fetch(ctx, f.httpc, imageInfo)
|
||||
}
|
||||
|
||||
// FetchCLIInfo fetches the given cli info from the versions API.
|
||||
func (f *VersionAPIFetcher) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) (versionsapi.CLIInfo, error) {
|
||||
return fetch(ctx, f.httpc, cliInfo)
|
||||
}
|
@ -2,7 +2,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "versionsapi",
|
||||
name = "versions",
|
||||
srcs = [
|
||||
"apiconstants.go",
|
||||
"cliinfo.go",
|
||||
@ -12,7 +12,7 @@ go_library(
|
||||
"version.go",
|
||||
"versionsapi.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi",
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versions",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/constants",
|
||||
@ -21,7 +21,7 @@ go_library(
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "versionsapi_test",
|
||||
name = "versions_test",
|
||||
srcs = [
|
||||
"cliinfo_test.go",
|
||||
"imageinfo_test.go",
|
||||
@ -29,7 +29,7 @@ go_test(
|
||||
"list_test.go",
|
||||
"version_test.go",
|
||||
],
|
||||
embed = [":versionsapi"],
|
||||
embed = [":versions"],
|
||||
deps = [
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/constants",
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
var (
|
||||
// APIV1 is the v1 API version.
|
@ -9,11 +9,12 @@ go_library(
|
||||
"main.go",
|
||||
"rm.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/cli",
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versions/cli",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versionsapi/client",
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/versions",
|
||||
"//internal/api/versions/client",
|
||||
"//internal/constants",
|
||||
"//internal/logger",
|
||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
@ -11,8 +11,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client"
|
||||
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versions/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap/zapcore"
|
||||
@ -104,7 +105,7 @@ func runAdd(cmd *cobra.Command, _ []string) (retErr error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureVersion(ctx context.Context, client *verclient.Client, kind versionsapi.VersionKind, ver versionsapi.Version, gran versionsapi.Granularity,
|
||||
func ensureVersion(ctx context.Context, client *verclient.VersionsClient, kind versionsapi.VersionKind, ver versionsapi.Version, gran versionsapi.Granularity,
|
||||
log *logger.Logger,
|
||||
) error {
|
||||
verListReq := versionsapi.List{
|
||||
@ -115,7 +116,7 @@ func ensureVersion(ctx context.Context, client *verclient.Client, kind versionsa
|
||||
Kind: kind,
|
||||
}
|
||||
verList, err := client.FetchVersionList(ctx, verListReq)
|
||||
var notFoundErr *verclient.NotFoundError
|
||||
var notFoundErr *apifetcher.NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
log.Infof("Version list for %s versions under %q does not exist. Creating new list", gran.String(), ver.Major())
|
||||
verList = verListReq
|
||||
@ -144,14 +145,14 @@ func ensureVersion(ctx context.Context, client *verclient.Client, kind versionsa
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateLatest(ctx context.Context, client *verclient.Client, kind versionsapi.VersionKind, ver versionsapi.Version, log *logger.Logger) error {
|
||||
func updateLatest(ctx context.Context, client *verclient.VersionsClient, kind versionsapi.VersionKind, ver versionsapi.Version, log *logger.Logger) error {
|
||||
latest := versionsapi.Latest{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Kind: kind,
|
||||
}
|
||||
latest, err := client.FetchVersionLatest(ctx, latest)
|
||||
var notFoundErr *verclient.NotFoundError
|
||||
var notFoundErr *apifetcher.NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
log.Debugf("Latest version for ref %q and stream %q not found", ver.Ref, ver.Stream)
|
||||
} else if err != nil {
|
@ -10,8 +10,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versions/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap/zapcore"
|
@ -16,8 +16,9 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
"golang.org/x/mod/semver"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client"
|
||||
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versions/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
)
|
||||
|
||||
@ -63,7 +64,7 @@ func runList(cmd *cobra.Command, _ []string) error {
|
||||
} else {
|
||||
log.Debugf("Getting minor versions")
|
||||
minorVersions, err = listMinorVersions(cmd.Context(), client, flags.ref, flags.stream)
|
||||
var errNotFound *verclient.NotFoundError
|
||||
var errNotFound *apifetcher.NotFoundError
|
||||
if err != nil && errors.As(err, &errNotFound) {
|
||||
log.Infof("No minor versions found for ref %q and stream %q.", flags.ref, flags.stream)
|
||||
return nil
|
||||
@ -74,7 +75,7 @@ func runList(cmd *cobra.Command, _ []string) error {
|
||||
|
||||
log.Debugf("Getting patch versions")
|
||||
patchVersions, err := listPatchVersions(cmd.Context(), client, flags.ref, flags.stream, minorVersions)
|
||||
var errNotFound *verclient.NotFoundError
|
||||
var errNotFound *apifetcher.NotFoundError
|
||||
if err != nil && errors.As(err, &errNotFound) {
|
||||
log.Infof("No patch versions found for ref %q, stream %q and minor versions %v.", flags.ref, flags.stream, minorVersions)
|
||||
return nil
|
||||
@ -104,7 +105,7 @@ func runList(cmd *cobra.Command, _ []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func listMinorVersions(ctx context.Context, client *verclient.Client, ref string, stream string) ([]string, error) {
|
||||
func listMinorVersions(ctx context.Context, client *verclient.VersionsClient, ref string, stream string) ([]string, error) {
|
||||
list := versionsapi.List{
|
||||
Ref: ref,
|
||||
Stream: stream,
|
||||
@ -120,7 +121,7 @@ func listMinorVersions(ctx context.Context, client *verclient.Client, ref string
|
||||
return list.Versions, nil
|
||||
}
|
||||
|
||||
func listPatchVersions(ctx context.Context, client *verclient.Client, ref string, stream string, minorVer []string,
|
||||
func listPatchVersions(ctx context.Context, client *verclient.VersionsClient, ref string, stream string, minorVer []string,
|
||||
) ([]versionsapi.Version, error) {
|
||||
var patchVers []versionsapi.Version
|
||||
|
@ -24,8 +24,9 @@ import (
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/aws/smithy-go"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client"
|
||||
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versions/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
gaxv2 "github.com/googleapis/gax-go/v2"
|
||||
"github.com/spf13/cobra"
|
||||
@ -157,7 +158,7 @@ func deleteRef(ctx context.Context, clients rmImageClients, ref string, dryrun b
|
||||
log.Infof("Listing versions of stream %s", stream)
|
||||
|
||||
minorVersions, err := listMinorVersions(ctx, clients.version, ref, stream)
|
||||
var notFoundErr *verclient.NotFoundError
|
||||
var notFoundErr *apifetcher.NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
log.Debugf("No minor versions found for stream %s", stream)
|
||||
continue
|
||||
@ -202,7 +203,7 @@ func deleteImage(ctx context.Context, clients rmImageClients, ver versionsapi.Ve
|
||||
Version: ver.Version,
|
||||
}
|
||||
imageInfo, err := clients.version.FetchImageInfo(ctx, imageInfo)
|
||||
var notFound *verclient.NotFoundError
|
||||
var notFound *apifetcher.NotFoundError
|
||||
if errors.As(err, ¬Found) {
|
||||
log.Warnf("Image info for %s not found", ver.Version)
|
||||
log.Warnf("Skipping image deletion")
|
||||
@ -239,7 +240,7 @@ func deleteImage(ctx context.Context, clients rmImageClients, ver versionsapi.Ve
|
||||
}
|
||||
|
||||
type rmImageClients struct {
|
||||
version *verclient.Client
|
||||
version *verclient.VersionsClient
|
||||
gcp *gcpClient
|
||||
aws *awsClient
|
||||
az *azureClient
|
16
internal/api/versions/client/BUILD.bazel
Normal file
16
internal/api/versions/client/BUILD.bazel
Normal file
@ -0,0 +1,16 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "client",
|
||||
srcs = ["client.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versions/client",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/client",
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/versions",
|
||||
"//internal/constants",
|
||||
"//internal/logger",
|
||||
"@org_golang_x_mod//semver",
|
||||
],
|
||||
)
|
230
internal/api/versions/client/client.go
Normal file
230
internal/api/versions/client/client.go
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
Package client provides a versions API specific implementation of the general API client.
|
||||
*/
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
|
||||
apiclient "github.com/edgelesssys/constellation/v2/internal/api/client"
|
||||
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
)
|
||||
|
||||
// VersionsClient is a client for the versions API.
|
||||
type VersionsClient struct {
|
||||
*apiclient.Client
|
||||
}
|
||||
|
||||
// NewClient creates a new client for the versions API.
|
||||
func NewClient(ctx context.Context, region, bucket, distributionID string, dryRun bool,
|
||||
log *logger.Logger,
|
||||
) (*VersionsClient, error) {
|
||||
genericClient, err := apiclient.NewClient(ctx, region, bucket, distributionID, dryRun, log)
|
||||
return &VersionsClient{genericClient}, err
|
||||
}
|
||||
|
||||
// NewReadOnlyClient creates a new read-only client.
|
||||
// This client can be used to fetch objects but cannot write updates.
|
||||
func NewReadOnlyClient(ctx context.Context, region, bucket, distributionID string,
|
||||
log *logger.Logger,
|
||||
) (*VersionsClient, error) {
|
||||
genericClient, err := apiclient.NewReadOnlyClient(ctx, region, bucket, distributionID, log)
|
||||
return &VersionsClient{genericClient}, err
|
||||
}
|
||||
|
||||
// FetchVersionList fetches the given version list from the versions API.
|
||||
func (c *VersionsClient) FetchVersionList(ctx context.Context, list versionsapi.List) (versionsapi.List, error) {
|
||||
return apiclient.Fetch(ctx, c.Client, list)
|
||||
}
|
||||
|
||||
// UpdateVersionList updates the given version list in the versions API.
|
||||
func (c *VersionsClient) UpdateVersionList(ctx context.Context, list versionsapi.List) error {
|
||||
semver.Sort(list.Versions)
|
||||
return apiclient.Update(ctx, c.Client, list)
|
||||
}
|
||||
|
||||
// FetchVersionLatest fetches the latest version from the versions API.
|
||||
func (c *VersionsClient) FetchVersionLatest(ctx context.Context, latest versionsapi.Latest) (versionsapi.Latest, error) {
|
||||
return apiclient.Fetch(ctx, c.Client, latest)
|
||||
}
|
||||
|
||||
// UpdateVersionLatest updates the latest version in the versions API.
|
||||
func (c *VersionsClient) UpdateVersionLatest(ctx context.Context, latest versionsapi.Latest) error {
|
||||
return apiclient.Update(ctx, c.Client, latest)
|
||||
}
|
||||
|
||||
// FetchImageInfo fetches the given image info from the versions API.
|
||||
func (c *VersionsClient) FetchImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) (versionsapi.ImageInfo, error) {
|
||||
return apiclient.Fetch(ctx, c.Client, imageInfo)
|
||||
}
|
||||
|
||||
// UpdateImageInfo updates the given image info in the versions API.
|
||||
func (c *VersionsClient) UpdateImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) error {
|
||||
return apiclient.Update(ctx, c.Client, imageInfo)
|
||||
}
|
||||
|
||||
// FetchCLIInfo fetches the given CLI info from the versions API.
|
||||
func (c *VersionsClient) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) (versionsapi.CLIInfo, error) {
|
||||
return apiclient.Fetch(ctx, c.Client, cliInfo)
|
||||
}
|
||||
|
||||
// UpdateCLIInfo updates the given CLI info in the versions API.
|
||||
func (c *VersionsClient) UpdateCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) error {
|
||||
return apiclient.Update(ctx, c.Client, cliInfo)
|
||||
}
|
||||
|
||||
// DeleteRef deletes the given ref from the versions API.
|
||||
func (c *VersionsClient) DeleteRef(ctx context.Context, ref string) error {
|
||||
if err := versionsapi.ValidateRef(ref); err != nil {
|
||||
return fmt.Errorf("validating ref: %w", err)
|
||||
}
|
||||
|
||||
refPath := path.Join(constants.CDNAPIPrefix, "ref", ref)
|
||||
if err := c.Client.DeletePath(ctx, refPath); err != nil {
|
||||
return fmt.Errorf("deleting ref path: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteVersion deletes the given version from the versions API.
|
||||
// The version will be removed from version lists and latest versions, and the versioned
|
||||
// objects are deleted.
|
||||
// Notice that the versions API can get into an inconsistent state if the version is the latest
|
||||
// version but there is no older version of the same minor version available.
|
||||
// Manual update of latest versions is required in this case.
|
||||
func (c *VersionsClient) DeleteVersion(ctx context.Context, ver versionsapi.Version) error {
|
||||
var retErr error
|
||||
|
||||
c.Client.Log.Debugf("Deleting version %s from minor version list", ver.Version)
|
||||
possibleNewLatest, err := c.deleteVersionFromMinorVersionList(ctx, ver)
|
||||
if err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("removing from minor version list: %w", err))
|
||||
}
|
||||
|
||||
c.Client.Log.Debugf("Checking latest version for %s", ver.Version)
|
||||
if err := c.deleteVersionFromLatest(ctx, ver, possibleNewLatest); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("updating latest version: %w", err))
|
||||
}
|
||||
|
||||
c.Client.Log.Debugf("Deleting artifact path %s for %s", ver.ArtifactPath(versionsapi.APIV1), ver.Version)
|
||||
if err := c.Client.DeletePath(ctx, ver.ArtifactPath(versionsapi.APIV1)); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting artifact path: %w", err))
|
||||
}
|
||||
|
||||
return retErr
|
||||
}
|
||||
|
||||
func (c *VersionsClient) deleteVersionFromMinorVersionList(ctx context.Context, ver versionsapi.Version,
|
||||
) (*versionsapi.Latest, error) {
|
||||
minorList := versionsapi.List{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Granularity: versionsapi.GranularityMinor,
|
||||
Base: ver.WithGranularity(versionsapi.GranularityMinor),
|
||||
Kind: versionsapi.VersionKindImage,
|
||||
}
|
||||
c.Client.Log.Debugf("Fetching minor version list for version %s", ver.Version)
|
||||
minorList, err := c.FetchVersionList(ctx, minorList)
|
||||
var notFoundErr *apifetcher.NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
c.Client.Log.Warnf("Minor version list for version %s not found", ver.Version)
|
||||
c.Client.Log.Warnf("Skipping update of minor version list")
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("fetching minor version list for version %s: %w", ver.Version, err)
|
||||
}
|
||||
|
||||
if !minorList.Contains(ver.Version) {
|
||||
c.Client.Log.Warnf("Version %s is not in minor version list %s", ver.Version, minorList.JSONPath())
|
||||
c.Client.Log.Warnf("Skipping update of minor version list")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
semver.Sort(minorList.Versions)
|
||||
for i, v := range minorList.Versions {
|
||||
if v == ver.Version {
|
||||
minorList.Versions = append(minorList.Versions[:i], minorList.Versions[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var latest *versionsapi.Latest
|
||||
if len(minorList.Versions) != 0 {
|
||||
latest = &versionsapi.Latest{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Kind: versionsapi.VersionKindImage,
|
||||
Version: minorList.Versions[len(minorList.Versions)-1],
|
||||
}
|
||||
c.Client.Log.Debugf("Possible latest version replacement %q", latest.Version)
|
||||
}
|
||||
|
||||
if c.Client.DryRun {
|
||||
c.Client.Log.Debugf("DryRun: Updating minor version list %s to %v", minorList.JSONPath(), minorList)
|
||||
return latest, nil
|
||||
}
|
||||
|
||||
c.Client.Log.Debugf("Updating minor version list %s", minorList.JSONPath())
|
||||
if err := c.UpdateVersionList(ctx, minorList); err != nil {
|
||||
return latest, fmt.Errorf("updating minor version list %s: %w", minorList.JSONPath(), err)
|
||||
}
|
||||
|
||||
c.Client.Log.Debugf("Removed version %s from minor version list %s", ver.Version, minorList.JSONPath())
|
||||
return latest, nil
|
||||
}
|
||||
|
||||
func (c *VersionsClient) deleteVersionFromLatest(ctx context.Context, ver versionsapi.Version, possibleNewLatest *versionsapi.Latest,
|
||||
) error {
|
||||
latest := versionsapi.Latest{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Kind: versionsapi.VersionKindImage,
|
||||
}
|
||||
c.Client.Log.Debugf("Fetching latest version from %s", latest.JSONPath())
|
||||
latest, err := c.FetchVersionLatest(ctx, latest)
|
||||
var notFoundErr *apifetcher.NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
c.Client.Log.Warnf("Latest version for %s not found", latest.JSONPath())
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("fetching latest version: %w", err)
|
||||
}
|
||||
|
||||
if latest.Version != ver.Version {
|
||||
c.Client.Log.Debugf("Latest version is %s, not the deleted version %s", latest.Version, ver.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
if possibleNewLatest == nil {
|
||||
c.Client.Log.Errorf("Latest version is %s, but no new latest version was found", latest.Version)
|
||||
c.Client.Log.Errorf("A manual update of latest at %s might be needed", latest.JSONPath())
|
||||
return fmt.Errorf("latest version is %s, but no new latest version was found", latest.Version)
|
||||
}
|
||||
|
||||
if c.Client.DryRun {
|
||||
c.Client.Log.Debugf("Would update latest version from %s to %s", latest.Version, possibleNewLatest.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Client.Log.Infof("Updating latest version from %s to %s", latest.Version, possibleNewLatest.Version)
|
||||
if err := c.UpdateVersionLatest(ctx, *possibleNewLatest); err != nil {
|
||||
return fmt.Errorf("updating latest version: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"errors"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"testing"
|
25
internal/api/versions/fetcher/BUILD.bazel
Normal file
25
internal/api/versions/fetcher/BUILD.bazel
Normal file
@ -0,0 +1,25 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "fetcher",
|
||||
srcs = ["fetcher.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versions/fetcher",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/versions",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "fetcher_test",
|
||||
srcs = ["fetcher_test.go"],
|
||||
embed = [":fetcher"],
|
||||
deps = [
|
||||
"//internal/api/versions",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
"@org_uber_go_goleak//:goleak",
|
||||
],
|
||||
)
|
44
internal/api/versions/fetcher/fetcher.go
Normal file
44
internal/api/versions/fetcher/fetcher.go
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package fetcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
)
|
||||
|
||||
// Fetcher fetches version API resources without authentication.
|
||||
type Fetcher struct {
|
||||
fetcher.HTTPClient
|
||||
}
|
||||
|
||||
// New returns a new Fetcher.
|
||||
func New() *Fetcher {
|
||||
return &Fetcher{fetcher.NewHTTPClient()}
|
||||
}
|
||||
|
||||
// FetchVersionList fetches the given version list from the versions API.
|
||||
func (f *Fetcher) FetchVersionList(ctx context.Context, list versions.List) (versions.List, error) {
|
||||
return fetcher.Fetch(ctx, f.HTTPClient, list)
|
||||
}
|
||||
|
||||
// FetchVersionLatest fetches the latest version from the versions API.
|
||||
func (f *Fetcher) FetchVersionLatest(ctx context.Context, latest versions.Latest) (versions.Latest, error) {
|
||||
return fetcher.Fetch(ctx, f.HTTPClient, latest)
|
||||
}
|
||||
|
||||
// FetchImageInfo fetches the given image info from the versions API.
|
||||
func (f *Fetcher) FetchImageInfo(ctx context.Context, imageInfo versions.ImageInfo) (versions.ImageInfo, error) {
|
||||
return fetcher.Fetch(ctx, f.HTTPClient, imageInfo)
|
||||
}
|
||||
|
||||
// FetchCLIInfo fetches the given cli info from the versions API.
|
||||
func (f *Fetcher) FetchCLIInfo(ctx context.Context, cliInfo versions.CLIInfo) (versions.CLIInfo, error) {
|
||||
return fetcher.Fetch(ctx, f.HTTPClient, cliInfo)
|
||||
}
|
@ -14,7 +14,7 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/goleak"
|
||||
@ -190,7 +190,7 @@ func TestFetchVersionList(t *testing.T) {
|
||||
return tc.serverResp
|
||||
})
|
||||
|
||||
fetcher := VersionAPIFetcher{&fetcher{httpc: client}}
|
||||
fetcher := Fetcher{client}
|
||||
|
||||
list, err := fetcher.FetchVersionList(context.Background(), tc.list)
|
||||
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"errors"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"testing"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"errors"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"testing"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"errors"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"testing"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package versionsapi
|
||||
package versions
|
||||
|
||||
import (
|
||||
"fmt"
|
@ -17,4 +17,4 @@ in these helper methods.
|
||||
The package also provides helper functions that can be used in context of the versions API,
|
||||
e.g. to validate versions.
|
||||
*/
|
||||
package versionsapi
|
||||
package versions
|
@ -1,472 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
Package client provides a client for the versions API.
|
||||
|
||||
The client needs to be authenticated with AWS. It should be used in internal
|
||||
development and CI tools for administrative tasks. For just fetching information
|
||||
from the API, use the fetcher package instead.
|
||||
|
||||
Needed IAM permissions for read mode:
|
||||
- "s3:GetObject"
|
||||
- "s3:ListBucket"
|
||||
|
||||
Additional needed IAM permissions for write mode:
|
||||
- "s3:PutObject"
|
||||
- "s3:DeleteObject"
|
||||
- "cloudfront:CreateInvalidation"
|
||||
|
||||
Thread-safety of the bucket is not guaranteed. The client is not thread-safe.
|
||||
*/
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/cloudfront"
|
||||
cftypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"golang.org/x/mod/semver"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
)
|
||||
|
||||
// Client is the client for the versions API.
|
||||
type Client struct {
|
||||
config aws.Config
|
||||
cloudfrontClient *cloudfront.Client
|
||||
s3Client *s3.Client
|
||||
uploadClient *s3manager.Uploader
|
||||
bucket string
|
||||
distributionID string
|
||||
cacheInvalidationWaitTimeout time.Duration
|
||||
|
||||
dirtyPaths []string // written paths to be invalidated
|
||||
dryRun bool // no write operations are performed
|
||||
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
// NewReadOnlyClient creates a new read-only client.
|
||||
// This client can be used to fetch objects but cannot write updates.
|
||||
func NewReadOnlyClient(ctx context.Context, region, bucket, distributionID string,
|
||||
log *logger.Logger,
|
||||
) (*Client, error) {
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(region))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s3c := s3.NewFromConfig(cfg)
|
||||
|
||||
return &Client{
|
||||
config: cfg,
|
||||
s3Client: s3c,
|
||||
bucket: bucket,
|
||||
distributionID: distributionID,
|
||||
dryRun: true,
|
||||
log: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewClient creates a new client for the versions API.
|
||||
func NewClient(ctx context.Context, region, bucket, distributionID string, dryRun bool,
|
||||
log *logger.Logger,
|
||||
) (*Client, error) {
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(region))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cloudfrontC := cloudfront.NewFromConfig(cfg)
|
||||
s3C := s3.NewFromConfig(cfg)
|
||||
uploadC := s3manager.NewUploader(s3C)
|
||||
|
||||
return &Client{
|
||||
config: cfg,
|
||||
cloudfrontClient: cloudfrontC,
|
||||
s3Client: s3C,
|
||||
uploadClient: uploadC,
|
||||
bucket: bucket,
|
||||
distributionID: distributionID,
|
||||
dryRun: dryRun,
|
||||
log: log,
|
||||
cacheInvalidationWaitTimeout: 10 * time.Minute,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FetchVersionList fetches the given version list from the versions API.
|
||||
func (c *Client) FetchVersionList(ctx context.Context, list versionsapi.List) (versionsapi.List, error) {
|
||||
return fetch(ctx, c, list)
|
||||
}
|
||||
|
||||
// UpdateVersionList updates the given version list in the versions API.
|
||||
func (c *Client) UpdateVersionList(ctx context.Context, list versionsapi.List) error {
|
||||
semver.Sort(list.Versions)
|
||||
return update(ctx, c, list)
|
||||
}
|
||||
|
||||
// FetchVersionLatest fetches the latest version from the versions API.
|
||||
func (c *Client) FetchVersionLatest(ctx context.Context, latest versionsapi.Latest) (versionsapi.Latest, error) {
|
||||
return fetch(ctx, c, latest)
|
||||
}
|
||||
|
||||
// UpdateVersionLatest updates the latest version in the versions API.
|
||||
func (c *Client) UpdateVersionLatest(ctx context.Context, latest versionsapi.Latest) error {
|
||||
return update(ctx, c, latest)
|
||||
}
|
||||
|
||||
// FetchImageInfo fetches the given image info from the versions API.
|
||||
func (c *Client) FetchImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) (versionsapi.ImageInfo, error) {
|
||||
return fetch(ctx, c, imageInfo)
|
||||
}
|
||||
|
||||
// UpdateImageInfo updates the given image info in the versions API.
|
||||
func (c *Client) UpdateImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) error {
|
||||
return update(ctx, c, imageInfo)
|
||||
}
|
||||
|
||||
// FetchCLIInfo fetches the given CLI info from the versions API.
|
||||
func (c *Client) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) (versionsapi.CLIInfo, error) {
|
||||
return fetch(ctx, c, cliInfo)
|
||||
}
|
||||
|
||||
// UpdateCLIInfo updates the given CLI info in the versions API.
|
||||
func (c *Client) UpdateCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) error {
|
||||
return update(ctx, c, cliInfo)
|
||||
}
|
||||
|
||||
// DeleteRef deletes the given ref from the versions API.
|
||||
func (c *Client) DeleteRef(ctx context.Context, ref string) error {
|
||||
if err := versionsapi.ValidateRef(ref); err != nil {
|
||||
return fmt.Errorf("validating ref: %w", err)
|
||||
}
|
||||
|
||||
refPath := path.Join(constants.CDNAPIPrefix, "ref", ref)
|
||||
if err := c.deletePath(ctx, refPath); err != nil {
|
||||
return fmt.Errorf("deleting ref path: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteVersion deletes the given version from the versions API.
|
||||
// The version will be removed from version lists and latest versions, and the versioned
|
||||
// objects are deleted.
|
||||
// Notice that the versions API can get into an inconsistent state if the version is the latest
|
||||
// version but there is no older version of the same minor version available.
|
||||
// Manual update of latest versions is required in this case.
|
||||
func (c *Client) DeleteVersion(ctx context.Context, ver versionsapi.Version) error {
|
||||
var retErr error
|
||||
|
||||
c.log.Debugf("Deleting version %s from minor version list", ver.Version)
|
||||
possibleNewLatest, err := c.deleteVersionFromMinorVersionList(ctx, ver)
|
||||
if err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("removing from minor version list: %w", err))
|
||||
}
|
||||
|
||||
c.log.Debugf("Checking latest version for %s", ver.Version)
|
||||
if err := c.deleteVersionFromLatest(ctx, ver, possibleNewLatest); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("updating latest version: %w", err))
|
||||
}
|
||||
|
||||
c.log.Debugf("Deleting artifact path %s for %s", ver.ArtifactPath(versionsapi.APIV1), ver.Version)
|
||||
if err := c.deletePath(ctx, ver.ArtifactPath(versionsapi.APIV1)); err != nil {
|
||||
retErr = errors.Join(retErr, fmt.Errorf("deleting artifact path: %w", err))
|
||||
}
|
||||
|
||||
return retErr
|
||||
}
|
||||
|
||||
// InvalidateCache invalidates the CDN cache for the paths that have been written.
|
||||
// The function should be deferred after the client has been created.
|
||||
func (c *Client) InvalidateCache(ctx context.Context) error {
|
||||
if len(c.dirtyPaths) == 0 {
|
||||
c.log.Debugf("No dirty paths, skipping cache invalidation")
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.dryRun {
|
||||
c.log.Debugf("DryRun: cloudfront create invalidation {DistributionID: %v, Paths: %v}", c.distributionID, c.dirtyPaths)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.log.Debugf("Paths to invalidate: %v", c.dirtyPaths)
|
||||
|
||||
in := &cloudfront.CreateInvalidationInput{
|
||||
DistributionId: &c.distributionID,
|
||||
InvalidationBatch: &cftypes.InvalidationBatch{
|
||||
CallerReference: ptr(fmt.Sprintf("%d", time.Now().Unix())),
|
||||
Paths: &cftypes.Paths{
|
||||
Items: c.dirtyPaths,
|
||||
Quantity: ptr(int32(len(c.dirtyPaths))),
|
||||
},
|
||||
},
|
||||
}
|
||||
invalidation, err := c.cloudfrontClient.CreateInvalidation(ctx, in)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating invalidation: %w", err)
|
||||
}
|
||||
|
||||
c.log.Debugf("Waiting for invalidation %s to complete", *invalidation.Invalidation.Id)
|
||||
waiter := cloudfront.NewInvalidationCompletedWaiter(c.cloudfrontClient)
|
||||
waitIn := &cloudfront.GetInvalidationInput{
|
||||
DistributionId: &c.distributionID,
|
||||
Id: invalidation.Invalidation.Id,
|
||||
}
|
||||
if err := waiter.Wait(ctx, waitIn, c.cacheInvalidationWaitTimeout); err != nil {
|
||||
return fmt.Errorf("waiting for invalidation to complete: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type apiObject interface {
|
||||
ValidateRequest() error
|
||||
Validate() error
|
||||
JSONPath() string
|
||||
}
|
||||
|
||||
func fetch[T apiObject](ctx context.Context, c *Client, obj T) (T, error) {
|
||||
if err := obj.ValidateRequest(); err != nil {
|
||||
return *new(T), fmt.Errorf("validating request for %T: %w", obj, err)
|
||||
}
|
||||
|
||||
in := &s3.GetObjectInput{
|
||||
Bucket: &c.bucket,
|
||||
Key: ptr(obj.JSONPath()),
|
||||
}
|
||||
|
||||
c.log.Debugf("Fetching %T from s3: %s", obj, obj.JSONPath())
|
||||
out, err := c.s3Client.GetObject(ctx, in)
|
||||
var noSuchkey *s3types.NoSuchKey
|
||||
if errors.As(err, &noSuchkey) {
|
||||
return *new(T), &NotFoundError{err: err}
|
||||
} else if err != nil {
|
||||
return *new(T), fmt.Errorf("getting s3 object at %s: %w", obj.JSONPath(), err)
|
||||
}
|
||||
defer out.Body.Close()
|
||||
|
||||
var newObj T
|
||||
if err := json.NewDecoder(out.Body).Decode(&newObj); err != nil {
|
||||
return *new(T), fmt.Errorf("decoding %T: %w", obj, err)
|
||||
}
|
||||
|
||||
if newObj.Validate() != nil {
|
||||
return *new(T), fmt.Errorf("received invalid %T: %w", newObj, newObj.Validate())
|
||||
}
|
||||
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
func update[T apiObject](ctx context.Context, c *Client, obj T) error {
|
||||
if err := obj.Validate(); err != nil {
|
||||
return fmt.Errorf("validating %T struct: %w", obj, err)
|
||||
}
|
||||
|
||||
rawJSON, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshaling %T struct: %w", obj, err)
|
||||
}
|
||||
|
||||
if c.dryRun {
|
||||
c.log.Debugf("DryRun: s3 put object {Bucket: %v, Key: %v, Body: %v", c.bucket, obj.JSONPath(), string(rawJSON))
|
||||
return nil
|
||||
}
|
||||
|
||||
in := &s3.PutObjectInput{
|
||||
Bucket: &c.bucket,
|
||||
Key: ptr(obj.JSONPath()),
|
||||
Body: bytes.NewBuffer(rawJSON),
|
||||
}
|
||||
|
||||
c.dirtyPaths = append(c.dirtyPaths, "/"+obj.JSONPath())
|
||||
|
||||
c.log.Debugf("Uploading %T to s3: %v", obj, obj.JSONPath())
|
||||
if _, err := c.uploadClient.Upload(ctx, in); err != nil {
|
||||
return fmt.Errorf("uploading %T: %w", obj, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) deleteVersionFromMinorVersionList(ctx context.Context, ver versionsapi.Version,
|
||||
) (*versionsapi.Latest, error) {
|
||||
minorList := versionsapi.List{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Granularity: versionsapi.GranularityMinor,
|
||||
Base: ver.WithGranularity(versionsapi.GranularityMinor),
|
||||
Kind: versionsapi.VersionKindImage,
|
||||
}
|
||||
c.log.Debugf("Fetching minor version list for version %s", ver.Version)
|
||||
minorList, err := c.FetchVersionList(ctx, minorList)
|
||||
var notFoundErr *NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
c.log.Warnf("Minor version list for version %s not found", ver.Version)
|
||||
c.log.Warnf("Skipping update of minor version list")
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("fetching minor version list for version %s: %w", ver.Version, err)
|
||||
}
|
||||
|
||||
if !minorList.Contains(ver.Version) {
|
||||
c.log.Warnf("Version %s is not in minor version list %s", ver.Version, minorList.JSONPath())
|
||||
c.log.Warnf("Skipping update of minor version list")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
semver.Sort(minorList.Versions)
|
||||
for i, v := range minorList.Versions {
|
||||
if v == ver.Version {
|
||||
minorList.Versions = append(minorList.Versions[:i], minorList.Versions[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var latest *versionsapi.Latest
|
||||
if len(minorList.Versions) != 0 {
|
||||
latest = &versionsapi.Latest{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Kind: versionsapi.VersionKindImage,
|
||||
Version: minorList.Versions[len(minorList.Versions)-1],
|
||||
}
|
||||
c.log.Debugf("Possible latest version replacement %q", latest.Version)
|
||||
}
|
||||
|
||||
if c.dryRun {
|
||||
c.log.Debugf("DryRun: Updating minor version list %s to %v", minorList.JSONPath(), minorList)
|
||||
return latest, nil
|
||||
}
|
||||
|
||||
c.log.Debugf("Updating minor version list %s", minorList.JSONPath())
|
||||
if err := c.UpdateVersionList(ctx, minorList); err != nil {
|
||||
return latest, fmt.Errorf("updating minor version list %s: %w", minorList.JSONPath(), err)
|
||||
}
|
||||
|
||||
c.log.Debugf("Removed version %s from minor version list %s", ver.Version, minorList.JSONPath())
|
||||
return latest, nil
|
||||
}
|
||||
|
||||
func (c *Client) deleteVersionFromLatest(ctx context.Context, ver versionsapi.Version, possibleNewLatest *versionsapi.Latest,
|
||||
) error {
|
||||
latest := versionsapi.Latest{
|
||||
Ref: ver.Ref,
|
||||
Stream: ver.Stream,
|
||||
Kind: versionsapi.VersionKindImage,
|
||||
}
|
||||
c.log.Debugf("Fetching latest version from %s", latest.JSONPath())
|
||||
latest, err := c.FetchVersionLatest(ctx, latest)
|
||||
var notFoundErr *NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
c.log.Warnf("Latest version for %s not found", latest.JSONPath())
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("fetching latest version: %w", err)
|
||||
}
|
||||
|
||||
if latest.Version != ver.Version {
|
||||
c.log.Debugf("Latest version is %s, not the deleted version %s", latest.Version, ver.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
if possibleNewLatest == nil {
|
||||
c.log.Errorf("Latest version is %s, but no new latest version was found", latest.Version)
|
||||
c.log.Errorf("A manual update of latest at %s might be needed", latest.JSONPath())
|
||||
return fmt.Errorf("latest version is %s, but no new latest version was found", latest.Version)
|
||||
}
|
||||
|
||||
if c.dryRun {
|
||||
c.log.Debugf("Would update latest version from %s to %s", latest.Version, possibleNewLatest.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.log.Infof("Updating latest version from %s to %s", latest.Version, possibleNewLatest.Version)
|
||||
if err := c.UpdateVersionLatest(ctx, *possibleNewLatest); err != nil {
|
||||
return fmt.Errorf("updating latest version: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) deletePath(ctx context.Context, path string) error {
|
||||
listIn := &s3.ListObjectsV2Input{
|
||||
Bucket: &c.bucket,
|
||||
Prefix: &path,
|
||||
}
|
||||
c.log.Debugf("Listing objects in %s", path)
|
||||
objs := []s3types.Object{}
|
||||
out := &s3.ListObjectsV2Output{IsTruncated: true}
|
||||
for out.IsTruncated {
|
||||
var err error
|
||||
out, err = c.s3Client.ListObjectsV2(ctx, listIn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing objects in %s: %w", path, err)
|
||||
}
|
||||
objs = append(objs, out.Contents...)
|
||||
}
|
||||
c.log.Debugf("Found %d objects in %s", len(objs), path)
|
||||
|
||||
if len(objs) == 0 {
|
||||
c.log.Warnf("Path %s is already empty", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
objIDs := make([]s3types.ObjectIdentifier, len(objs))
|
||||
for i, obj := range objs {
|
||||
objIDs[i] = s3types.ObjectIdentifier{Key: obj.Key}
|
||||
}
|
||||
|
||||
if c.dryRun {
|
||||
c.log.Debugf("DryRun: Deleting %d objects with IDs %v", len(objs), objIDs)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.dirtyPaths = append(c.dirtyPaths, "/"+path)
|
||||
|
||||
deleteIn := &s3.DeleteObjectsInput{
|
||||
Bucket: &c.bucket,
|
||||
Delete: &s3types.Delete{
|
||||
Objects: objIDs,
|
||||
},
|
||||
}
|
||||
c.log.Debugf("Deleting %d objects in %s", len(objs), path)
|
||||
if _, err := c.s3Client.DeleteObjects(ctx, deleteIn); err != nil {
|
||||
return fmt.Errorf("deleting objects in %s: %w", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotFoundError is an error that is returned when a resource is not found.
|
||||
type NotFoundError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *NotFoundError) Error() string {
|
||||
return fmt.Sprintf("the requested resource was not found: %s", e.err.Error())
|
||||
}
|
||||
|
||||
func (e *NotFoundError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func ptr[T any](t T) *T {
|
||||
return &t
|
||||
}
|
@ -13,7 +13,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/measurements",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/sigstore",
|
||||
"//internal/variant",
|
||||
@ -28,7 +28,7 @@ go_test(
|
||||
srcs = ["measurements_test.go"],
|
||||
embed = [":measurements"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/sigstore",
|
||||
"//internal/variant",
|
||||
|
@ -7,7 +7,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/measurements/measurement-generator",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/sigstore",
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
|
@ -31,7 +31,7 @@ import (
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
|
@ -5,6 +5,7 @@ go_library(
|
||||
name = "config",
|
||||
srcs = [
|
||||
"attestation.go",
|
||||
"attestationversion.go",
|
||||
"azure.go",
|
||||
"config.go",
|
||||
"config_doc.go",
|
||||
@ -18,9 +19,9 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/config",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/configapi",
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/api/attestationconfig/fetcher",
|
||||
"//internal/api/versions",
|
||||
"//internal/attestation/idkeydigest",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
@ -44,14 +45,15 @@ go_test(
|
||||
name = "config_test",
|
||||
srcs = [
|
||||
"attestation_test.go",
|
||||
"attestationversion_test.go",
|
||||
"config_test.go",
|
||||
"validation_test.go",
|
||||
],
|
||||
data = glob(["testdata/**"]),
|
||||
embed = [":config"],
|
||||
deps = [
|
||||
"//internal/api/configapi",
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/attestationconfig",
|
||||
"//internal/api/versions",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/config/instancetypes",
|
||||
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package configapi
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package configapi
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
@ -11,9 +11,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
@ -27,16 +28,16 @@ type AzureSEVSNP struct {
|
||||
Measurements measurements.M `json:"measurements" yaml:"measurements" validate:"required,no_placeholders"`
|
||||
// description: |
|
||||
// Lowest acceptable bootloader version.
|
||||
BootloaderVersion configapi.AttestationVersion `json:"bootloaderVersion" yaml:"bootloaderVersion"`
|
||||
BootloaderVersion AttestationVersion `json:"bootloaderVersion" yaml:"bootloaderVersion"`
|
||||
// description: |
|
||||
// Lowest acceptable TEE version.
|
||||
TEEVersion configapi.AttestationVersion `json:"teeVersion" yaml:"teeVersion"`
|
||||
TEEVersion AttestationVersion `json:"teeVersion" yaml:"teeVersion"`
|
||||
// description: |
|
||||
// Lowest acceptable SEV-SNP version.
|
||||
SNPVersion configapi.AttestationVersion `json:"snpVersion" yaml:"snpVersion"`
|
||||
SNPVersion AttestationVersion `json:"snpVersion" yaml:"snpVersion"`
|
||||
// description: |
|
||||
// Lowest acceptable microcode version.
|
||||
MicrocodeVersion configapi.AttestationVersion `json:"microcodeVersion" yaml:"microcodeVersion"`
|
||||
MicrocodeVersion AttestationVersion `json:"microcodeVersion" yaml:"microcodeVersion"`
|
||||
// description: |
|
||||
// Configuration for validating the firmware signature.
|
||||
FirmwareSignerConfig SNPFirmwareSignerConfig `json:"firmwareSignerConfig" yaml:"firmwareSignerConfig"`
|
||||
@ -50,10 +51,10 @@ type AzureSEVSNP struct {
|
||||
func DefaultForAzureSEVSNP() *AzureSEVSNP {
|
||||
return &AzureSEVSNP{
|
||||
Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureSEVSNP{}),
|
||||
BootloaderVersion: configapi.NewLatestPlaceholderVersion(),
|
||||
TEEVersion: configapi.NewLatestPlaceholderVersion(),
|
||||
SNPVersion: configapi.NewLatestPlaceholderVersion(),
|
||||
MicrocodeVersion: configapi.NewLatestPlaceholderVersion(),
|
||||
BootloaderVersion: NewLatestPlaceholderVersion(),
|
||||
TEEVersion: NewLatestPlaceholderVersion(),
|
||||
SNPVersion: NewLatestPlaceholderVersion(),
|
||||
MicrocodeVersion: NewLatestPlaceholderVersion(),
|
||||
FirmwareSignerConfig: SNPFirmwareSignerConfig{
|
||||
AcceptedKeyDigests: idkeydigest.DefaultList(),
|
||||
EnforcementPolicy: idkeydigest.MAAFallback,
|
||||
@ -97,13 +98,13 @@ func (c AzureSEVSNP) EqualTo(old AttestationCfg) (bool, error) {
|
||||
}
|
||||
|
||||
// FetchAndSetLatestVersionNumbers fetches the latest version numbers from the configapi and sets them.
|
||||
func (c *AzureSEVSNP) FetchAndSetLatestVersionNumbers(fetcher fetcher.ConfigAPIFetcher, version versionsapi.Version) error {
|
||||
versions, err := fetcher.FetchLatestAzureSEVSNPVersion(context.Background(), version)
|
||||
func (c *AzureSEVSNP) FetchAndSetLatestVersionNumbers(fetcher attestationconfigfetcher.AttestationConfigAPIFetcher, version versionsapi.Version) error {
|
||||
versions, err := fetcher.FetchAzureSEVSNPVersionLatest(context.Background(), version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// set number and keep isLatest flag
|
||||
c.mergeVersionNumbers(versions)
|
||||
c.mergeVersionNumbers(versions.AzureSEVSNPVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,8 @@ import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
en_translations "github.com/go-playground/validator/v10/translations/en"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
@ -385,7 +385,7 @@ func fromFile(fileHandler file.Handler, name string) (*Config, error) {
|
||||
// 2. For "latest" version values of the attestation variants fetch the version numbers.
|
||||
// 3. Read secrets from environment variables.
|
||||
// 4. Validate config. If `--force` is set the version validation will be disabled and any version combination is allowed.
|
||||
func New(fileHandler file.Handler, name string, fetcher fetcher.ConfigAPIFetcher, force bool) (*Config, error) {
|
||||
func New(fileHandler file.Handler, name string, fetcher attestationconfigfetcher.AttestationConfigAPIFetcher, force bool) (*Config, error) {
|
||||
// Read config file
|
||||
c, err := fromFile(fileHandler, name)
|
||||
if err != nil {
|
||||
|
@ -21,8 +21,8 @@ import (
|
||||
"go.uber.org/goleak"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
||||
@ -75,11 +75,11 @@ func TestReadConfigFile(t *testing.T) {
|
||||
configName: constants.ConfigFilename,
|
||||
wantResult: func() *Config {
|
||||
conf := Default()
|
||||
conf.Attestation.AzureSEVSNP.BootloaderVersion = configapi.AttestationVersion{
|
||||
conf.Attestation.AzureSEVSNP.BootloaderVersion = AttestationVersion{
|
||||
Value: 1,
|
||||
IsLatest: false,
|
||||
}
|
||||
conf.Attestation.AzureSEVSNP.TEEVersion = configapi.AttestationVersion{
|
||||
conf.Attestation.AzureSEVSNP.TEEVersion = AttestationVersion{
|
||||
Value: 2,
|
||||
IsLatest: false,
|
||||
}
|
||||
@ -892,8 +892,10 @@ func (f fakeConfigFetcher) FetchAzureSEVSNPVersion(_ context.Context, _ configap
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f fakeConfigFetcher) FetchLatestAzureSEVSNPVersion(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersion, error) {
|
||||
return testCfg, nil
|
||||
func (f fakeConfigFetcher) FetchAzureSEVSNPVersionLatest(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersionGet, error) {
|
||||
return configapi.AzureSEVSNPVersionGet{
|
||||
AzureSEVSNPVersion: testCfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var testCfg = configapi.AzureSEVSNPVersion{
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
"golang.org/x/mod/semver"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
|
@ -193,6 +193,8 @@ const (
|
||||
CDNAPIPrefix = CDNAPIBase + "/v1"
|
||||
// CDNAPIPrefixV2 is the prefix of the Constellation API (v2).
|
||||
CDNAPIPrefixV2 = CDNAPIBase + "/v2"
|
||||
// CDNAttestationConfigPrefixV1 is the prefix of the Constellation AttestationConfig API (v1).
|
||||
CDNAttestationConfigPrefixV1 = CDNAPIPrefix + "/attestation"
|
||||
// CDNMeasurementsFile is name of file containing image measurements.
|
||||
CDNMeasurementsFile = "measurements.json"
|
||||
// CDNMeasurementsSignature is name of file containing signature for CDNMeasurementsFile.
|
||||
|
@ -11,7 +11,8 @@ go_library(
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/fetcher",
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/api/versions/fetcher",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/variant",
|
||||
"@com_github_schollz_progressbar_v3//:progressbar",
|
||||
@ -27,7 +28,7 @@ go_test(
|
||||
],
|
||||
embed = [":imagefetcher"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/file",
|
||||
"//internal/variant",
|
||||
|
@ -20,7 +20,8 @@ import (
|
||||
"regexp"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
versionsfetcher "github.com/edgelesssys/constellation/v2/internal/api/versions/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/spf13/afero"
|
||||
@ -35,7 +36,7 @@ type Fetcher struct {
|
||||
// New returns a new image fetcher.
|
||||
func New() *Fetcher {
|
||||
return &Fetcher{
|
||||
fetcher: fetcher.NewVersionAPIFetcher(),
|
||||
fetcher: versionsfetcher.New(),
|
||||
fs: &afero.Afero{Fs: afero.NewOsFs()},
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/osimage/secureboot",
|
||||
],
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/archive",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/constants",
|
||||
"//internal/logger",
|
||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/aws",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/logger",
|
||||
"//internal/osimage",
|
||||
"//internal/osimage/secureboot",
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/aws/smithy-go"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage/secureboot"
|
||||
|
@ -9,7 +9,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/azure",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/logger",
|
||||
"//internal/osimage",
|
||||
"@com_github_azure_azure_sdk_for_go_sdk_azcore//runtime",
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
armcomputev4 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/pageblob"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/gcp",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/logger",
|
||||
"//internal/osimage",
|
||||
"//internal/osimage/secureboot",
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
compute "cloud.google.com/go/compute/apiv1"
|
||||
"cloud.google.com/go/compute/apiv1/computepb"
|
||||
"cloud.google.com/go/storage"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||
"github.com/edgelesssys/constellation/v2/internal/osimage/secureboot"
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/constants",
|
||||
"//internal/logger",
|
||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/measurementsuploader",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/constants",
|
||||
"//internal/logger",
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
|
@ -6,7 +6,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/nop",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/api/versions",
|
||||
"//internal/logger",
|
||||
"//internal/osimage",
|
||||
],
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user