mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-06-24 14:10:49 -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
105 changed files with 1042 additions and 916 deletions
|
@ -48,8 +48,10 @@ go_library(
|
||||||
"//cli/internal/terraform",
|
"//cli/internal/terraform",
|
||||||
"//cli/internal/upgrade",
|
"//cli/internal/upgrade",
|
||||||
"//disk-mapper/recoverproto",
|
"//disk-mapper/recoverproto",
|
||||||
|
"//internal/api/attestationconfig/fetcher",
|
||||||
"//internal/api/fetcher",
|
"//internal/api/fetcher",
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
|
"//internal/api/versions/fetcher",
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/azureshared",
|
"//internal/cloud/azureshared",
|
||||||
|
@ -135,8 +137,8 @@ go_test(
|
||||||
"//cli/internal/terraform",
|
"//cli/internal/terraform",
|
||||||
"//cli/internal/upgrade",
|
"//cli/internal/upgrade",
|
||||||
"//disk-mapper/recoverproto",
|
"//disk-mapper/recoverproto",
|
||||||
"//internal/api/configapi",
|
"//internal/api/attestationconfig",
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
|
|
|
@ -15,8 +15,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||||
"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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"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}
|
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)
|
return cfm.configFetchMeasurements(cmd, sigstore.CosignVerifier{}, rekor, fileHandler, fetcher, http.DefaultClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfm *configFetchMeasurementsCmd) configFetchMeasurements(
|
func (cfm *configFetchMeasurementsCmd) configFetchMeasurements(
|
||||||
cmd *cobra.Command, cosign cosignVerifier, rekor rekorVerifier,
|
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 {
|
) error {
|
||||||
flags, err := cfm.parseFetchMeasurementsFlags(cmd)
|
flags, err := cfm.parseFetchMeasurementsFlags(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -16,8 +16,8 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||||
"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/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
|
@ -305,8 +305,10 @@ func (f fakeConfigFetcher) FetchAzureSEVSNPVersion(_ context.Context, _ configap
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fakeConfigFetcher) FetchLatestAzureSEVSNPVersion(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersion, error) {
|
func (f fakeConfigFetcher) FetchAzureSEVSNPVersionLatest(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersionGet, error) {
|
||||||
return testCfg, nil
|
return configapi.AzureSEVSNPVersionGet{
|
||||||
|
AzureSEVSNPVersion: testCfg,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var testCfg = configapi.AzureSEVSNPVersion{
|
var testCfg = configapi.AzureSEVSNPVersion{
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
"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/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
|
@ -59,11 +59,11 @@ func runCreate(cmd *cobra.Command, _ []string) error {
|
||||||
fileHandler := file.NewHandler(afero.NewOsFs())
|
fileHandler := file.NewHandler(afero.NewOsFs())
|
||||||
creator := cloudcmd.NewCreator(spinner)
|
creator := cloudcmd.NewCreator(spinner)
|
||||||
c := &createCmd{log: log}
|
c := &createCmd{log: log}
|
||||||
fetcher := fetcher.NewConfigAPIFetcher()
|
fetcher := attestationconfigfetcher.New()
|
||||||
return c.create(cmd, creator, fileHandler, spinner, fetcher)
|
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)
|
flags, err := c.parseCreateFlags(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"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/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
|
|
||||||
|
@ -98,13 +98,13 @@ func runInitialize(cmd *cobra.Command, _ []string) error {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
cmd.SetContext(ctx)
|
cmd.SetContext(ctx)
|
||||||
i := &initCmd{log: log, spinner: spinner, merger: &kubeconfigMerger{log: log}, fh: &fileHandler}
|
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)
|
return i.initialize(cmd, newDialer, fileHandler, license.NewClient(), fetcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize initializes a Constellation.
|
// initialize initializes a Constellation.
|
||||||
func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.Validator) *dialer.Dialer,
|
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 {
|
) error {
|
||||||
flags, err := i.evalFlagArgs(cmd)
|
flags, err := i.evalFlagArgs(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
|
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
"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/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -46,7 +46,7 @@ func newMiniUpCmd() *cobra.Command {
|
||||||
|
|
||||||
type miniUpCmd struct {
|
type miniUpCmd struct {
|
||||||
log debugLog
|
log debugLog
|
||||||
configFetcher fetcher.ConfigAPIFetcher
|
configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUp(cmd *cobra.Command, _ []string) error {
|
func runUp(cmd *cobra.Command, _ []string) error {
|
||||||
|
@ -62,7 +62,7 @@ func runUp(cmd *cobra.Command, _ []string) error {
|
||||||
defer spinner.Stop()
|
defer spinner.Stop()
|
||||||
creator := cloudcmd.NewCreator(spinner)
|
creator := cloudcmd.NewCreator(spinner)
|
||||||
|
|
||||||
m := &miniUpCmd{log: log, configFetcher: fetcher.NewConfigAPIFetcher()}
|
m := &miniUpCmd{log: log, configFetcher: attestationconfigfetcher.New()}
|
||||||
return m.up(cmd, creator, spinner)
|
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/cloudcmd"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
||||||
"github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto"
|
"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/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -50,7 +50,7 @@ func NewRecoverCmd() *cobra.Command {
|
||||||
|
|
||||||
type recoverCmd struct {
|
type recoverCmd struct {
|
||||||
log debugLog
|
log debugLog
|
||||||
configFetcher fetcher.ConfigAPIFetcher
|
configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRecover(cmd *cobra.Command, _ []string) error {
|
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 {
|
newDialer := func(validator atls.Validator) *dialer.Dialer {
|
||||||
return dialer.New(nil, validator, &net.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)
|
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/kubernetes"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
"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/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -67,7 +67,7 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
imagefetcher := imagefetcher.New()
|
imagefetcher := imagefetcher.New()
|
||||||
configFetcher := fetcher.NewConfigAPIFetcher()
|
configFetcher := attestationconfigfetcher.New()
|
||||||
|
|
||||||
applyCmd := upgradeApplyCmd{upgrader: upgrader, log: log, imageFetcher: imagefetcher, configFetcher: configFetcher}
|
applyCmd := upgradeApplyCmd{upgrader: upgrader, log: log, imageFetcher: imagefetcher, configFetcher: configFetcher}
|
||||||
return applyCmd.upgradeApply(cmd, fileHandler)
|
return applyCmd.upgradeApply(cmd, fileHandler)
|
||||||
|
@ -76,7 +76,7 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
||||||
type upgradeApplyCmd struct {
|
type upgradeApplyCmd struct {
|
||||||
upgrader cloudUpgrader
|
upgrader cloudUpgrader
|
||||||
imageFetcher imageFetcher
|
imageFetcher imageFetcher
|
||||||
configFetcher fetcher.ConfigAPIFetcher
|
configFetcher attestationconfigfetcher.AttestationConfigAPIFetcher
|
||||||
log debugLog
|
log debugLog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,10 @@ import (
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
"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/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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
|
@ -68,7 +70,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
versionListFetcher := fetcher.NewVersionAPIFetcher()
|
versionListFetcher := versionfetcher.New()
|
||||||
rekor, err := sigstore.NewRekor()
|
rekor, err := sigstore.NewRekor()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("constructing Rekor client: %w", err)
|
return fmt.Errorf("constructing Rekor client: %w", err)
|
||||||
|
@ -86,12 +88,12 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
||||||
flags: flags,
|
flags: flags,
|
||||||
cliVersion: compatibility.EnsurePrefixV(constants.VersionInfo()),
|
cliVersion: compatibility.EnsurePrefixV(constants.VersionInfo()),
|
||||||
log: log,
|
log: log,
|
||||||
versionsapi: fetcher.NewVersionAPIFetcher(),
|
versionsapi: versionfetcher.New(),
|
||||||
},
|
},
|
||||||
log: log,
|
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) {
|
func parseUpgradeCheckFlags(cmd *cobra.Command) (upgradeCheckFlags, error) {
|
||||||
|
@ -131,7 +133,7 @@ type upgradeCheckCmd struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// upgradePlan plans an upgrade of a Constellation cluster.
|
// 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)
|
conf, err := config.New(fileHandler, flags.configPath, fetcher, flags.force)
|
||||||
var configValidationErr *config.ValidationError
|
var configValidationErr *config.ValidationError
|
||||||
if errors.As(err, &configValidationErr) {
|
if errors.As(err, &configValidationErr) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"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/cloudcmd"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
"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/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -72,11 +72,11 @@ func runVerify(cmd *cobra.Command, _ []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &verifyCmd{log: log}
|
v := &verifyCmd{log: log}
|
||||||
fetcher := fetcher.NewConfigAPIFetcher()
|
fetcher := attestationconfigfetcher.New()
|
||||||
return v.verify(cmd, fileHandler, verifyClient, formatter, fetcher)
|
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)
|
flags, err := c.parseVerifyFlags(cmd, fileHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
|
|
|
@ -14,7 +14,7 @@ go_library(
|
||||||
"//cli/internal/helm",
|
"//cli/internal/helm",
|
||||||
"//cli/internal/terraform",
|
"//cli/internal/terraform",
|
||||||
"//cli/internal/upgrade",
|
"//cli/internal/upgrade",
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/compatibility",
|
"//internal/compatibility",
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
"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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
|
|
|
@ -14,7 +14,7 @@ go_library(
|
||||||
"//debugd/internal/filetransfer",
|
"//debugd/internal/filetransfer",
|
||||||
"//debugd/internal/filetransfer/streamer",
|
"//debugd/internal/filetransfer/streamer",
|
||||||
"//debugd/service",
|
"//debugd/service",
|
||||||
"//internal/api/fetcher",
|
"//internal/api/attestationconfig/fetcher",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"github.com/edgelesssys/constellation/v2/debugd/internal/filetransfer"
|
"github.com/edgelesssys/constellation/v2/debugd/internal/filetransfer"
|
||||||
"github.com/edgelesssys/constellation/v2/debugd/internal/filetransfer/streamer"
|
"github.com/edgelesssys/constellation/v2/debugd/internal/filetransfer/streamer"
|
||||||
pb "github.com/edgelesssys/constellation/v2/debugd/service"
|
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/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
|
@ -69,7 +69,7 @@ func runDeploy(cmd *cobra.Command, _ []string) error {
|
||||||
fileHandler := file.NewHandler(fs)
|
fileHandler := file.NewHandler(fs)
|
||||||
streamer := streamer.New(fs)
|
streamer := streamer.New(fs)
|
||||||
transfer := filetransfer.New(log, streamer, filetransfer.ShowProgress)
|
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
|
var configValidationErr *config.ValidationError
|
||||||
if errors.As(err, &configValidationErr) {
|
if errors.As(err, &configValidationErr) {
|
||||||
cmd.PrintErrln(configValidationErr.LongMessage())
|
cmd.PrintErrln(configValidationErr.LongMessage())
|
||||||
|
|
|
@ -11,7 +11,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/e2e/internal/upgrade",
|
importpath = "github.com/edgelesssys/constellation/v2/e2e/internal/upgrade",
|
||||||
visibility = ["//e2e:__subpackages__"],
|
visibility = ["//e2e:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
|
@ -26,6 +26,7 @@ go_library(
|
||||||
go_test(
|
go_test(
|
||||||
name = "upgrade_test",
|
name = "upgrade_test",
|
||||||
srcs = ["upgrade_test.go"],
|
srcs = ["upgrade_test.go"],
|
||||||
|
# keep
|
||||||
count = 1,
|
count = 1,
|
||||||
data = [
|
data = [
|
||||||
"//cli:cli_oss_linux_amd64",
|
"//cli:cli_oss_linux_amd64",
|
||||||
|
@ -34,11 +35,12 @@ go_test(
|
||||||
env = {
|
env = {
|
||||||
"PATH_CLI": "$(location //cli:cli_oss_linux_amd64)",
|
"PATH_CLI": "$(location //cli:cli_oss_linux_amd64)",
|
||||||
},
|
},
|
||||||
|
# keep
|
||||||
gotags = ["e2e"],
|
gotags = ["e2e"],
|
||||||
tags = ["manual"],
|
tags = ["manual"],
|
||||||
deps = [
|
deps = [
|
||||||
"//e2e/internal/kubectl",
|
"//e2e/internal/kubectl",
|
||||||
"//internal/api/fetcher",
|
"//internal/api/attestationconfig/fetcher",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/e2e/internal/kubectl"
|
"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/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"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 {
|
func writeUpgradeConfig(require *require.Assertions, image string, kubernetes string, microservices string) versionContainer {
|
||||||
fileHandler := file.NewHandler(afero.NewOsFs())
|
fileHandler := file.NewHandler(afero.NewOsFs())
|
||||||
fetcher := fetcher.NewConfigAPIFetcher()
|
fetcher := attestationconfigfetcher.New()
|
||||||
cfg, err := config.New(fileHandler, constants.ConfigFilename, fetcher, true)
|
cfg, err := config.New(fileHandler, constants.ConfigFilename, fetcher, true)
|
||||||
var cfgErr *config.ValidationError
|
var cfgErr *config.ValidationError
|
||||||
var longMsg string
|
var longMsg string
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/hack/azure-snp-report-verify",
|
importpath = "github.com/edgelesssys/constellation/v2/hack/azure-snp-report-verify",
|
||||||
visibility = ["//visibility:private"],
|
visibility = ["//visibility:private"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/configapi",
|
"//internal/api/attestationconfig",
|
||||||
"@in_gopkg_square_go_jose_v2//:go-jose_v2",
|
"@in_gopkg_square_go_jose_v2//:go-jose_v2",
|
||||||
"@in_gopkg_square_go_jose_v2//jwt",
|
"@in_gopkg_square_go_jose_v2//jwt",
|
||||||
],
|
],
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"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"
|
||||||
"gopkg.in/square/go-jose.v2/jwt"
|
"gopkg.in/square/go-jose.v2/jwt"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,8 +6,8 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/hack/cli-k8s-compatibility",
|
importpath = "github.com/edgelesssys/constellation/v2/hack/cli-k8s-compatibility",
|
||||||
visibility = ["//visibility:private"],
|
visibility = ["//visibility:private"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/api/versionsapi/client",
|
"//internal/api/versions/client",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
"@org_uber_go_zap//zapcore",
|
"@org_uber_go_zap//zapcore",
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client"
|
"github.com/edgelesssys/constellation/v2/internal/api/versions/client"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
|
|
@ -6,7 +6,8 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/hack/configapi/cmd",
|
importpath = "github.com/edgelesssys/constellation/v2/hack/configapi/cmd",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/configapi",
|
"//internal/api/attestationconfig",
|
||||||
|
"//internal/api/attestationconfig/client",
|
||||||
"//internal/staticupload",
|
"//internal/staticupload",
|
||||||
"@com_github_spf13_cobra//:cobra",
|
"@com_github_spf13_cobra//:cobra",
|
||||||
],
|
],
|
||||||
|
|
|
@ -12,7 +12,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"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/edgelesssys/constellation/v2/internal/staticupload"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -75,7 +76,7 @@ func runCmd(cmd *cobra.Command, _ []string) error {
|
||||||
return fmt.Errorf("unmarshalling version file: %w", err)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("creating repo: %w", err)
|
return fmt.Errorf("creating repo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/image/upload/internal/cmd",
|
importpath = "github.com/edgelesssys/constellation/v2/image/upload/internal/cmd",
|
||||||
visibility = ["//image/upload:__subpackages__"],
|
visibility = ["//image/upload:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"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"
|
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"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/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"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"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
infoupload "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo"
|
infoupload "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"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"
|
"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
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
package configapi
|
|
||||||
|
package attestationconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -2,16 +2,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
load("//bazel/go:go_test.bzl", "go_test")
|
load("//bazel/go:go_test.bzl", "go_test")
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "configapi",
|
name = "client",
|
||||||
srcs = [
|
srcs = ["client.go"],
|
||||||
"attestation.go",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/client",
|
||||||
"attestationversion.go",
|
|
||||||
"configapi.go",
|
|
||||||
"repo.go",
|
|
||||||
],
|
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/configapi",
|
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/api/attestationconfig",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/kms/storage",
|
"//internal/kms/storage",
|
||||||
"//internal/sigstore",
|
"//internal/sigstore",
|
||||||
|
@ -22,15 +18,18 @@ go_library(
|
||||||
)
|
)
|
||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "configapi_test",
|
name = "client_test",
|
||||||
srcs = [
|
srcs = ["client_test.go"],
|
||||||
"attestationversion_test.go",
|
# keep
|
||||||
"repo_test.go",
|
count = 1,
|
||||||
],
|
# keep
|
||||||
embed = [":configapi"],
|
gotags = ["e2e"],
|
||||||
|
# keep
|
||||||
|
tags = ["manual"],
|
||||||
deps = [
|
deps = [
|
||||||
|
":client",
|
||||||
|
"//internal/api/attestationconfig",
|
||||||
"//internal/staticupload",
|
"//internal/staticupload",
|
||||||
"@com_github_stretchr_testify//require",
|
"@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
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
package configapi
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -17,30 +17,32 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"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/kms/storage"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/staticupload"
|
"github.com/edgelesssys/constellation/v2/internal/staticupload"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AttestationVersionRepo manages (modifies) the version information for the attestation variants.
|
// Client manages (modifies) the version information for the attestation variants.
|
||||||
type AttestationVersionRepo struct {
|
type Client struct {
|
||||||
*staticupload.Client
|
*staticupload.Client
|
||||||
cosignPwd []byte // used to decrypt the cosign private key
|
cosignPwd []byte // used to decrypt the cosign private key
|
||||||
privKey []byte // used to sign
|
privKey []byte // used to sign
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAttestationVersionRepo returns a new AttestationVersionRepo.
|
// New returns a new Client.
|
||||||
func NewAttestationVersionRepo(ctx context.Context, cfg staticupload.Config, cosignPwd, privateKey []byte) (*AttestationVersionRepo, error) {
|
func New(ctx context.Context, cfg staticupload.Config, cosignPwd, privateKey []byte) (*Client, error) {
|
||||||
client, err := staticupload.New(ctx, cfg)
|
client, err := staticupload.New(ctx, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create s3 storage: %w", err)
|
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.
|
// 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)
|
versionBytes, err := json.Marshal(versions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -48,7 +50,7 @@ func (a AttestationVersionRepo) UploadAzureSEVSNP(ctx context.Context, versions
|
||||||
variant := variant.AzureSEVSNP{}
|
variant := variant.AzureSEVSNP{}
|
||||||
fname := date.Format("2006-01-02-15-04") + ".json"
|
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)
|
err = put(ctx, a.Client, filePath, versionBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// 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)
|
signature, err := sigstore.SignContent(a.cosignPwd, a.privKey, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sign version file: %w", err)
|
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.
|
// List returns the list of versions for the given attestation type.
|
||||||
func (a AttestationVersionRepo) List(ctx context.Context, attestation variant.Variant) ([]string, error) {
|
func (a Client) List(ctx context.Context, attestation variant.Variant) ([]string, error) {
|
||||||
key := path.Join(attestationURLPath, attestation.String(), "list")
|
key := path.Join(constants.CDNAttestationConfigPrefixV1, attestation.String(), "list")
|
||||||
bt, err := get(ctx, a.Client, key)
|
bt, err := get(ctx, a.Client, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// 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{}
|
versions := []string{}
|
||||||
bt, err := json.Marshal(&versions)
|
bt, err := json.Marshal(&versions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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{}
|
versions := []string{}
|
||||||
key := path.Join(attestationURLPath, attestation.String(), "list")
|
key := path.Join(constants.CDNAttestationConfigPrefixV1, attestation.String(), "list")
|
||||||
bt, err := get(ctx, a.Client, key)
|
bt, err := get(ctx, a.Client, key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := json.Unmarshal(bt, &versions); 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
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
package configapi_test
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -16,7 +16,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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/edgelesssys/constellation/v2/internal/staticupload"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -64,7 +65,7 @@ func TestMain(m *testing.M) {
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
var versionValues = configapi.AzureSEVSNPVersion{
|
var versionValues = attestationconfig.AzureSEVSNPVersion{
|
||||||
Bootloader: 2,
|
Bootloader: 2,
|
||||||
TEE: 0,
|
TEE: 0,
|
||||||
SNP: 6,
|
SNP: 6,
|
||||||
|
@ -73,8 +74,8 @@ var versionValues = configapi.AzureSEVSNPVersion{
|
||||||
|
|
||||||
func TestUploadAzureSEVSNPVersions(t *testing.T) {
|
func TestUploadAzureSEVSNPVersions(t *testing.T) {
|
||||||
ctx := context.Background()
|
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)
|
require.NoError(t, err)
|
||||||
d := time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC)
|
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"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||||
"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/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testCfg = configapi.AzureSEVSNPVersion{
|
var testCfg = configapi.AzureSEVSNPVersionGet{
|
||||||
Microcode: 93,
|
AzureSEVSNPVersion: configapi.AzureSEVSNPVersion{
|
||||||
TEE: 0,
|
Microcode: 93,
|
||||||
SNP: 6,
|
TEE: 0,
|
||||||
Bootloader: 2,
|
SNP: 6,
|
||||||
|
Bootloader: 2,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchLatestAzureSEVSNPVersion(t *testing.T) {
|
func TestFetchLatestAzureSEVSNPVersion(t *testing.T) {
|
||||||
testcases := map[string]struct {
|
testcases := map[string]struct {
|
||||||
signature []byte
|
signature []byte
|
||||||
wantErr bool
|
wantErr bool
|
||||||
want configapi.AzureSEVSNPVersion
|
want configapi.AzureSEVSNPVersionGet
|
||||||
}{
|
}{
|
||||||
"get version with valid signature": {
|
"get version with valid signature": {
|
||||||
signature: []byte("MEUCIQDNn6wiSh9Nz9mtU9RvxvfkH3fNDFGeqopjTIRoBNkyrAIgSsKgdYNQXvPevaLWmmpnj/9WcgrltAQ+KfI+bQfklAo="),
|
signature: []byte("MEUCIQDNn6wiSh9Nz9mtU9RvxvfkH3fNDFGeqopjTIRoBNkyrAIgSsKgdYNQXvPevaLWmmpnj/9WcgrltAQ+KfI+bQfklAo="),
|
||||||
|
@ -52,10 +54,10 @@ func TestFetchLatestAzureSEVSNPVersion(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
version, err := versionsapi.NewVersionFromShortPath("stream/debug/v9.9.9", versionsapi.VersionKindImage)
|
version, err := versionsapi.NewVersionFromShortPath("stream/debug/v9.9.9", versionsapi.VersionKindImage)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
fetcher := NewConfigAPIFetcherWithClient(client)
|
fetcher := NewWithClient(client)
|
||||||
|
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
res, err := fetcher.FetchLatestAzureSEVSNPVersion(context.Background(), version)
|
res, err := fetcher.FetchAzureSEVSNPVersionLatest(context.Background(), version)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
} else {
|
} else {
|
|
@ -3,11 +3,9 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
go_library(
|
go_library(
|
||||||
name = "client",
|
name = "client",
|
||||||
srcs = ["client.go"],
|
srcs = ["client.go"],
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/api/client",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
|
||||||
"//internal/constants",
|
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"@com_github_aws_aws_sdk_go_v2//aws",
|
"@com_github_aws_aws_sdk_go_v2//aws",
|
||||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
"@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_cloudfront//types",
|
||||||
"@com_github_aws_aws_sdk_go_v2_service_s3//:s3",
|
"@com_github_aws_aws_sdk_go_v2_service_s3//:s3",
|
||||||
"@com_github_aws_aws_sdk_go_v2_service_s3//types",
|
"@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("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
load("//bazel/go:go_test.bzl", "go_test")
|
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "fetcher",
|
name = "fetcher",
|
||||||
srcs = [
|
srcs = ["fetcher.go"],
|
||||||
"configapi.go",
|
|
||||||
"fetcher.go",
|
|
||||||
"versionapi.go",
|
|
||||||
],
|
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/fetcher",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/api/fetcher",
|
||||||
visibility = ["//:__subpackages__"],
|
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
|
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
|
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.
|
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
|
package fetcher
|
||||||
|
|
||||||
|
@ -17,56 +21,17 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// fetcher fetches versions API resources without authentication.
|
|
||||||
type fetcher struct {
|
|
||||||
httpc HTTPClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHTTPClient returns a new http client.
|
// NewHTTPClient returns a new http client.
|
||||||
func NewHTTPClient() HTTPClient {
|
func NewHTTPClient() HTTPClient {
|
||||||
return &http.Client{Transport: &http.Transport{DisableKeepAlives: true}} // DisableKeepAlives fixes concurrency issue see https://stackoverflow.com/a/75816347
|
return &http.Client{Transport: &http.Transport{DisableKeepAlives: true}} // DisableKeepAlives fixes concurrency issue see https://stackoverflow.com/a/75816347
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFetcherWith(client HTTPClient) *fetcher {
|
// Fetch fetches the given apiObject from the public Constellation CDN.
|
||||||
return &fetcher{
|
// Fetch does not require authentication.
|
||||||
httpc: client,
|
func Fetch[T apiObject](ctx context.Context, c HTTPClient, obj T) (T, error) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if err := obj.ValidateRequest(); err != nil {
|
if err := obj.ValidateRequest(); err != nil {
|
||||||
return *new(T), fmt.Errorf("validating request for %T: %w", obj, err)
|
return *new(T), fmt.Errorf("validating request for %T: %w", obj, err)
|
||||||
}
|
}
|
||||||
|
@ -123,3 +88,9 @@ func (e *NotFoundError) Unwrap() error {
|
||||||
type HTTPClient interface {
|
type HTTPClient interface {
|
||||||
Do(req *http.Request) (*http.Response, error)
|
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")
|
load("//bazel/go:go_test.bzl", "go_test")
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "versionsapi",
|
name = "versions",
|
||||||
srcs = [
|
srcs = [
|
||||||
"apiconstants.go",
|
"apiconstants.go",
|
||||||
"cliinfo.go",
|
"cliinfo.go",
|
||||||
|
@ -12,7 +12,7 @@ go_library(
|
||||||
"version.go",
|
"version.go",
|
||||||
"versionsapi.go",
|
"versionsapi.go",
|
||||||
],
|
],
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/api/versions",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
|
@ -21,7 +21,7 @@ go_library(
|
||||||
)
|
)
|
||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "versionsapi_test",
|
name = "versions_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"cliinfo_test.go",
|
"cliinfo_test.go",
|
||||||
"imageinfo_test.go",
|
"imageinfo_test.go",
|
||||||
|
@ -29,7 +29,7 @@ go_test(
|
||||||
"list_test.go",
|
"list_test.go",
|
||||||
"version_test.go",
|
"version_test.go",
|
||||||
],
|
],
|
||||||
embed = [":versionsapi"],
|
embed = [":versions"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// APIV1 is the v1 API version.
|
// APIV1 is the v1 API version.
|
|
@ -9,11 +9,12 @@ go_library(
|
||||||
"main.go",
|
"main.go",
|
||||||
"rm.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"],
|
visibility = ["//visibility:private"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/fetcher",
|
||||||
"//internal/api/versionsapi/client",
|
"//internal/api/versions",
|
||||||
|
"//internal/api/versions/client",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
|
@ -11,8 +11,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||||
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/edgelesssys/constellation/v2/internal/logger"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
@ -104,7 +105,7 @@ func runAdd(cmd *cobra.Command, _ []string) (retErr error) {
|
||||||
return nil
|
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,
|
log *logger.Logger,
|
||||||
) error {
|
) error {
|
||||||
verListReq := versionsapi.List{
|
verListReq := versionsapi.List{
|
||||||
|
@ -115,7 +116,7 @@ func ensureVersion(ctx context.Context, client *verclient.Client, kind versionsa
|
||||||
Kind: kind,
|
Kind: kind,
|
||||||
}
|
}
|
||||||
verList, err := client.FetchVersionList(ctx, verListReq)
|
verList, err := client.FetchVersionList(ctx, verListReq)
|
||||||
var notFoundErr *verclient.NotFoundError
|
var notFoundErr *apifetcher.NotFoundError
|
||||||
if errors.As(err, ¬FoundErr) {
|
if errors.As(err, ¬FoundErr) {
|
||||||
log.Infof("Version list for %s versions under %q does not exist. Creating new list", gran.String(), ver.Major())
|
log.Infof("Version list for %s versions under %q does not exist. Creating new list", gran.String(), ver.Major())
|
||||||
verList = verListReq
|
verList = verListReq
|
||||||
|
@ -144,14 +145,14 @@ func ensureVersion(ctx context.Context, client *verclient.Client, kind versionsa
|
||||||
return nil
|
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{
|
latest := versionsapi.Latest{
|
||||||
Ref: ver.Ref,
|
Ref: ver.Ref,
|
||||||
Stream: ver.Stream,
|
Stream: ver.Stream,
|
||||||
Kind: kind,
|
Kind: kind,
|
||||||
}
|
}
|
||||||
latest, err := client.FetchVersionLatest(ctx, latest)
|
latest, err := client.FetchVersionLatest(ctx, latest)
|
||||||
var notFoundErr *verclient.NotFoundError
|
var notFoundErr *apifetcher.NotFoundError
|
||||||
if errors.As(err, ¬FoundErr) {
|
if errors.As(err, ¬FoundErr) {
|
||||||
log.Debugf("Latest version for ref %q and stream %q not found", ver.Ref, ver.Stream)
|
log.Debugf("Latest version for ref %q and stream %q not found", ver.Ref, ver.Stream)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||||
verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client"
|
verclient "github.com/edgelesssys/constellation/v2/internal/api/versions/client"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
|
@ -16,8 +16,9 @@ import (
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||||
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/edgelesssys/constellation/v2/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ func runList(cmd *cobra.Command, _ []string) error {
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Getting minor versions")
|
log.Debugf("Getting minor versions")
|
||||||
minorVersions, err = listMinorVersions(cmd.Context(), client, flags.ref, flags.stream)
|
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) {
|
if err != nil && errors.As(err, &errNotFound) {
|
||||||
log.Infof("No minor versions found for ref %q and stream %q.", flags.ref, flags.stream)
|
log.Infof("No minor versions found for ref %q and stream %q.", flags.ref, flags.stream)
|
||||||
return nil
|
return nil
|
||||||
|
@ -74,7 +75,7 @@ func runList(cmd *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
log.Debugf("Getting patch versions")
|
log.Debugf("Getting patch versions")
|
||||||
patchVersions, err := listPatchVersions(cmd.Context(), client, flags.ref, flags.stream, minorVersions)
|
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) {
|
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)
|
log.Infof("No patch versions found for ref %q, stream %q and minor versions %v.", flags.ref, flags.stream, minorVersions)
|
||||||
return nil
|
return nil
|
||||||
|
@ -104,7 +105,7 @@ func runList(cmd *cobra.Command, _ []string) error {
|
||||||
return nil
|
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{
|
list := versionsapi.List{
|
||||||
Ref: ref,
|
Ref: ref,
|
||||||
Stream: stream,
|
Stream: stream,
|
||||||
|
@ -120,7 +121,7 @@ func listMinorVersions(ctx context.Context, client *verclient.Client, ref string
|
||||||
return list.Versions, nil
|
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) {
|
) ([]versionsapi.Version, error) {
|
||||||
var patchVers []versionsapi.Version
|
var patchVers []versionsapi.Version
|
||||||
|
|
|
@ -24,8 +24,9 @@ import (
|
||||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||||
"github.com/aws/smithy-go"
|
"github.com/aws/smithy-go"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||||
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/edgelesssys/constellation/v2/internal/logger"
|
||||||
gaxv2 "github.com/googleapis/gax-go/v2"
|
gaxv2 "github.com/googleapis/gax-go/v2"
|
||||||
"github.com/spf13/cobra"
|
"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)
|
log.Infof("Listing versions of stream %s", stream)
|
||||||
|
|
||||||
minorVersions, err := listMinorVersions(ctx, clients.version, ref, stream)
|
minorVersions, err := listMinorVersions(ctx, clients.version, ref, stream)
|
||||||
var notFoundErr *verclient.NotFoundError
|
var notFoundErr *apifetcher.NotFoundError
|
||||||
if errors.As(err, ¬FoundErr) {
|
if errors.As(err, ¬FoundErr) {
|
||||||
log.Debugf("No minor versions found for stream %s", stream)
|
log.Debugf("No minor versions found for stream %s", stream)
|
||||||
continue
|
continue
|
||||||
|
@ -202,7 +203,7 @@ func deleteImage(ctx context.Context, clients rmImageClients, ver versionsapi.Ve
|
||||||
Version: ver.Version,
|
Version: ver.Version,
|
||||||
}
|
}
|
||||||
imageInfo, err := clients.version.FetchImageInfo(ctx, imageInfo)
|
imageInfo, err := clients.version.FetchImageInfo(ctx, imageInfo)
|
||||||
var notFound *verclient.NotFoundError
|
var notFound *apifetcher.NotFoundError
|
||||||
if errors.As(err, ¬Found) {
|
if errors.As(err, ¬Found) {
|
||||||
log.Warnf("Image info for %s not found", ver.Version)
|
log.Warnf("Image info for %s not found", ver.Version)
|
||||||
log.Warnf("Skipping image deletion")
|
log.Warnf("Skipping image deletion")
|
||||||
|
@ -239,7 +240,7 @@ func deleteImage(ctx context.Context, clients rmImageClients, ver versionsapi.Ve
|
||||||
}
|
}
|
||||||
|
|
||||||
type rmImageClients struct {
|
type rmImageClients struct {
|
||||||
version *verclient.Client
|
version *verclient.VersionsClient
|
||||||
gcp *gcpClient
|
gcp *gcpClient
|
||||||
aws *awsClient
|
aws *awsClient
|
||||||
az *azureClient
|
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
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"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"
|
"net/http"
|
||||||
"testing"
|
"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/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/goleak"
|
"go.uber.org/goleak"
|
||||||
|
@ -190,7 +190,7 @@ func TestFetchVersionList(t *testing.T) {
|
||||||
return tc.serverResp
|
return tc.serverResp
|
||||||
})
|
})
|
||||||
|
|
||||||
fetcher := VersionAPIFetcher{&fetcher{httpc: client}}
|
fetcher := Fetcher{client}
|
||||||
|
|
||||||
list, err := fetcher.FetchVersionList(context.Background(), tc.list)
|
list, err := fetcher.FetchVersionList(context.Background(), tc.list)
|
||||||
|
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package versionsapi
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"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,
|
The package also provides helper functions that can be used in context of the versions API,
|
||||||
e.g. to validate versions.
|
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",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/measurements",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/sigstore",
|
"//internal/sigstore",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
|
@ -28,7 +28,7 @@ go_test(
|
||||||
srcs = ["measurements_test.go"],
|
srcs = ["measurements_test.go"],
|
||||||
embed = [":measurements"],
|
embed = [":measurements"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/sigstore",
|
"//internal/sigstore",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
|
|
|
@ -7,7 +7,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/measurements/measurement-generator",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/measurements/measurement-generator",
|
||||||
visibility = ["//visibility:private"],
|
visibility = ["//visibility:private"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/sigstore",
|
"//internal/sigstore",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||||
|
|
|
@ -31,7 +31,7 @@ import (
|
||||||
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
||||||
"gopkg.in/yaml.v3"
|
"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/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/yaml.v3"
|
"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/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
|
|
|
@ -5,6 +5,7 @@ go_library(
|
||||||
name = "config",
|
name = "config",
|
||||||
srcs = [
|
srcs = [
|
||||||
"attestation.go",
|
"attestation.go",
|
||||||
|
"attestationversion.go",
|
||||||
"azure.go",
|
"azure.go",
|
||||||
"config.go",
|
"config.go",
|
||||||
"config_doc.go",
|
"config_doc.go",
|
||||||
|
@ -18,9 +19,9 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/config",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/config",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/configapi",
|
"//internal/api/attestationconfig",
|
||||||
"//internal/api/fetcher",
|
"//internal/api/attestationconfig/fetcher",
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/attestation/idkeydigest",
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
|
@ -44,14 +45,15 @@ go_test(
|
||||||
name = "config_test",
|
name = "config_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"attestation_test.go",
|
"attestation_test.go",
|
||||||
|
"attestationversion_test.go",
|
||||||
"config_test.go",
|
"config_test.go",
|
||||||
"validation_test.go",
|
"validation_test.go",
|
||||||
],
|
],
|
||||||
data = glob(["testdata/**"]),
|
data = glob(["testdata/**"]),
|
||||||
embed = [":config"],
|
embed = [":config"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/configapi",
|
"//internal/api/attestationconfig",
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/config/instancetypes",
|
"//internal/config/instancetypes",
|
||||||
|
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package configapi
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package configapi
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
|
@ -11,9 +11,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"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"`
|
Measurements measurements.M `json:"measurements" yaml:"measurements" validate:"required,no_placeholders"`
|
||||||
// description: |
|
// description: |
|
||||||
// Lowest acceptable bootloader version.
|
// Lowest acceptable bootloader version.
|
||||||
BootloaderVersion configapi.AttestationVersion `json:"bootloaderVersion" yaml:"bootloaderVersion"`
|
BootloaderVersion AttestationVersion `json:"bootloaderVersion" yaml:"bootloaderVersion"`
|
||||||
// description: |
|
// description: |
|
||||||
// Lowest acceptable TEE version.
|
// Lowest acceptable TEE version.
|
||||||
TEEVersion configapi.AttestationVersion `json:"teeVersion" yaml:"teeVersion"`
|
TEEVersion AttestationVersion `json:"teeVersion" yaml:"teeVersion"`
|
||||||
// description: |
|
// description: |
|
||||||
// Lowest acceptable SEV-SNP version.
|
// Lowest acceptable SEV-SNP version.
|
||||||
SNPVersion configapi.AttestationVersion `json:"snpVersion" yaml:"snpVersion"`
|
SNPVersion AttestationVersion `json:"snpVersion" yaml:"snpVersion"`
|
||||||
// description: |
|
// description: |
|
||||||
// Lowest acceptable microcode version.
|
// Lowest acceptable microcode version.
|
||||||
MicrocodeVersion configapi.AttestationVersion `json:"microcodeVersion" yaml:"microcodeVersion"`
|
MicrocodeVersion AttestationVersion `json:"microcodeVersion" yaml:"microcodeVersion"`
|
||||||
// description: |
|
// description: |
|
||||||
// Configuration for validating the firmware signature.
|
// Configuration for validating the firmware signature.
|
||||||
FirmwareSignerConfig SNPFirmwareSignerConfig `json:"firmwareSignerConfig" yaml:"firmwareSignerConfig"`
|
FirmwareSignerConfig SNPFirmwareSignerConfig `json:"firmwareSignerConfig" yaml:"firmwareSignerConfig"`
|
||||||
|
@ -50,10 +51,10 @@ type AzureSEVSNP struct {
|
||||||
func DefaultForAzureSEVSNP() *AzureSEVSNP {
|
func DefaultForAzureSEVSNP() *AzureSEVSNP {
|
||||||
return &AzureSEVSNP{
|
return &AzureSEVSNP{
|
||||||
Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureSEVSNP{}),
|
Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureSEVSNP{}),
|
||||||
BootloaderVersion: configapi.NewLatestPlaceholderVersion(),
|
BootloaderVersion: NewLatestPlaceholderVersion(),
|
||||||
TEEVersion: configapi.NewLatestPlaceholderVersion(),
|
TEEVersion: NewLatestPlaceholderVersion(),
|
||||||
SNPVersion: configapi.NewLatestPlaceholderVersion(),
|
SNPVersion: NewLatestPlaceholderVersion(),
|
||||||
MicrocodeVersion: configapi.NewLatestPlaceholderVersion(),
|
MicrocodeVersion: NewLatestPlaceholderVersion(),
|
||||||
FirmwareSignerConfig: SNPFirmwareSignerConfig{
|
FirmwareSignerConfig: SNPFirmwareSignerConfig{
|
||||||
AcceptedKeyDigests: idkeydigest.DefaultList(),
|
AcceptedKeyDigests: idkeydigest.DefaultList(),
|
||||||
EnforcementPolicy: idkeydigest.MAAFallback,
|
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.
|
// FetchAndSetLatestVersionNumbers fetches the latest version numbers from the configapi and sets them.
|
||||||
func (c *AzureSEVSNP) FetchAndSetLatestVersionNumbers(fetcher fetcher.ConfigAPIFetcher, version versionsapi.Version) error {
|
func (c *AzureSEVSNP) FetchAndSetLatestVersionNumbers(fetcher attestationconfigfetcher.AttestationConfigAPIFetcher, version versionsapi.Version) error {
|
||||||
versions, err := fetcher.FetchLatestAzureSEVSNPVersion(context.Background(), version)
|
versions, err := fetcher.FetchAzureSEVSNPVersionLatest(context.Background(), version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// set number and keep isLatest flag
|
// set number and keep isLatest flag
|
||||||
c.mergeVersionNumbers(versions)
|
c.mergeVersionNumbers(versions.AzureSEVSNPVersion)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,8 @@ import (
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
en_translations "github.com/go-playground/validator/v10/translations/en"
|
en_translations "github.com/go-playground/validator/v10/translations/en"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
attestationconfigfetcher "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig/fetcher"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
versionsapi "github.com/edgelesssys/constellation/v2/internal/api/versions"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"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.
|
// 2. For "latest" version values of the attestation variants fetch the version numbers.
|
||||||
// 3. Read secrets from environment variables.
|
// 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.
|
// 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
|
// Read config file
|
||||||
c, err := fromFile(fileHandler, name)
|
c, err := fromFile(fileHandler, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"go.uber.org/goleak"
|
"go.uber.org/goleak"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/configapi"
|
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
|
||||||
"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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
||||||
|
@ -75,11 +75,11 @@ func TestReadConfigFile(t *testing.T) {
|
||||||
configName: constants.ConfigFilename,
|
configName: constants.ConfigFilename,
|
||||||
wantResult: func() *Config {
|
wantResult: func() *Config {
|
||||||
conf := Default()
|
conf := Default()
|
||||||
conf.Attestation.AzureSEVSNP.BootloaderVersion = configapi.AttestationVersion{
|
conf.Attestation.AzureSEVSNP.BootloaderVersion = AttestationVersion{
|
||||||
Value: 1,
|
Value: 1,
|
||||||
IsLatest: false,
|
IsLatest: false,
|
||||||
}
|
}
|
||||||
conf.Attestation.AzureSEVSNP.TEEVersion = configapi.AttestationVersion{
|
conf.Attestation.AzureSEVSNP.TEEVersion = AttestationVersion{
|
||||||
Value: 2,
|
Value: 2,
|
||||||
IsLatest: false,
|
IsLatest: false,
|
||||||
}
|
}
|
||||||
|
@ -892,8 +892,10 @@ func (f fakeConfigFetcher) FetchAzureSEVSNPVersion(_ context.Context, _ configap
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fakeConfigFetcher) FetchLatestAzureSEVSNPVersion(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersion, error) {
|
func (f fakeConfigFetcher) FetchAzureSEVSNPVersionLatest(_ context.Context, _ versionsapi.Version) (configapi.AzureSEVSNPVersionGet, error) {
|
||||||
return testCfg, nil
|
return configapi.AzureSEVSNPVersionGet{
|
||||||
|
AzureSEVSNPVersion: testCfg,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var testCfg = configapi.AzureSEVSNPVersion{
|
var testCfg = configapi.AzureSEVSNPVersion{
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"golang.org/x/mod/semver"
|
"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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
|
|
|
@ -193,6 +193,8 @@ const (
|
||||||
CDNAPIPrefix = CDNAPIBase + "/v1"
|
CDNAPIPrefix = CDNAPIBase + "/v1"
|
||||||
// CDNAPIPrefixV2 is the prefix of the Constellation API (v2).
|
// CDNAPIPrefixV2 is the prefix of the Constellation API (v2).
|
||||||
CDNAPIPrefixV2 = CDNAPIBase + "/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 is name of file containing image measurements.
|
||||||
CDNMeasurementsFile = "measurements.json"
|
CDNMeasurementsFile = "measurements.json"
|
||||||
// CDNMeasurementsSignature is name of file containing signature for CDNMeasurementsFile.
|
// CDNMeasurementsSignature is name of file containing signature for CDNMeasurementsFile.
|
||||||
|
|
|
@ -11,7 +11,8 @@ go_library(
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/fetcher",
|
"//internal/api/fetcher",
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
|
"//internal/api/versions/fetcher",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
"@com_github_schollz_progressbar_v3//:progressbar",
|
"@com_github_schollz_progressbar_v3//:progressbar",
|
||||||
|
@ -27,7 +28,7 @@ go_test(
|
||||||
],
|
],
|
||||||
embed = [":imagefetcher"],
|
embed = [":imagefetcher"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
|
|
|
@ -20,7 +20,8 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/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"
|
||||||
|
versionsfetcher "github.com/edgelesssys/constellation/v2/internal/api/versions/fetcher"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
@ -35,7 +36,7 @@ type Fetcher struct {
|
||||||
// New returns a new image fetcher.
|
// New returns a new image fetcher.
|
||||||
func New() *Fetcher {
|
func New() *Fetcher {
|
||||||
return &Fetcher{
|
return &Fetcher{
|
||||||
fetcher: fetcher.NewVersionAPIFetcher(),
|
fetcher: versionsfetcher.New(),
|
||||||
fs: &afero.Afero{Fs: afero.NewOsFs()},
|
fs: &afero.Afero{Fs: afero.NewOsFs()},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"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/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/osimage/secureboot",
|
"//internal/osimage/secureboot",
|
||||||
],
|
],
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/archive",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/archive",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
"@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"
|
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
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/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/aws",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/aws",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"//internal/osimage",
|
"//internal/osimage",
|
||||||
"//internal/osimage/secureboot",
|
"//internal/osimage/secureboot",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||||
"github.com/aws/smithy-go"
|
"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/logger"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/osimage/secureboot"
|
"github.com/edgelesssys/constellation/v2/internal/osimage/secureboot"
|
||||||
|
|
|
@ -9,7 +9,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/azure",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/azure",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"//internal/osimage",
|
"//internal/osimage",
|
||||||
"@com_github_azure_azure_sdk_for_go_sdk_azcore//runtime",
|
"@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"
|
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/blob"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/pageblob"
|
"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/logger"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/gcp",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/gcp",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"//internal/osimage",
|
"//internal/osimage",
|
||||||
"//internal/osimage/secureboot",
|
"//internal/osimage/secureboot",
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
compute "cloud.google.com/go/compute/apiv1"
|
compute "cloud.google.com/go/compute/apiv1"
|
||||||
"cloud.google.com/go/compute/apiv1/computepb"
|
"cloud.google.com/go/compute/apiv1/computepb"
|
||||||
"cloud.google.com/go/storage"
|
"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/logger"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
"github.com/edgelesssys/constellation/v2/internal/osimage"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/osimage/secureboot"
|
"github.com/edgelesssys/constellation/v2/internal/osimage/secureboot"
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
"@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"
|
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
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/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/measurementsuploader",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/measurementsuploader",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
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/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
|
|
@ -6,7 +6,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/nop",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/nop",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/api/versionsapi",
|
"//internal/api/versions",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"//internal/osimage",
|
"//internal/osimage",
|
||||||
],
|
],
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue