diff --git a/.golangci.yml b/.golangci.yml index 008f7f80..f028a943 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -80,6 +80,7 @@ linters-settings: - github.com/opencontainers/image-spec/specs-go/v1 - oras.land/oras-go/v2 - github.com/wI2L/jsondiff + - github.com/google/uuid exhaustive: # Switch statements are to be considered exhaustive if a 'default' case is # present, even if all enum members aren't listed in the switch. diff --git a/build/rofl/oci.go b/build/rofl/oci.go index 5eb7f858..77e301d0 100644 --- a/build/rofl/oci.go +++ b/build/rofl/oci.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "maps" + "net/http" "os" "path/filepath" "slices" @@ -27,6 +28,9 @@ const ( ociTypeOrcArtifact = "application/vnd.oasis.orc" ) +// DefaultOCIRegistry is the default OCI registry. +const DefaultOCIRegistry = "rofl.sh" + // PushBundleToOciRepository pushes an ORC bundle to the given remote OCI repository. // // Returns the OCI manifest digest and the ORC manifest hash. @@ -118,11 +122,17 @@ func PushBundleToOciRepository(bundleFn, dst string) (string, hash.Hash, error) if err != nil { return "", hash.Hash{}, fmt.Errorf("failed to init OCI credential store: %w", err) } - repo.Client = &auth.Client{ + client := &auth.Client{ Client: retry.DefaultClient, Cache: auth.NewCache(), Credential: credentials.Credential(creds), } + if strings.Contains(dst, DefaultOCIRegistry) { + client.Header = http.Header{ + "X-Rofl-Registry-Caller": []string{"cli"}, + } + } + repo.Client = client // Push to remote repository. if _, err = oras.Copy(ctx, store, tag, repo, tag, oras.DefaultCopyOptions); err != nil { diff --git a/cmd/rofl/deploy.go b/cmd/rofl/deploy.go index 41b693bf..ae350bef 100644 --- a/cmd/rofl/deploy.go +++ b/cmd/rofl/deploy.go @@ -8,7 +8,9 @@ import ( "maps" "os" "sort" + "time" + "github.com/google/uuid" "github.com/spf13/cobra" flag "github.com/spf13/pflag" @@ -117,8 +119,10 @@ var ( // Push ORC to OCI repository. if deployment.OCIRepository == "" { - // TODO: Support default OCI repository. - cobra.CheckErr(fmt.Sprintf("Missing OCI repository for deployment '%s'.", deploymentName)) + // Use default OCI repository with random name and timestamp tag. + deployment.OCIRepository = fmt.Sprintf( + "%s/%s:%d", buildRofl.DefaultOCIRegistry, uuid.New(), time.Now().Unix(), + ) } fmt.Printf("Pushing ROFL app to OCI repository '%s'...\n", deployment.OCIRepository) @@ -126,6 +130,10 @@ var ( ociDigest, manifestHash, err := buildRofl.PushBundleToOciRepository(orcFilename, deployment.OCIRepository) switch { case err == nil: + // Save the OCI repository field to the configuration file so we avoid multiple uploads. + if err := manifest.Save(); err != nil { + cobra.CheckErr(fmt.Sprintf("Failed to update manifest with OCI repository: %s", err)) + } case errors.Is(err, os.ErrNotExist): cobra.CheckErr(fmt.Sprintf("ROFL app bundle '%s' not found. Run `oasis rofl build` first.", orcFilename)) default: diff --git a/go.mod b/go.mod index c294842d..3c0774a5 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/ethereum/go-ethereum v1.15.0 github.com/foxboron/go-uefi v0.0.0-20241017190036-fab4fdf2f2f3 github.com/github/go-spdx/v2 v2.3.2 + github.com/google/uuid v1.6.0 github.com/miguelmota/go-ethereum-hdwallet v0.1.2 github.com/mitchellh/mapstructure v1.5.0 github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a