From 01ffe44ce9b550e1ea1c746750dfcacd3e5c67b7 Mon Sep 17 00:00:00 2001 From: Kim Christensen Date: Fri, 20 Sep 2024 10:16:51 +0200 Subject: [PATCH 1/2] feat: Retag referenced images when they are relocated During relocation of referenced images, the images will no longer loose their tag and name. Signed-off-by: Kim Christensen --- cmd/porter/bundle.go | 2 + docs/content/docs/references/cli/build.md | 1 + .../docs/references/cli/bundles_build.md | 1 + docs/content/docs/references/cli/publish.md | 1 + pkg/cnab/cnab-to-oci/provider.go | 10 + pkg/cnab/cnab-to-oci/registry.go | 54 ++ pkg/cnab/config-adapter/adapter.go | 5 +- pkg/cnab/config-adapter/adapter_test.go | 119 +++-- pkg/cnab/config-adapter/helpers.go | 2 +- pkg/cnab/config-adapter/stamp.go | 8 +- pkg/cnab/config-adapter/stamp_test.go | 67 ++- .../testdata/mybuns-depsv1.bundle.json | 3 +- .../mybuns-depsv1.bundle.preserveTags.json | 475 +++++++++++++++++ .../testdata/mybuns-depsv2.bundle.json | 3 +- .../mybuns-depsv2.bundle.preserveTags.json | 478 ++++++++++++++++++ .../testdata/myenv-depsv2.bundle.json | 3 +- pkg/porter/build.go | 6 +- pkg/porter/build_integration_test.go | 36 +- pkg/porter/cnab.go | 3 + pkg/porter/copy.go | 2 +- pkg/porter/generateManifest.go | 56 +- pkg/porter/generateManifest_test.go | 4 + pkg/porter/publish.go | 23 +- pkg/porter/stamp.go | 15 +- .../expected-result-preserve-tags.yaml | 36 ++ .../testdata/porter-with-image-tag.yaml | 82 +++ tests/integration/copy_test.go | 51 ++ tests/integration/publish_test.go | 50 ++ .../bundles/bundle-with-image/helpers.sh | 25 + .../bundles/bundle-with-image/porter.yaml | 34 ++ tests/testdata/embeddedimg/.dockerignore | 4 + tests/testdata/embeddedimg/.gitignore | 1 + .../embeddedimg/connection-string.txt | 1 + tests/testdata/embeddedimg/porter.yaml | 69 +++ tests/testdata/helpers.go | 3 + tests/tester/helpers.go | 33 +- 36 files changed, 1643 insertions(+), 123 deletions(-) create mode 100644 pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.preserveTags.json create mode 100644 pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.preserveTags.json create mode 100644 pkg/porter/testdata/generateManifest/expected-result-preserve-tags.yaml create mode 100644 pkg/porter/testdata/porter-with-image-tag.yaml create mode 100755 tests/integration/testdata/bundles/bundle-with-image/helpers.sh create mode 100644 tests/integration/testdata/bundles/bundle-with-image/porter.yaml create mode 100644 tests/testdata/embeddedimg/.dockerignore create mode 100644 tests/testdata/embeddedimg/.gitignore create mode 100644 tests/testdata/embeddedimg/connection-string.txt create mode 100644 tests/testdata/embeddedimg/porter.yaml diff --git a/cmd/porter/bundle.go b/cmd/porter/bundle.go index 164dd30d9..8b4a3e297 100644 --- a/cmd/porter/bundle.go +++ b/cmd/porter/bundle.go @@ -99,6 +99,7 @@ The docker driver builds the bundle image using the local Docker host. To use a "Define an individual key-value pair for the custom section in the form of NAME=VALUE. Use dot notation to specify a nested custom field. May be specified multiple times. Max length is 5,000 characters when used as a build argument.") f.BoolVar(&opts.InsecureRegistry, "insecure-registry", false, "Don't require TLS when pulling referenced images") + f.BoolVar(&opts.PreserveTags, "preserve-tags", false, "Preserve the original tag name on referenced images") // Allow configuring the --driver flag with build-driver, to avoid conflicts with other commands cmd.Flag("driver").Annotations = map[string][]string{ @@ -178,6 +179,7 @@ Note: if overrides for registry/tag/reference are provided, this command only re } f.BoolVar(&opts.AutoBuildDisabled, "autobuild-disabled", false, "Do not automatically build the bundle from source when the last build is out-of-date.") f.BoolVar(&opts.SignBundle, "sign-bundle", false, "Sign the bundle using the configured signing plugin") + f.BoolVar(&opts.PreserveTags, "preserve-tags", false, "Preserve the original tag name on referenced images") return &cmd } diff --git a/docs/content/docs/references/cli/build.md b/docs/content/docs/references/cli/build.md index 2a1e51afb..244ab1b78 100644 --- a/docs/content/docs/references/cli/build.md +++ b/docs/content/docs/references/cli/build.md @@ -46,6 +46,7 @@ porter build [flags] --name string Override the bundle name --no-cache Do not use the Docker cache when building the bundle image. --no-lint Do not run the linter + --preserve-tags Preserve the original tag name on referenced images --secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). Custom values are accessible as build arguments in the template Dockerfile and in the manifest using template variables. May be specified multiple times. --ssh stringArray SSH agent socket or keys to expose to the build (format: default|[=|[,]]). May be specified multiple times. --version string Override the bundle version diff --git a/docs/content/docs/references/cli/bundles_build.md b/docs/content/docs/references/cli/bundles_build.md index f9ca1fffd..906a30af0 100644 --- a/docs/content/docs/references/cli/bundles_build.md +++ b/docs/content/docs/references/cli/bundles_build.md @@ -46,6 +46,7 @@ porter bundles build [flags] --name string Override the bundle name --no-cache Do not use the Docker cache when building the bundle image. --no-lint Do not run the linter + --preserve-tags Preserve the original tag name on referenced images --secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). Custom values are accessible as build arguments in the template Dockerfile and in the manifest using template variables. May be specified multiple times. --ssh stringArray SSH agent socket or keys to expose to the build (format: default|[=|[,]]). May be specified multiple times. --version string Override the bundle version diff --git a/docs/content/docs/references/cli/publish.md b/docs/content/docs/references/cli/publish.md index 9a6b44d18..e1009adb4 100644 --- a/docs/content/docs/references/cli/publish.md +++ b/docs/content/docs/references/cli/publish.md @@ -40,6 +40,7 @@ porter publish [flags] --force Force push the bundle to overwrite the previously published bundle -h, --help help for publish --insecure-registry Don't require TLS for the registry + --preserve-tags Preserve the original tag name on referenced images -r, --reference string Use a bundle in an OCI registry specified by the given reference. --registry string Override the registry portion of the bundle reference, e.g. docker.io, myregistry.com/myorg --sign-bundle Sign the bundle using the configured signing plugin diff --git a/pkg/cnab/cnab-to-oci/provider.go b/pkg/cnab/cnab-to-oci/provider.go index fd59d234d..553497c2a 100644 --- a/pkg/cnab/cnab-to-oci/provider.go +++ b/pkg/cnab/cnab-to-oci/provider.go @@ -54,3 +54,13 @@ func (o RegistryOptions) toCraneOptions() []crane.Option { } return result } + +type PushBundleOptions struct { + RegistryOptions +} + +func WithRegistryOptions(registryOpts RegistryOptions) func(*PushBundleOptions) { + return func(opts *PushBundleOptions) { + opts.RegistryOptions = registryOpts + } +} diff --git a/pkg/cnab/cnab-to-oci/registry.go b/pkg/cnab/cnab-to-oci/registry.go index 7ce5831a2..55ac6c2ba 100644 --- a/pkg/cnab/cnab-to-oci/registry.go +++ b/pkg/cnab/cnab-to-oci/registry.go @@ -9,6 +9,7 @@ import ( "strings" "get.porter.sh/porter/pkg/cnab" + configadapter "get.porter.sh/porter/pkg/cnab/config-adapter" "get.porter.sh/porter/pkg/portercontext" "get.porter.sh/porter/pkg/tracing" "github.com/cnabio/cnab-go/driver/docker" @@ -95,6 +96,7 @@ func (r *Registry) PullBundle(ctx context.Context, ref cnab.OCIReference, opts R return bundleRef, nil } +// PushBundle pushes a bundle to an OCI registry. func (r *Registry) PushBundle(ctx context.Context, bundleRef cnab.BundleReference, opts RegistryOptions) (cnab.BundleReference, error) { ctx, log := tracing.StartSpan(ctx) defer log.EndSpan() @@ -154,6 +156,17 @@ func (r *Registry) PushBundle(ctx context.Context, bundleRef cnab.BundleReferenc } bundleRef.Digest = d.Digest + stamp, err := configadapter.LoadStamp(bundleRef.Definition) + if err != nil { + return cnab.BundleReference{}, log.Errorf("error loading stamp from bundle: %w", err) + } + if stamp.PreserveTags { + err = preserveRelocatedImageTags(ctx, bundleRef, opts) + if err != nil { + return cnab.BundleReference{}, log.Error(fmt.Errorf("error preserving tags on relocated images: %w", err)) + } + } + log.Infof("Bundle %s pushed successfully, with digest %q\n", bundleRef.Reference, d.Digest) return bundleRef, nil } @@ -461,3 +474,44 @@ func GetInsecureRegistryTransport() *http.Transport { skipTLS.TLSClientConfig.InsecureSkipVerify = true return skipTLS } + +func preserveRelocatedImageTags(ctx context.Context, bundleRef cnab.BundleReference, opts RegistryOptions) error { + _, log := tracing.StartSpan(ctx) + defer log.EndSpan() + + if len(bundleRef.Definition.Images) <= 0 { + log.Debugf("No images to preserve tags on") + return nil + } + + log.Infof("Tagging relocated images...") + for _, image := range bundleRef.Definition.Images { + imageRef, err := cnab.ParseOCIReference(image.Image) + if err != nil { + return log.Errorf("error parsing image reference %s: %w", image.Image, err) + } + + if !imageRef.HasTag() { + log.Debugf("Image %s has no tag, skipping", imageRef) + continue + } + + if relocImage, ok := bundleRef.RelocationMap[image.Image]; ok { + relocRef, err := cnab.ParseOCIReference(relocImage) + if err != nil { + return log.Errorf("error parsing image reference %s: %w", relocImage, err) + } + + dstRef := fmt.Sprintf("%s/%s:%s", relocRef.Registry(), imageRef.Repository(), imageRef.Tag()) + log.Debugf("Copying image %s to %s", relocRef, dstRef) + err = crane.Copy(relocRef.String(), dstRef, opts.toCraneOptions()...) + if err != nil { + return log.Errorf("error copying image %s to %s: %w", relocRef, dstRef, err) + } + } else { + log.Debugf("No relocation for image %s", imageRef) + } + } + + return nil +} diff --git a/pkg/cnab/config-adapter/adapter.go b/pkg/cnab/config-adapter/adapter.go index aabb3ba5c..b44bb2394 100644 --- a/pkg/cnab/config-adapter/adapter.go +++ b/pkg/cnab/config-adapter/adapter.go @@ -25,6 +25,7 @@ type ManifestConverter struct { Manifest *manifest.Manifest ImageDigests map[string]string InstalledMixins []mixin.Metadata + PreserveTags bool } func NewManifestConverter( @@ -32,12 +33,14 @@ func NewManifestConverter( manifest *manifest.Manifest, imageDigests map[string]string, mixins []mixin.Metadata, + preserveTags bool, ) *ManifestConverter { return &ManifestConverter{ config: config, Manifest: manifest, ImageDigests: imageDigests, InstalledMixins: mixins, + PreserveTags: preserveTags, } } @@ -45,7 +48,7 @@ func (c *ManifestConverter) ToBundle(ctx context.Context) (cnab.ExtendedBundle, ctx, span := tracing.StartSpan(ctx) defer span.EndSpan() - stamp, err := c.GenerateStamp(ctx) + stamp, err := c.GenerateStamp(ctx, c.PreserveTags) if err != nil { return cnab.ExtendedBundle{}, span.Error(err) } diff --git a/pkg/cnab/config-adapter/adapter_test.go b/pkg/cnab/config-adapter/adapter_test.go index d4edaa626..a1c393566 100644 --- a/pkg/cnab/config-adapter/adapter_test.go +++ b/pkg/cnab/config-adapter/adapter_test.go @@ -28,23 +28,39 @@ func TestManifestConverter(t *testing.T) { configHandler func(c *config.Config) manifestPath string goldenFile string + preserveTags bool }{ {name: "mybuns depsv1", configHandler: func(c *config.Config) {}, manifestPath: "tests/testdata/mybuns/porter.yaml", - goldenFile: "testdata/mybuns-depsv1.bundle.json"}, + goldenFile: "testdata/mybuns-depsv1.bundle.json", + preserveTags: false}, + {name: "mybuns depsv1 preserveTags", + configHandler: func(c *config.Config) {}, + manifestPath: "tests/testdata/mybuns/porter.yaml", + goldenFile: "testdata/mybuns-depsv1.bundle.preserveTags.json", + preserveTags: true}, {name: "mybuns depsv2", configHandler: func(c *config.Config) { c.SetExperimentalFlags(experimental.FlagDependenciesV2) }, manifestPath: "tests/testdata/mybuns/porter.yaml", - goldenFile: "testdata/mybuns-depsv2.bundle.json"}, + goldenFile: "testdata/mybuns-depsv2.bundle.json", + preserveTags: false}, + {name: "mybuns depsv2 preserveTags", + configHandler: func(c *config.Config) { + c.SetExperimentalFlags(experimental.FlagDependenciesV2) + }, + manifestPath: "tests/testdata/mybuns/porter.yaml", + goldenFile: "testdata/mybuns-depsv2.bundle.preserveTags.json", + preserveTags: true}, {name: "myenv depsv2", configHandler: func(c *config.Config) { c.SetExperimentalFlags(experimental.FlagDependenciesV2) }, manifestPath: "tests/testdata/myenv/porter.yaml", - goldenFile: "testdata/myenv-depsv2.bundle.json"}, + goldenFile: "testdata/myenv-depsv2.bundle.json", + preserveTags: false}, } for _, tc := range testcases { @@ -64,7 +80,7 @@ func TestManifestConverter(t *testing.T) { {Name: "exec", VersionInfo: pkgmgmt.VersionInfo{Version: "v1.2.3"}}, } - a := NewManifestConverter(c.Config, m, nil, installedMixins) + a := NewManifestConverter(c.Config, m, nil, installedMixins, tc.preserveTags) bun, err := a.ToBundle(ctx) require.NoError(t, err, "ToBundle failed") @@ -89,39 +105,54 @@ func prepBundleForDiff(b *bundle.Bundle) { } func TestManifestConverter_ToBundle(t *testing.T) { - t.Parallel() + testcases := []struct { + name string + preserveTags bool + }{ + {name: "not preserving tags", preserveTags: false}, + {name: "preserving tags", preserveTags: true}, + } - c := config.NewTestConfig(t) - c.TestContext.AddTestFileFromRoot("tests/testdata/mybuns/porter.yaml", config.Name) + for _, tc := range testcases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() - ctx := context.Background() - m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) - require.NoError(t, err, "could not load manifest") + c := config.NewTestConfig(t) + c.TestContext.AddTestFileFromRoot("tests/testdata/mybuns/porter.yaml", config.Name) - a := NewManifestConverter(c.Config, m, nil, nil) + ctx := context.Background() + m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) + require.NoError(t, err, "could not load manifest") - bun, err := a.ToBundle(ctx) - require.NoError(t, err, "ToBundle failed") + a := NewManifestConverter(c.Config, m, nil, nil, tc.preserveTags) + + bun, err := a.ToBundle(ctx) + require.NoError(t, err, "ToBundle failed") - assert.Equal(t, cnab.BundleSchemaVersion(), bun.SchemaVersion) - assert.Equal(t, "mybuns", bun.Name) - assert.Equal(t, "0.1.2", bun.Version) - assert.Equal(t, "A very thorough test bundle", bun.Description) + assert.Equal(t, cnab.BundleSchemaVersion(), bun.SchemaVersion) + assert.Equal(t, "mybuns", bun.Name) + assert.Equal(t, "0.1.2", bun.Version) + assert.Equal(t, "A very thorough test bundle", bun.Description) - stamp, err := LoadStamp(bun) - require.NoError(t, err, "could not load porter's stamp") - assert.NotNil(t, stamp) + stamp, err := LoadStamp(bun) + require.NoError(t, err, "could not load porter's stamp") + assert.NotNil(t, stamp) - assert.Contains(t, bun.Actions, "status", "custom action 'status' was not populated") + assert.Equal(t, tc.preserveTags, stamp.PreserveTags) - require.Len(t, bun.Credentials, 2, "expected two credentials") - assert.Contains(t, bun.Parameters, "porter-debug", "porter-debug parameter was not defined") - assert.Contains(t, bun.Definitions, "porter-debug-parameter", "porter-debug definition was not defined") + assert.Contains(t, bun.Actions, "status", "custom action 'status' was not populated") - assert.True(t, bun.HasDependenciesV1(), "DependenciesV1 was not populated") - assert.Contains(t, bun.RequiredExtensions, "io.cnab.dependencies") + require.Len(t, bun.Credentials, 2, "expected two credentials") + assert.Contains(t, bun.Parameters, "porter-debug", "porter-debug parameter was not defined") + assert.Contains(t, bun.Definitions, "porter-debug-parameter", "porter-debug definition was not defined") - assert.NotEmpty(t, bun.Outputs, "expected multiple outputs generated") + assert.True(t, bun.HasDependenciesV1(), "DependenciesV1 was not populated") + assert.Contains(t, bun.RequiredExtensions, "io.cnab.dependencies") + + assert.NotEmpty(t, bun.Outputs, "expected multiple outputs generated") + }) + } } func TestManifestConverter_generateBundleCredentials(t *testing.T) { @@ -134,7 +165,7 @@ func TestManifestConverter_generateBundleCredentials(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) bun, err := a.ToBundle(ctx) require.NoError(t, err, "ToBundle failed") @@ -325,7 +356,7 @@ func TestManifestConverter_generateBundleParametersSchema(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) defs := make(definition.Definitions, len(m.Parameters)) params := a.generateBundleParameters(ctx, &defs) @@ -352,7 +383,7 @@ func TestManifestConverter_buildDefaultPorterParameters(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) defs := make(definition.Definitions, len(m.Parameters)) params := a.generateBundleParameters(ctx, &defs) @@ -378,7 +409,7 @@ func TestManifestConverter_generateImages(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) mappedImage := manifest.MappedImage{ Description: "un petite server", @@ -420,7 +451,7 @@ func TestManifestConverter_generateBundleImages_EmptyLabels(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) mappedImage := manifest.MappedImage{ Description: "un petite server", @@ -450,7 +481,7 @@ func TestManifestConverter_generateBundleOutputs(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) outputDefinitions := manifest.OutputDefinitions{ "output1": { @@ -608,7 +639,7 @@ func TestManifestConverter_generateDependenciesv1(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) defs := make(definition.Definitions, len(m.Parameters)) depsExt, depsExtKey, err := a.generateDependencies(ctx, &defs) @@ -714,7 +745,7 @@ func TestManifestConverter_generateDependenciesv2(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) defs := make(definition.Definitions, len(m.Parameters)) depsExt, depsExtKey, err := a.generateDependencies(ctx, &defs) @@ -749,7 +780,7 @@ func TestManifestConverter_generateParameterSources(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) b, err := a.ToBundle(ctx) require.NoError(t, err, "ToBundle failed") @@ -775,7 +806,7 @@ func TestNewManifestConverter_generateOutputWiringParameter(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) outputDef := definition.Schema{ Type: "string", @@ -831,7 +862,7 @@ func TestNewManifestConverter_generateDependencyOutputWiringParameter(t *testing m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) ref := manifest.DependencyOutputReference{Dependency: "mysql", Output: "mysql-password"} name, param, paramDef := a.generateDependencyOutputWiringParameter(ref) @@ -856,7 +887,7 @@ func TestManifestConverter_generateRequiredExtensions_ParameterSources(t *testin m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) bun, err := a.ToBundle(ctx) require.NoError(t, err, "ToBundle failed") @@ -873,7 +904,7 @@ func TestManifestConverter_generateRequiredExtensions(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) bun, err := a.ToBundle(ctx) require.NoError(t, err, "ToBundle failed") @@ -892,7 +923,7 @@ func TestManifestConverter_generateCustomExtensions_withRequired(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) bun, err := a.ToBundle(ctx) require.NoError(t, err, "ToBundle failed") @@ -912,7 +943,7 @@ func TestManifestConverter_GenerateCustomActionDefinitions(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) defs := a.generateCustomActionDefinitions() require.Len(t, defs, 3, "expected 3 custom action definitions to be generated") @@ -986,7 +1017,7 @@ func TestManifestConverter_generateCustomMetadata(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) bun, err := a.ToBundle(ctx) require.NoError(t, err, "ToBundle failed") @@ -1021,7 +1052,7 @@ func TestManifestConverter_generatedMaintainers(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) got := a.generateBundleMaintainers() assert.Len(t, got, len(want), "Created bundle should contain desired maintainers") diff --git a/pkg/cnab/config-adapter/helpers.go b/pkg/cnab/config-adapter/helpers.go index 5e9a6ae2f..352b3b643 100644 --- a/pkg/cnab/config-adapter/helpers.go +++ b/pkg/cnab/config-adapter/helpers.go @@ -24,6 +24,6 @@ func LoadTestBundle(t *testing.T, config *config.Config, path string) cnab.Exten // and making a bundle.json for it. Does not make an accurate representation // of the bundle, but is suitable for testing. func ConvertToTestBundle(ctx context.Context, cfg *config.Config, manifest *manifest.Manifest) (cnab.ExtendedBundle, error) { - converter := NewManifestConverter(cfg, manifest, nil, nil) + converter := NewManifestConverter(cfg, manifest, nil, nil, false) return converter.ToBundle(ctx) } diff --git a/pkg/cnab/config-adapter/stamp.go b/pkg/cnab/config-adapter/stamp.go index 8f73cb9f8..e6037607b 100644 --- a/pkg/cnab/config-adapter/stamp.go +++ b/pkg/cnab/config-adapter/stamp.go @@ -36,8 +36,9 @@ type Stamp struct { EncodedManifest string `json:"manifest"` // Version and commit define the version of the Porter used when a bundle was built. - Version string `json:"version"` - Commit string `json:"commit"` + Version string `json:"version"` + Commit string `json:"commit"` + PreserveTags bool `json:"preserveTags"` } // DecodeManifest base64 decodes the manifest stored in the stamp @@ -113,7 +114,7 @@ func (m MixinRecords) Swap(i, j int) { m[j] = tmp } -func (c *ManifestConverter) GenerateStamp(ctx context.Context) (Stamp, error) { +func (c *ManifestConverter) GenerateStamp(ctx context.Context, preserveTags bool) (Stamp, error) { log := tracing.LoggerFromContext(ctx) stamp := Stamp{} @@ -124,6 +125,7 @@ func (c *ManifestConverter) GenerateStamp(ctx context.Context) (Stamp, error) { return Stamp{}, err } stamp.EncodedManifest = base64.StdEncoding.EncodeToString(rawManifest) + stamp.PreserveTags = preserveTags stamp.Mixins = make(map[string]MixinRecord, len(c.Manifest.Mixins)) usedMixins := c.getUsedMixinRecords() diff --git a/pkg/cnab/config-adapter/stamp_test.go b/pkg/cnab/config-adapter/stamp_test.go index ebdd2cdb6..2a7735eec 100644 --- a/pkg/cnab/config-adapter/stamp_test.go +++ b/pkg/cnab/config-adapter/stamp_test.go @@ -21,31 +21,44 @@ var simpleManifestDigest = "4a748b8ac237b4af8f1eb3a327a82dfdd7eb70f3a1126e97a9e5 func TestConfig_GenerateStamp(t *testing.T) { // Do not run this test in parallel // Still need to figure out what is introducing flakey-ness - - c := config.NewTestConfig(t) - c.TestContext.AddTestFileFromRoot("pkg/manifest/testdata/simple.porter.yaml", config.Name) - - ctx := context.Background() - m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) - require.NoError(t, err, "could not load manifest") - - installedMixins := []mixin.Metadata{ - {Name: "exec", VersionInfo: pkgmgmt.VersionInfo{Version: "v1.2.3"}}, + testcases := []struct { + name string + preserveTags bool + }{ + {name: "not preserving tags", preserveTags: false}, + {name: "preserving tags", preserveTags: true}, } - a := NewManifestConverter(c.Config, m, nil, installedMixins) - stamp, err := a.GenerateStamp(ctx) - require.NoError(t, err, "DigestManifest failed") - assert.Equal(t, simpleManifestDigest, stamp.ManifestDigest) - assert.Equal(t, map[string]MixinRecord{"exec": {Name: "exec", Version: "v1.2.3"}}, stamp.Mixins, "Stamp.Mixins was not populated properly") - assert.Equal(t, pkg.Version, stamp.Version) - assert.Equal(t, pkg.Commit, stamp.Commit) - - gotManifestContentsB, err := stamp.DecodeManifest() - require.NoError(t, err, "DecodeManifest failed") - wantManifestContentsB, err := c.FileSystem.ReadFile(config.Name) - require.NoError(t, err, "could not read %s", config.Name) - assert.Equal(t, string(wantManifestContentsB), string(gotManifestContentsB), "Stamp.EncodedManifest was not popluated and decoded properly") + for _, tc := range testcases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + c := config.NewTestConfig(t) + c.TestContext.AddTestFileFromRoot("pkg/manifest/testdata/simple.porter.yaml", config.Name) + + ctx := context.Background() + m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) + require.NoError(t, err, "could not load manifest") + + installedMixins := []mixin.Metadata{ + {Name: "exec", VersionInfo: pkgmgmt.VersionInfo{Version: "v1.2.3"}}, + } + + a := NewManifestConverter(c.Config, m, nil, installedMixins, tc.preserveTags) + stamp, err := a.GenerateStamp(ctx, tc.preserveTags) + require.NoError(t, err, "DigestManifest failed") + assert.Equal(t, simpleManifestDigest, stamp.ManifestDigest) + assert.Equal(t, map[string]MixinRecord{"exec": {Name: "exec", Version: "v1.2.3"}}, stamp.Mixins, "Stamp.Mixins was not populated properly") + assert.Equal(t, pkg.Version, stamp.Version) + assert.Equal(t, pkg.Commit, stamp.Commit) + assert.Equal(t, tc.preserveTags, stamp.PreserveTags) + + gotManifestContentsB, err := stamp.DecodeManifest() + require.NoError(t, err, "DecodeManifest failed") + wantManifestContentsB, err := c.FileSystem.ReadFile(config.Name) + require.NoError(t, err, "could not read %s", config.Name) + assert.Equal(t, string(wantManifestContentsB), string(gotManifestContentsB), "Stamp.EncodedManifest was not popluated and decoded properly") + }) + } } func TestConfig_LoadStamp(t *testing.T) { @@ -59,6 +72,7 @@ func TestConfig_LoadStamp(t *testing.T) { "mixins": map[string]interface{}{ "exec": struct{}{}, }, + "preserveTags": true, }, }, }) @@ -68,6 +82,7 @@ func TestConfig_LoadStamp(t *testing.T) { assert.Equal(t, "somedigest", stamp.ManifestDigest) assert.Equal(t, map[string]MixinRecord{"exec": {}}, stamp.Mixins, "Stamp.Mixins was not populated properly") assert.Equal(t, "abc123", stamp.EncodedManifest) + assert.Equal(t, true, stamp.PreserveTags) } func TestConfig_LoadStamp_Invalid(t *testing.T) { @@ -146,7 +161,7 @@ func TestConfig_DigestManifest(t *testing.T) { m, err := manifest.LoadManifestFrom(context.Background(), c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) + a := NewManifestConverter(c.Config, m, nil, nil, false) digest, err := a.DigestManifest() require.NoError(t, err, "DigestManifest failed") @@ -176,8 +191,8 @@ func TestConfig_GenerateStamp_IncludeVersion(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, c.Config, config.Name) require.NoError(t, err, "could not load manifest") - a := NewManifestConverter(c.Config, m, nil, nil) - stamp, err := a.GenerateStamp(ctx) + a := NewManifestConverter(c.Config, m, nil, nil, false) + stamp, err := a.GenerateStamp(ctx, false) require.NoError(t, err, "DigestManifest failed") assert.Equal(t, "v1.2.3", stamp.Version) assert.Equal(t, "abc123", stamp.Commit) diff --git a/pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.json b/pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.json index 530ef707d..eb66c74a7 100644 --- a/pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.json +++ b/pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.json @@ -467,7 +467,8 @@ }, "manifest": "IyBUaGlzIGlzIGEgdGVzdCBidW5kbGUgdGhhdCBtYWtlcyBubyBsb2dpY2FsIHNlbnNlLCBidXQgaXQgZG9lcyBleGVyY2lzZSBsb3RzIG9mIGRpZmZlcmVudCBidW5kbGUgZmVhdHVyZXMKc2NoZW1hVHlwZTogQnVuZGxlCnNjaGVtYVZlcnNpb246IDEuMC4xCm5hbWU6IG15YnVucwp2ZXJzaW9uOiAwLjEuMgpkZXNjcmlwdGlvbjogIkEgdmVyeSB0aG9yb3VnaCB0ZXN0IGJ1bmRsZSIKcmVnaXN0cnk6IGxvY2FsaG9zdDo1MDAwCmRvY2tlcmZpbGU6IERvY2tlcmZpbGUudG1wbAoKbWFpbnRhaW5lcnM6Ci0gbmFtZTogIkpvaG4gRG9lIgogIGVtYWlsOiAiam9obi5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9hIgotIG5hbWU6ICJKYW5lIERvZSIKICB1cmw6ICJodHRwczovL2V4YW1wbGUuY29tL2IiCi0gbmFtZTogIkphbmluZSBEb2UiCiAgZW1haWw6ICJqYW5pbmUuZG9lQGV4YW1wbGUuY29tIgotIGVtYWlsOiAibWlrZS5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9jIgoKY3VzdG9tOgogIGFwcDoKICAgIHZlcnNpb246IDEuMi4zCiAgZm9vOgogICAgdGVzdDE6IHRydWUKICAgIHRlc3QyOiAxCiAgICB0ZXN0MzogdmFsdWUKICAgIHRlc3Q0OgogICAgICAtIG9uZQogICAgICAtIHR3bwogICAgICAtIHRocmVlCiAgICB0ZXN0NToKICAgICAgMTogb25lCiAgICAgIHR3bzogdHdvCgpyZXF1aXJlZDoKICAtIGRvY2tlcgoKY3JlZGVudGlhbHM6CiAgLSBuYW1lOiB1c2VybmFtZQogICAgZGVzY3JpcHRpb246ICJUaGUgbmFtZSB5b3Ugd2FudCBvbiB0aGUgYXVkaXQgbG9nIgogICAgZW52OiBST09UX1VTRVJOQU1FCiAgICByZXF1aXJlZDogZmFsc2UKICAtIG5hbWU6IHBhc3N3b3JkCiAgICBwYXRoOiAvdG1wL3Bhc3N3b3JkCiAgICBhcHBseVRvOgogICAgICAtIGJvb20KCnBhcmFtZXRlcnM6CiAgLSBuYW1lOiBsb2dfbGV2ZWwKICAgIGRlc2NyaXB0aW9uOiAiSG93IHVuaGVscGZ1bCB3b3VsZCB5b3UgbGlrZSB0aGUgbG9ncyB0byBiZT8iCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBtaW5pbXVtOiAxCiAgICBtYXhpbXVtOiAxMQogICAgZGVmYXVsdDogNQogIC0gbmFtZTogcGFzc3dvcmQKICAgIGRlc2NyaXB0aW9uOiAiVGhlIHN1cGVyIHNlY3JldCBkYXRhIgogICAgdHlwZTogc3RyaW5nCiAgICBkZWZhdWx0OiAiZGVmYXVsdC1zZWNyZXQiCiAgICBzZW5zaXRpdmU6IHRydWUKICAtIG5hbWU6IG15c3FsLWNvbm5zdHIKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIgIyBTZXR0aW5nIGEgZGVmYXVsdCBzbyB0aGF0IHRoaXMgaXNuJ3QgcmVxdWlyZWQgZm9yIGluc3RhbGwKICAgIHNvdXJjZToKICAgICAgZGVwZW5kZW5jeTogZGIKICAgICAgb3V0cHV0OiBjb25uc3RyCiAgLSBuYW1lOiBjaGFvc19tb25rZXkKICAgIGRlc2NyaXB0aW9uOiAiU2V0IHRvIHRydWUgdG8gbWFrZSB0aGUgYnVuZGxlIGZhaWwiCiAgICB0eXBlOiBib29sZWFuCiAgICBkZWZhdWx0OiBmYWxzZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIHNvdXJjZToKICAgICAgb3V0cHV0OiB0ZnN0YXRlCiAgICBhcHBseVRvOgogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNmZwogICAgZGVzY3JpcHRpb246ICJBIGpzb24gY29uZmlnIGZpbGUiCiAgICB0eXBlOiBmaWxlCiAgICBkZWZhdWx0OiAnJwogICAgcGF0aDogYnVuY2ZnLmpzb24KICAtIG5hbWU6IGFpbnRlZ2VyCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBkZWZhdWx0OiAxCiAgICBtaW5pbXVtOiAwCiAgICBtYXhpbXVtOiAxMAogIC0gbmFtZTogYW51bWJlcgogICAgdHlwZTogbnVtYmVyCiAgICBkZWZhdWx0OiAwLjUgIyBUaGlzIGlzIGEgcmVncmVzc2lvbiB0ZXN0IHRoYXQgd2UgY2FuIGJvdGggYnVpbGQgYW5kIHB1c2ggYSBidW5kbGUgdGhhdCB1c2VzIG51bWVyaWMgdHlwZXMKICAgIGV4Y2x1c2l2ZU1pbmltdW06IDAKICAgIGV4Y2x1c2l2ZU1heGltdW06IDEKICAtIG5hbWU6IGFzdHJpbmdlbnVtCiAgICB0eXBlOiBzdHJpbmcKICAgIGRlZmF1bHQ6IGJsdWUKICAgIGVudW06CiAgICAgIC0gYmx1ZQogICAgICAtIHJlZAogICAgICAtIHB1cnBsZQogICAgICAtIHBpbmsKICAtIG5hbWU6IGFzdHJpbmcKICAgIHR5cGU6IHN0cmluZwogICAgbWluTGVuZ3RoOiAxCiAgICBtYXhMZW5ndGg6IDEwCiAgICBkZWZhdWx0OiAnYm9vcCEnCiAgLSBuYW1lOiBhYm9vbGVhbgogICAgdHlwZTogYm9vbGVhbgogICAgZGVmYXVsdDogdHJ1ZQogIC0gbmFtZTogaW5zdGFsbG9ubHkKICAgIHR5cGU6IGJvb2xlYW4KICAgIGRlZmF1bHQ6IGZhbHNlCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAtIG5hbWU6IHNlbnNpdGl2ZQogICAgdHlwZTogc3RyaW5nCiAgICBzZW5zaXRpdmU6IHRydWUKICAgIGRlZmF1bHQ6ICJwYXNzdzByZDEyMyIKICAtIG5hbWU6IGpzb25vYmplY3QKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogJyJteW9iamVjdCI6IHsKICAgICAgICAiZm9vIjogInRydWUiLAogICAgICAgICJiYXIiOiBbCiAgICAgICAgICAxLAogICAgICAgICAgMiwKICAgICAgICAgIDMKICAgICAgICBdCiAgICAgIH0nCiAgLSBuYW1lOiBhZmlsZQogICAgdHlwZTogZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9ob21lL25vbnJvb3QvLmt1YmUvY29uZmlnCiAgLSBuYW1lOiBub3R5cGUtZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9jbmFiL2FwcC9jb25maWcudG9tbAogIC0gbmFtZTogbm90eXBlLXN0cmluZwogICAgZGVmYXVsdDogJycKCm91dHB1dHM6CiAgLSBuYW1lOiBtc2cKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNvbm5TdHIKICAgICRpZDogInBvcnRlci5zaC9pbnRlcmZhY2VzL215c3FsLmNvbm5lY3Rpb24tc3RyaW5nIgogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogIC0gbmFtZTogbXlsb2dzCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAgICAgLSB1cGdyYWRlCiAgLSBuYW1lOiByZXN1bHQKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgIHNlbnNpdGl2ZTogdHJ1ZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKCnN0YXRlOgogIC0gbmFtZTogbWFnaWNfZmlsZQogICAgcGF0aDogbWFnaWMudHh0CgpkZXBlbmRlbmNpZXM6CiAgcmVxdWlyZXM6CiAgICAtIG5hbWU6IGRiCiAgICAgIGJ1bmRsZToKICAgICAgICByZWZlcmVuY2U6ICJsb2NhbGhvc3Q6NTAwMC9teWRiOnYwLjEuMCIKICAgICAgcGFyYW1ldGVyczoKICAgICAgICBkYXRhYmFzZTogYmlnZGIKCmltYWdlczoKICB3aGFsZXNheWQ6CiAgICBkZXNjcmlwdGlvbjogIldoYWxlc2F5IGFzIGEgc2VydmljZSIKICAgIGltYWdlVHlwZTogImRvY2tlciIKICAgIHJlcG9zaXRvcnk6IGNhcm9seW52cy93aGFsZXNheWQKICAgIHRhZzogImxhdGVzdCIKCm1peGluczoKICAtIGV4ZWMKICAtIHRlc3RtaXhpbjoKICAgICAgY2xpZW50VmVyc2lvbjogMS4yLjMKCmN1c3RvbUFjdGlvbnM6CiAgZHJ5LXJ1bjoKICAgIGRlc2NyaXB0aW9uOiAiTWFrZSBzdXJlIGl0IHdpbGwgd29yayBiZWZvcmUgeW91IHJ1biBpdCIKICAgIHN0YXRlbGVzczogdHJ1ZQogICAgbW9kaWZpZXM6IGZhbHNlCiAgc3RhdHVzOgogICAgZGVzY3JpcHRpb246ICJQcmludCB0aGUgaW5zdGFsbGF0aW9uIHN0YXR1cyIKICAgIHN0YXRlbGVzczogZmFsc2UKICAgIG1vZGlmaWVzOiBmYWxzZQoKaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgdGhlIGRvY2tlciBzb2NrZXQiCiAgICAgIGNvbW1hbmQ6IHN0YXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gL3Zhci9ydW4vZG9ja2VyLnNvY2sKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiTGV0J3MgbWFrZSBzb21lIG1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFrZU1hZ2ljCiAgICAgICAgLSAiJHsgYnVuZGxlLmNyZWRlbnRpYWxzLnVzZXJuYW1lIH0gaXMgYSB1bmljb3JuIHdpdGggJHsgYnVuZGxlLnBhcmFtZXRlcnMucGFzc3dvcmQgfSBzZWNyZXQuIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJpbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gaW5zdGFsbAogICAgICBvdXRwdXRzOgogICAgICAgIC0gbmFtZTogbXlsb2dzCiAgICAgICAgICByZWdleDogIiguKikiCiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogInJvbGwgdGhlIGRpY2Ugd2l0aCB5b3VyIGNoYW9zIG1vbmtleSIKICAgICAgY29tbWFuZDogLi9oZWxwZXJzLnNoCiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtIGNoYW9zX21vbmtleQogICAgICAgIC0gJHsgYnVuZGxlLnBhcmFtZXRlcnMuY2hhb3NfbW9ua2V5IH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IHJlc3VsdAogICAgICAgICAgcmVnZXg6ICIoLiopIgoKZHJ5LXJ1bjoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgc29tZSB0aGluZ3MiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIkFsbCBjbGVhciEiCgpzdGF0dXM6CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IGNvbmZpZyIKICAgICAgY29tbWFuZDogY2F0CiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNmZyB9CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IG1hZ2ljIgogICAgICBjb21tYW5kOiBjYXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFnaWMudHh0Cgpib29tOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJtb2RpZnkgdGhlIGJ1bmRsZSBpbiB1bmtub3dhYmxlIHdheXMiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIllPTE8iCgp1cGdyYWRlOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJFbnN1cmUgbWFnaWMiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBlbnN1cmVNYWdpYwogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJ1cGdyYWRlIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdXBncmFkZQogICAgICAgIC0gJHsgYnVuZGxlLm91dHB1dHMubXNnIH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IG15bG9ncwogICAgICAgICAgcmVnZXg6ICIoLiopIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9CiAgICAgIG91dHB1dHM6CiAgICAgICAgLSBuYW1lOiByZXN1bHQKICAgICAgICAgIHJlZ2V4OiAiKC4qKSIKCnVuaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiRW5zdXJlIE1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gZW5zdXJlTWFnaWMKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAidW5pbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdW5pbnN0YWxsCiAgICAgICAgLSAkeyBidW5kbGUub3V0cHV0cy5tc2cgfQogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9Cg==", "version": "", - "commit": "" + "commit": "", + "preserveTags": false }, "sh.porter.file-parameters": {} } diff --git a/pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.preserveTags.json b/pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.preserveTags.json new file mode 100644 index 000000000..140133030 --- /dev/null +++ b/pkg/cnab/config-adapter/testdata/mybuns-depsv1.bundle.preserveTags.json @@ -0,0 +1,475 @@ +{ + "schemaVersion": "1.2.0", + "name": "mybuns", + "version": "0.1.2", + "description": "A very thorough test bundle", + "maintainers": [ + { + "name": "John Doe", + "email": "john.doe@example.com", + "url": "https://example.com/a" + }, + { + "name": "Jane Doe", + "url": "https://example.com/b" + }, + { + "name": "Janine Doe", + "email": "janine.doe@example.com" + }, + { + "name": "", + "email": "mike.doe@example.com", + "url": "https://example.com/c" + } + ], + "invocationImages": [ + { + "imageType": "docker", + "image": "localhost:5000/mybuns:porter-332dd75c541511a27fc332bdcd049d5b" + } + ], + "images": { + "whalesayd": { + "imageType": "docker", + "image": "carolynvs/whalesayd:latest", + "description": "Whalesay as a service" + } + }, + "actions": { + "boom": { + "modifies": true, + "description": "boom" + }, + "dry-run": { + "stateless": true, + "description": "Make sure it will work before you run it" + }, + "status": { + "description": "Print the installation status" + } + }, + "parameters": { + "aboolean": { + "definition": "aboolean-parameter", + "destination": { + "env": "ABOOLEAN" + } + }, + "afile": { + "definition": "afile-parameter", + "destination": { + "path": "/home/nonroot/.kube/config" + } + }, + "ainteger": { + "definition": "ainteger-parameter", + "destination": { + "env": "AINTEGER" + } + }, + "anumber": { + "definition": "anumber-parameter", + "destination": { + "env": "ANUMBER" + } + }, + "astring": { + "definition": "astring-parameter", + "destination": { + "env": "ASTRING" + } + }, + "astringenum": { + "definition": "astringenum-parameter", + "destination": { + "env": "ASTRINGENUM" + } + }, + "cfg": { + "definition": "cfg-parameter", + "description": "A json config file", + "destination": { + "path": "/cnab/app/buncfg.json" + } + }, + "chaos_monkey": { + "definition": "chaos_monkey-parameter", + "description": "Set to true to make the bundle fail", + "destination": { + "env": "CHAOS_MONKEY" + } + }, + "installonly": { + "definition": "installonly-parameter", + "applyTo": [ + "install" + ], + "destination": { + "env": "INSTALLONLY" + } + }, + "jsonobject": { + "definition": "jsonobject-parameter", + "destination": { + "env": "JSONOBJECT" + } + }, + "log_level": { + "definition": "log_level-parameter", + "description": "How unhelpful would you like the logs to be?", + "destination": { + "env": "LOG_LEVEL" + } + }, + "mysql-connstr": { + "definition": "mysql-connstr-parameter", + "destination": { + "env": "MYSQL_CONNSTR" + } + }, + "notype-file": { + "definition": "notype-file-parameter", + "destination": { + "path": "/cnab/app/config.toml" + } + }, + "notype-string": { + "definition": "notype-string-parameter", + "destination": { + "env": "NOTYPE_STRING" + } + }, + "password": { + "definition": "password-parameter", + "description": "The super secret data", + "destination": { + "env": "PASSWORD" + } + }, + "porter-debug": { + "definition": "porter-debug-parameter", + "description": "Print debug information from Porter when executing the bundle", + "destination": { + "env": "PORTER_DEBUG" + } + }, + "porter-msg-output": { + "definition": "porter-msg-output", + "description": "Wires up the msg output for use as a parameter. Porter internal parameter that should not be set manually.", + "destination": { + "env": "PORTER_MSG_OUTPUT" + } + }, + "porter-state": { + "definition": "porter-state", + "description": "Supports persisting state for bundles. Porter internal parameter that should not be set manually.", + "destination": { + "path": "/porter/state.tgz" + } + }, + "sensitive": { + "definition": "sensitive-parameter", + "destination": { + "env": "SENSITIVE" + } + }, + "tfstate": { + "definition": "tfstate-parameter", + "applyTo": [ + "upgrade", + "uninstall" + ], + "destination": { + "path": "/cnab/app/tfstate" + }, + "required": true + } + }, + "credentials": { + "password": { + "path": "/tmp/password", + "required": true, + "applyTo": [ + "boom" + ] + }, + "username": { + "env": "ROOT_USERNAME", + "description": "The name you want on the audit log" + } + }, + "outputs": { + "connStr": { + "definition": "connStr-output", + "applyTo": [ + "install" + ], + "path": "/cnab/app/outputs/connStr" + }, + "msg": { + "definition": "msg-output", + "applyTo": [ + "install", + "upgrade", + "uninstall" + ], + "path": "/cnab/app/outputs/msg" + }, + "mylogs": { + "definition": "mylogs-output", + "applyTo": [ + "install", + "upgrade" + ], + "path": "/cnab/app/outputs/mylogs" + }, + "porter-state": { + "definition": "porter-state", + "description": "Supports persisting state for bundles. Porter internal parameter that should not be set manually.", + "path": "/cnab/app/outputs/porter-state" + }, + "result": { + "definition": "result-output", + "applyTo": [ + "install", + "upgrade" + ], + "path": "/cnab/app/outputs/result" + }, + "tfstate": { + "definition": "tfstate-output", + "applyTo": [ + "install", + "upgrade", + "uninstall" + ], + "path": "/cnab/app/outputs/tfstate" + } + }, + "definitions": { + "aboolean-parameter": { + "default": true, + "type": "boolean" + }, + "afile-parameter": { + "contentEncoding": "base64", + "default": "", + "type": "string" + }, + "ainteger-parameter": { + "default": 1, + "maximum": 10, + "minimum": 0, + "type": "integer" + }, + "anumber-parameter": { + "default": 0.5, + "exclusiveMaximum": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + "astring-parameter": { + "default": "boop!", + "maxLength": 10, + "minLength": 1, + "type": "string" + }, + "astringenum-parameter": { + "default": "blue", + "enum": [ + "blue", + "red", + "purple", + "pink" + ], + "type": "string" + }, + "cfg-parameter": { + "contentEncoding": "base64", + "default": "", + "description": "A json config file", + "type": "string" + }, + "chaos_monkey-parameter": { + "default": false, + "description": "Set to true to make the bundle fail", + "type": "boolean" + }, + "connStr-output": { + "$id": "porter.sh/interfaces/mysql.connection-string", + "default": "", + "type": "string" + }, + "installonly-parameter": { + "default": false, + "type": "boolean" + }, + "jsonobject-parameter": { + "default": "\"myobject\": { \"foo\": \"true\", \"bar\": [ 1, 2, 3 ] }", + "type": "string" + }, + "log_level-parameter": { + "default": 5, + "description": "How unhelpful would you like the logs to be?", + "maximum": 11, + "minimum": 1, + "type": "integer" + }, + "msg-output": { + "default": "", + "type": "string" + }, + "mylogs-output": { + "type": "string" + }, + "mysql-connstr-parameter": { + "default": "", + "type": "string" + }, + "notype-file-parameter": { + "contentEncoding": "base64", + "default": "", + "type": "string" + }, + "notype-string-parameter": { + "default": "", + "type": "string" + }, + "password-parameter": { + "default": "default-secret", + "description": "The super secret data", + "type": "string", + "writeOnly": true + }, + "porter-debug-parameter": { + "$comment": "porter-internal", + "$id": "https://porter.sh/generated-bundle/#porter-debug", + "default": false, + "description": "Print debug information from Porter when executing the bundle", + "type": "boolean" + }, + "porter-msg-output": { + "$comment": "porter-internal", + "$id": "https://porter.sh/generated-bundle/#porter-parameter-source-definition", + "default": "", + "type": "string" + }, + "porter-state": { + "$comment": "porter-internal", + "$id": "https://porter.sh/generated-bundle/#porter-state", + "contentEncoding": "base64", + "description": "Supports persisting state for bundles. Porter internal parameter that should not be set manually.", + "type": "string" + }, + "result-output": { + "type": "string", + "writeOnly": true + }, + "sensitive-parameter": { + "default": "passw0rd123", + "type": "string", + "writeOnly": true + }, + "tfstate-output": { + "contentEncoding": "base64", + "type": "string" + }, + "tfstate-parameter": { + "contentEncoding": "base64", + "type": "string" + } + }, + "requiredExtensions": [ + "sh.porter.file-parameters", + "io.cnab.dependencies", + "io.cnab.parameter-sources", + "io.cnab.docker" + ], + "custom": { + "app": { + "version": "1.2.3" + }, + "foo": { + "test1": true, + "test2": 1, + "test3": "value", + "test4": [ + "one", + "two", + "three" + ], + "test5": { + "1": "one", + "two": "two" + } + }, + "io.cnab.dependencies": { + "sequence": [ + "db" + ], + "requires": { + "db": { + "bundle": "localhost:5000/mydb:v0.1.0" + } + } + }, + "io.cnab.docker": null, + "io.cnab.parameter-sources": { + "mysql-connstr": { + "priority": [ + "dependencies.output" + ], + "sources": { + "dependencies.output": { + "dependency": "db", + "name": "connstr" + } + } + }, + "porter-msg-output": { + "priority": [ + "output" + ], + "sources": { + "output": { + "name": "msg" + } + } + }, + "porter-state": { + "priority": [ + "output" + ], + "sources": { + "output": { + "name": "porter-state" + } + } + }, + "tfstate": { + "priority": [ + "output" + ], + "sources": { + "output": { + "name": "tfstate" + } + } + } + }, + "sh.porter": { + "manifestDigest": "", + "mixins": { + "exec": { + "version": "v1.2.3" + } + }, + "manifest": "IyBUaGlzIGlzIGEgdGVzdCBidW5kbGUgdGhhdCBtYWtlcyBubyBsb2dpY2FsIHNlbnNlLCBidXQgaXQgZG9lcyBleGVyY2lzZSBsb3RzIG9mIGRpZmZlcmVudCBidW5kbGUgZmVhdHVyZXMKc2NoZW1hVHlwZTogQnVuZGxlCnNjaGVtYVZlcnNpb246IDEuMC4xCm5hbWU6IG15YnVucwp2ZXJzaW9uOiAwLjEuMgpkZXNjcmlwdGlvbjogIkEgdmVyeSB0aG9yb3VnaCB0ZXN0IGJ1bmRsZSIKcmVnaXN0cnk6IGxvY2FsaG9zdDo1MDAwCmRvY2tlcmZpbGU6IERvY2tlcmZpbGUudG1wbAoKbWFpbnRhaW5lcnM6Ci0gbmFtZTogIkpvaG4gRG9lIgogIGVtYWlsOiAiam9obi5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9hIgotIG5hbWU6ICJKYW5lIERvZSIKICB1cmw6ICJodHRwczovL2V4YW1wbGUuY29tL2IiCi0gbmFtZTogIkphbmluZSBEb2UiCiAgZW1haWw6ICJqYW5pbmUuZG9lQGV4YW1wbGUuY29tIgotIGVtYWlsOiAibWlrZS5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9jIgoKY3VzdG9tOgogIGFwcDoKICAgIHZlcnNpb246IDEuMi4zCiAgZm9vOgogICAgdGVzdDE6IHRydWUKICAgIHRlc3QyOiAxCiAgICB0ZXN0MzogdmFsdWUKICAgIHRlc3Q0OgogICAgICAtIG9uZQogICAgICAtIHR3bwogICAgICAtIHRocmVlCiAgICB0ZXN0NToKICAgICAgMTogb25lCiAgICAgIHR3bzogdHdvCgpyZXF1aXJlZDoKICAtIGRvY2tlcgoKY3JlZGVudGlhbHM6CiAgLSBuYW1lOiB1c2VybmFtZQogICAgZGVzY3JpcHRpb246ICJUaGUgbmFtZSB5b3Ugd2FudCBvbiB0aGUgYXVkaXQgbG9nIgogICAgZW52OiBST09UX1VTRVJOQU1FCiAgICByZXF1aXJlZDogZmFsc2UKICAtIG5hbWU6IHBhc3N3b3JkCiAgICBwYXRoOiAvdG1wL3Bhc3N3b3JkCiAgICBhcHBseVRvOgogICAgICAtIGJvb20KCnBhcmFtZXRlcnM6CiAgLSBuYW1lOiBsb2dfbGV2ZWwKICAgIGRlc2NyaXB0aW9uOiAiSG93IHVuaGVscGZ1bCB3b3VsZCB5b3UgbGlrZSB0aGUgbG9ncyB0byBiZT8iCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBtaW5pbXVtOiAxCiAgICBtYXhpbXVtOiAxMQogICAgZGVmYXVsdDogNQogIC0gbmFtZTogcGFzc3dvcmQKICAgIGRlc2NyaXB0aW9uOiAiVGhlIHN1cGVyIHNlY3JldCBkYXRhIgogICAgdHlwZTogc3RyaW5nCiAgICBkZWZhdWx0OiAiZGVmYXVsdC1zZWNyZXQiCiAgICBzZW5zaXRpdmU6IHRydWUKICAtIG5hbWU6IG15c3FsLWNvbm5zdHIKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIgIyBTZXR0aW5nIGEgZGVmYXVsdCBzbyB0aGF0IHRoaXMgaXNuJ3QgcmVxdWlyZWQgZm9yIGluc3RhbGwKICAgIHNvdXJjZToKICAgICAgZGVwZW5kZW5jeTogZGIKICAgICAgb3V0cHV0OiBjb25uc3RyCiAgLSBuYW1lOiBjaGFvc19tb25rZXkKICAgIGRlc2NyaXB0aW9uOiAiU2V0IHRvIHRydWUgdG8gbWFrZSB0aGUgYnVuZGxlIGZhaWwiCiAgICB0eXBlOiBib29sZWFuCiAgICBkZWZhdWx0OiBmYWxzZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIHNvdXJjZToKICAgICAgb3V0cHV0OiB0ZnN0YXRlCiAgICBhcHBseVRvOgogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNmZwogICAgZGVzY3JpcHRpb246ICJBIGpzb24gY29uZmlnIGZpbGUiCiAgICB0eXBlOiBmaWxlCiAgICBkZWZhdWx0OiAnJwogICAgcGF0aDogYnVuY2ZnLmpzb24KICAtIG5hbWU6IGFpbnRlZ2VyCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBkZWZhdWx0OiAxCiAgICBtaW5pbXVtOiAwCiAgICBtYXhpbXVtOiAxMAogIC0gbmFtZTogYW51bWJlcgogICAgdHlwZTogbnVtYmVyCiAgICBkZWZhdWx0OiAwLjUgIyBUaGlzIGlzIGEgcmVncmVzc2lvbiB0ZXN0IHRoYXQgd2UgY2FuIGJvdGggYnVpbGQgYW5kIHB1c2ggYSBidW5kbGUgdGhhdCB1c2VzIG51bWVyaWMgdHlwZXMKICAgIGV4Y2x1c2l2ZU1pbmltdW06IDAKICAgIGV4Y2x1c2l2ZU1heGltdW06IDEKICAtIG5hbWU6IGFzdHJpbmdlbnVtCiAgICB0eXBlOiBzdHJpbmcKICAgIGRlZmF1bHQ6IGJsdWUKICAgIGVudW06CiAgICAgIC0gYmx1ZQogICAgICAtIHJlZAogICAgICAtIHB1cnBsZQogICAgICAtIHBpbmsKICAtIG5hbWU6IGFzdHJpbmcKICAgIHR5cGU6IHN0cmluZwogICAgbWluTGVuZ3RoOiAxCiAgICBtYXhMZW5ndGg6IDEwCiAgICBkZWZhdWx0OiAnYm9vcCEnCiAgLSBuYW1lOiBhYm9vbGVhbgogICAgdHlwZTogYm9vbGVhbgogICAgZGVmYXVsdDogdHJ1ZQogIC0gbmFtZTogaW5zdGFsbG9ubHkKICAgIHR5cGU6IGJvb2xlYW4KICAgIGRlZmF1bHQ6IGZhbHNlCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAtIG5hbWU6IHNlbnNpdGl2ZQogICAgdHlwZTogc3RyaW5nCiAgICBzZW5zaXRpdmU6IHRydWUKICAgIGRlZmF1bHQ6ICJwYXNzdzByZDEyMyIKICAtIG5hbWU6IGpzb25vYmplY3QKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogJyJteW9iamVjdCI6IHsKICAgICAgICAiZm9vIjogInRydWUiLAogICAgICAgICJiYXIiOiBbCiAgICAgICAgICAxLAogICAgICAgICAgMiwKICAgICAgICAgIDMKICAgICAgICBdCiAgICAgIH0nCiAgLSBuYW1lOiBhZmlsZQogICAgdHlwZTogZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9ob21lL25vbnJvb3QvLmt1YmUvY29uZmlnCiAgLSBuYW1lOiBub3R5cGUtZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9jbmFiL2FwcC9jb25maWcudG9tbAogIC0gbmFtZTogbm90eXBlLXN0cmluZwogICAgZGVmYXVsdDogJycKCm91dHB1dHM6CiAgLSBuYW1lOiBtc2cKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNvbm5TdHIKICAgICRpZDogInBvcnRlci5zaC9pbnRlcmZhY2VzL215c3FsLmNvbm5lY3Rpb24tc3RyaW5nIgogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogIC0gbmFtZTogbXlsb2dzCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAgICAgLSB1cGdyYWRlCiAgLSBuYW1lOiByZXN1bHQKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgIHNlbnNpdGl2ZTogdHJ1ZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKCnN0YXRlOgogIC0gbmFtZTogbWFnaWNfZmlsZQogICAgcGF0aDogbWFnaWMudHh0CgpkZXBlbmRlbmNpZXM6CiAgcmVxdWlyZXM6CiAgICAtIG5hbWU6IGRiCiAgICAgIGJ1bmRsZToKICAgICAgICByZWZlcmVuY2U6ICJsb2NhbGhvc3Q6NTAwMC9teWRiOnYwLjEuMCIKICAgICAgcGFyYW1ldGVyczoKICAgICAgICBkYXRhYmFzZTogYmlnZGIKCmltYWdlczoKICB3aGFsZXNheWQ6CiAgICBkZXNjcmlwdGlvbjogIldoYWxlc2F5IGFzIGEgc2VydmljZSIKICAgIGltYWdlVHlwZTogImRvY2tlciIKICAgIHJlcG9zaXRvcnk6IGNhcm9seW52cy93aGFsZXNheWQKICAgIHRhZzogImxhdGVzdCIKCm1peGluczoKICAtIGV4ZWMKICAtIHRlc3RtaXhpbjoKICAgICAgY2xpZW50VmVyc2lvbjogMS4yLjMKCmN1c3RvbUFjdGlvbnM6CiAgZHJ5LXJ1bjoKICAgIGRlc2NyaXB0aW9uOiAiTWFrZSBzdXJlIGl0IHdpbGwgd29yayBiZWZvcmUgeW91IHJ1biBpdCIKICAgIHN0YXRlbGVzczogdHJ1ZQogICAgbW9kaWZpZXM6IGZhbHNlCiAgc3RhdHVzOgogICAgZGVzY3JpcHRpb246ICJQcmludCB0aGUgaW5zdGFsbGF0aW9uIHN0YXR1cyIKICAgIHN0YXRlbGVzczogZmFsc2UKICAgIG1vZGlmaWVzOiBmYWxzZQoKaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgdGhlIGRvY2tlciBzb2NrZXQiCiAgICAgIGNvbW1hbmQ6IHN0YXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gL3Zhci9ydW4vZG9ja2VyLnNvY2sKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiTGV0J3MgbWFrZSBzb21lIG1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFrZU1hZ2ljCiAgICAgICAgLSAiJHsgYnVuZGxlLmNyZWRlbnRpYWxzLnVzZXJuYW1lIH0gaXMgYSB1bmljb3JuIHdpdGggJHsgYnVuZGxlLnBhcmFtZXRlcnMucGFzc3dvcmQgfSBzZWNyZXQuIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJpbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gaW5zdGFsbAogICAgICBvdXRwdXRzOgogICAgICAgIC0gbmFtZTogbXlsb2dzCiAgICAgICAgICByZWdleDogIiguKikiCiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogInJvbGwgdGhlIGRpY2Ugd2l0aCB5b3VyIGNoYW9zIG1vbmtleSIKICAgICAgY29tbWFuZDogLi9oZWxwZXJzLnNoCiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtIGNoYW9zX21vbmtleQogICAgICAgIC0gJHsgYnVuZGxlLnBhcmFtZXRlcnMuY2hhb3NfbW9ua2V5IH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IHJlc3VsdAogICAgICAgICAgcmVnZXg6ICIoLiopIgoKZHJ5LXJ1bjoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgc29tZSB0aGluZ3MiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIkFsbCBjbGVhciEiCgpzdGF0dXM6CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IGNvbmZpZyIKICAgICAgY29tbWFuZDogY2F0CiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNmZyB9CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IG1hZ2ljIgogICAgICBjb21tYW5kOiBjYXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFnaWMudHh0Cgpib29tOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJtb2RpZnkgdGhlIGJ1bmRsZSBpbiB1bmtub3dhYmxlIHdheXMiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIllPTE8iCgp1cGdyYWRlOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJFbnN1cmUgbWFnaWMiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBlbnN1cmVNYWdpYwogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJ1cGdyYWRlIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdXBncmFkZQogICAgICAgIC0gJHsgYnVuZGxlLm91dHB1dHMubXNnIH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IG15bG9ncwogICAgICAgICAgcmVnZXg6ICIoLiopIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9CiAgICAgIG91dHB1dHM6CiAgICAgICAgLSBuYW1lOiByZXN1bHQKICAgICAgICAgIHJlZ2V4OiAiKC4qKSIKCnVuaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiRW5zdXJlIE1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gZW5zdXJlTWFnaWMKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAidW5pbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdW5pbnN0YWxsCiAgICAgICAgLSAkeyBidW5kbGUub3V0cHV0cy5tc2cgfQogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9Cg==", + "version": "", + "commit": "", + "preserveTags": true + }, + "sh.porter.file-parameters": {} + } +} \ No newline at end of file diff --git a/pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.json b/pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.json index a0b26a604..974e5c598 100644 --- a/pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.json +++ b/pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.json @@ -470,7 +470,8 @@ }, "manifest": "IyBUaGlzIGlzIGEgdGVzdCBidW5kbGUgdGhhdCBtYWtlcyBubyBsb2dpY2FsIHNlbnNlLCBidXQgaXQgZG9lcyBleGVyY2lzZSBsb3RzIG9mIGRpZmZlcmVudCBidW5kbGUgZmVhdHVyZXMKc2NoZW1hVHlwZTogQnVuZGxlCnNjaGVtYVZlcnNpb246IDEuMC4xCm5hbWU6IG15YnVucwp2ZXJzaW9uOiAwLjEuMgpkZXNjcmlwdGlvbjogIkEgdmVyeSB0aG9yb3VnaCB0ZXN0IGJ1bmRsZSIKcmVnaXN0cnk6IGxvY2FsaG9zdDo1MDAwCmRvY2tlcmZpbGU6IERvY2tlcmZpbGUudG1wbAoKbWFpbnRhaW5lcnM6Ci0gbmFtZTogIkpvaG4gRG9lIgogIGVtYWlsOiAiam9obi5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9hIgotIG5hbWU6ICJKYW5lIERvZSIKICB1cmw6ICJodHRwczovL2V4YW1wbGUuY29tL2IiCi0gbmFtZTogIkphbmluZSBEb2UiCiAgZW1haWw6ICJqYW5pbmUuZG9lQGV4YW1wbGUuY29tIgotIGVtYWlsOiAibWlrZS5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9jIgoKY3VzdG9tOgogIGFwcDoKICAgIHZlcnNpb246IDEuMi4zCiAgZm9vOgogICAgdGVzdDE6IHRydWUKICAgIHRlc3QyOiAxCiAgICB0ZXN0MzogdmFsdWUKICAgIHRlc3Q0OgogICAgICAtIG9uZQogICAgICAtIHR3bwogICAgICAtIHRocmVlCiAgICB0ZXN0NToKICAgICAgMTogb25lCiAgICAgIHR3bzogdHdvCgpyZXF1aXJlZDoKICAtIGRvY2tlcgoKY3JlZGVudGlhbHM6CiAgLSBuYW1lOiB1c2VybmFtZQogICAgZGVzY3JpcHRpb246ICJUaGUgbmFtZSB5b3Ugd2FudCBvbiB0aGUgYXVkaXQgbG9nIgogICAgZW52OiBST09UX1VTRVJOQU1FCiAgICByZXF1aXJlZDogZmFsc2UKICAtIG5hbWU6IHBhc3N3b3JkCiAgICBwYXRoOiAvdG1wL3Bhc3N3b3JkCiAgICBhcHBseVRvOgogICAgICAtIGJvb20KCnBhcmFtZXRlcnM6CiAgLSBuYW1lOiBsb2dfbGV2ZWwKICAgIGRlc2NyaXB0aW9uOiAiSG93IHVuaGVscGZ1bCB3b3VsZCB5b3UgbGlrZSB0aGUgbG9ncyB0byBiZT8iCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBtaW5pbXVtOiAxCiAgICBtYXhpbXVtOiAxMQogICAgZGVmYXVsdDogNQogIC0gbmFtZTogcGFzc3dvcmQKICAgIGRlc2NyaXB0aW9uOiAiVGhlIHN1cGVyIHNlY3JldCBkYXRhIgogICAgdHlwZTogc3RyaW5nCiAgICBkZWZhdWx0OiAiZGVmYXVsdC1zZWNyZXQiCiAgICBzZW5zaXRpdmU6IHRydWUKICAtIG5hbWU6IG15c3FsLWNvbm5zdHIKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIgIyBTZXR0aW5nIGEgZGVmYXVsdCBzbyB0aGF0IHRoaXMgaXNuJ3QgcmVxdWlyZWQgZm9yIGluc3RhbGwKICAgIHNvdXJjZToKICAgICAgZGVwZW5kZW5jeTogZGIKICAgICAgb3V0cHV0OiBjb25uc3RyCiAgLSBuYW1lOiBjaGFvc19tb25rZXkKICAgIGRlc2NyaXB0aW9uOiAiU2V0IHRvIHRydWUgdG8gbWFrZSB0aGUgYnVuZGxlIGZhaWwiCiAgICB0eXBlOiBib29sZWFuCiAgICBkZWZhdWx0OiBmYWxzZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIHNvdXJjZToKICAgICAgb3V0cHV0OiB0ZnN0YXRlCiAgICBhcHBseVRvOgogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNmZwogICAgZGVzY3JpcHRpb246ICJBIGpzb24gY29uZmlnIGZpbGUiCiAgICB0eXBlOiBmaWxlCiAgICBkZWZhdWx0OiAnJwogICAgcGF0aDogYnVuY2ZnLmpzb24KICAtIG5hbWU6IGFpbnRlZ2VyCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBkZWZhdWx0OiAxCiAgICBtaW5pbXVtOiAwCiAgICBtYXhpbXVtOiAxMAogIC0gbmFtZTogYW51bWJlcgogICAgdHlwZTogbnVtYmVyCiAgICBkZWZhdWx0OiAwLjUgIyBUaGlzIGlzIGEgcmVncmVzc2lvbiB0ZXN0IHRoYXQgd2UgY2FuIGJvdGggYnVpbGQgYW5kIHB1c2ggYSBidW5kbGUgdGhhdCB1c2VzIG51bWVyaWMgdHlwZXMKICAgIGV4Y2x1c2l2ZU1pbmltdW06IDAKICAgIGV4Y2x1c2l2ZU1heGltdW06IDEKICAtIG5hbWU6IGFzdHJpbmdlbnVtCiAgICB0eXBlOiBzdHJpbmcKICAgIGRlZmF1bHQ6IGJsdWUKICAgIGVudW06CiAgICAgIC0gYmx1ZQogICAgICAtIHJlZAogICAgICAtIHB1cnBsZQogICAgICAtIHBpbmsKICAtIG5hbWU6IGFzdHJpbmcKICAgIHR5cGU6IHN0cmluZwogICAgbWluTGVuZ3RoOiAxCiAgICBtYXhMZW5ndGg6IDEwCiAgICBkZWZhdWx0OiAnYm9vcCEnCiAgLSBuYW1lOiBhYm9vbGVhbgogICAgdHlwZTogYm9vbGVhbgogICAgZGVmYXVsdDogdHJ1ZQogIC0gbmFtZTogaW5zdGFsbG9ubHkKICAgIHR5cGU6IGJvb2xlYW4KICAgIGRlZmF1bHQ6IGZhbHNlCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAtIG5hbWU6IHNlbnNpdGl2ZQogICAgdHlwZTogc3RyaW5nCiAgICBzZW5zaXRpdmU6IHRydWUKICAgIGRlZmF1bHQ6ICJwYXNzdzByZDEyMyIKICAtIG5hbWU6IGpzb25vYmplY3QKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogJyJteW9iamVjdCI6IHsKICAgICAgICAiZm9vIjogInRydWUiLAogICAgICAgICJiYXIiOiBbCiAgICAgICAgICAxLAogICAgICAgICAgMiwKICAgICAgICAgIDMKICAgICAgICBdCiAgICAgIH0nCiAgLSBuYW1lOiBhZmlsZQogICAgdHlwZTogZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9ob21lL25vbnJvb3QvLmt1YmUvY29uZmlnCiAgLSBuYW1lOiBub3R5cGUtZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9jbmFiL2FwcC9jb25maWcudG9tbAogIC0gbmFtZTogbm90eXBlLXN0cmluZwogICAgZGVmYXVsdDogJycKCm91dHB1dHM6CiAgLSBuYW1lOiBtc2cKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNvbm5TdHIKICAgICRpZDogInBvcnRlci5zaC9pbnRlcmZhY2VzL215c3FsLmNvbm5lY3Rpb24tc3RyaW5nIgogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogIC0gbmFtZTogbXlsb2dzCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAgICAgLSB1cGdyYWRlCiAgLSBuYW1lOiByZXN1bHQKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgIHNlbnNpdGl2ZTogdHJ1ZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKCnN0YXRlOgogIC0gbmFtZTogbWFnaWNfZmlsZQogICAgcGF0aDogbWFnaWMudHh0CgpkZXBlbmRlbmNpZXM6CiAgcmVxdWlyZXM6CiAgICAtIG5hbWU6IGRiCiAgICAgIGJ1bmRsZToKICAgICAgICByZWZlcmVuY2U6ICJsb2NhbGhvc3Q6NTAwMC9teWRiOnYwLjEuMCIKICAgICAgcGFyYW1ldGVyczoKICAgICAgICBkYXRhYmFzZTogYmlnZGIKCmltYWdlczoKICB3aGFsZXNheWQ6CiAgICBkZXNjcmlwdGlvbjogIldoYWxlc2F5IGFzIGEgc2VydmljZSIKICAgIGltYWdlVHlwZTogImRvY2tlciIKICAgIHJlcG9zaXRvcnk6IGNhcm9seW52cy93aGFsZXNheWQKICAgIHRhZzogImxhdGVzdCIKCm1peGluczoKICAtIGV4ZWMKICAtIHRlc3RtaXhpbjoKICAgICAgY2xpZW50VmVyc2lvbjogMS4yLjMKCmN1c3RvbUFjdGlvbnM6CiAgZHJ5LXJ1bjoKICAgIGRlc2NyaXB0aW9uOiAiTWFrZSBzdXJlIGl0IHdpbGwgd29yayBiZWZvcmUgeW91IHJ1biBpdCIKICAgIHN0YXRlbGVzczogdHJ1ZQogICAgbW9kaWZpZXM6IGZhbHNlCiAgc3RhdHVzOgogICAgZGVzY3JpcHRpb246ICJQcmludCB0aGUgaW5zdGFsbGF0aW9uIHN0YXR1cyIKICAgIHN0YXRlbGVzczogZmFsc2UKICAgIG1vZGlmaWVzOiBmYWxzZQoKaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgdGhlIGRvY2tlciBzb2NrZXQiCiAgICAgIGNvbW1hbmQ6IHN0YXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gL3Zhci9ydW4vZG9ja2VyLnNvY2sKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiTGV0J3MgbWFrZSBzb21lIG1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFrZU1hZ2ljCiAgICAgICAgLSAiJHsgYnVuZGxlLmNyZWRlbnRpYWxzLnVzZXJuYW1lIH0gaXMgYSB1bmljb3JuIHdpdGggJHsgYnVuZGxlLnBhcmFtZXRlcnMucGFzc3dvcmQgfSBzZWNyZXQuIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJpbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gaW5zdGFsbAogICAgICBvdXRwdXRzOgogICAgICAgIC0gbmFtZTogbXlsb2dzCiAgICAgICAgICByZWdleDogIiguKikiCiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogInJvbGwgdGhlIGRpY2Ugd2l0aCB5b3VyIGNoYW9zIG1vbmtleSIKICAgICAgY29tbWFuZDogLi9oZWxwZXJzLnNoCiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtIGNoYW9zX21vbmtleQogICAgICAgIC0gJHsgYnVuZGxlLnBhcmFtZXRlcnMuY2hhb3NfbW9ua2V5IH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IHJlc3VsdAogICAgICAgICAgcmVnZXg6ICIoLiopIgoKZHJ5LXJ1bjoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgc29tZSB0aGluZ3MiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIkFsbCBjbGVhciEiCgpzdGF0dXM6CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IGNvbmZpZyIKICAgICAgY29tbWFuZDogY2F0CiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNmZyB9CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IG1hZ2ljIgogICAgICBjb21tYW5kOiBjYXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFnaWMudHh0Cgpib29tOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJtb2RpZnkgdGhlIGJ1bmRsZSBpbiB1bmtub3dhYmxlIHdheXMiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIllPTE8iCgp1cGdyYWRlOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJFbnN1cmUgbWFnaWMiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBlbnN1cmVNYWdpYwogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJ1cGdyYWRlIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdXBncmFkZQogICAgICAgIC0gJHsgYnVuZGxlLm91dHB1dHMubXNnIH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IG15bG9ncwogICAgICAgICAgcmVnZXg6ICIoLiopIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9CiAgICAgIG91dHB1dHM6CiAgICAgICAgLSBuYW1lOiByZXN1bHQKICAgICAgICAgIHJlZ2V4OiAiKC4qKSIKCnVuaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiRW5zdXJlIE1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gZW5zdXJlTWFnaWMKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAidW5pbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdW5pbnN0YWxsCiAgICAgICAgLSAkeyBidW5kbGUub3V0cHV0cy5tc2cgfQogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9Cg==", "version": "", - "commit": "" + "commit": "", + "preserveTags": false }, "sh.porter.file-parameters": {} } diff --git a/pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.preserveTags.json b/pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.preserveTags.json new file mode 100644 index 000000000..a9bd7f5e0 --- /dev/null +++ b/pkg/cnab/config-adapter/testdata/mybuns-depsv2.bundle.preserveTags.json @@ -0,0 +1,478 @@ +{ + "schemaVersion": "1.2.0", + "name": "mybuns", + "version": "0.1.2", + "description": "A very thorough test bundle", + "maintainers": [ + { + "name": "John Doe", + "email": "john.doe@example.com", + "url": "https://example.com/a" + }, + { + "name": "Jane Doe", + "url": "https://example.com/b" + }, + { + "name": "Janine Doe", + "email": "janine.doe@example.com" + }, + { + "name": "", + "email": "mike.doe@example.com", + "url": "https://example.com/c" + } + ], + "invocationImages": [ + { + "imageType": "docker", + "image": "localhost:5000/mybuns:porter-332dd75c541511a27fc332bdcd049d5b" + } + ], + "images": { + "whalesayd": { + "imageType": "docker", + "image": "carolynvs/whalesayd:latest", + "description": "Whalesay as a service" + } + }, + "actions": { + "boom": { + "modifies": true, + "description": "boom" + }, + "dry-run": { + "stateless": true, + "description": "Make sure it will work before you run it" + }, + "status": { + "description": "Print the installation status" + } + }, + "parameters": { + "aboolean": { + "definition": "aboolean-parameter", + "destination": { + "env": "ABOOLEAN" + } + }, + "afile": { + "definition": "afile-parameter", + "destination": { + "path": "/home/nonroot/.kube/config" + } + }, + "ainteger": { + "definition": "ainteger-parameter", + "destination": { + "env": "AINTEGER" + } + }, + "anumber": { + "definition": "anumber-parameter", + "destination": { + "env": "ANUMBER" + } + }, + "astring": { + "definition": "astring-parameter", + "destination": { + "env": "ASTRING" + } + }, + "astringenum": { + "definition": "astringenum-parameter", + "destination": { + "env": "ASTRINGENUM" + } + }, + "cfg": { + "definition": "cfg-parameter", + "description": "A json config file", + "destination": { + "path": "/cnab/app/buncfg.json" + } + }, + "chaos_monkey": { + "definition": "chaos_monkey-parameter", + "description": "Set to true to make the bundle fail", + "destination": { + "env": "CHAOS_MONKEY" + } + }, + "installonly": { + "definition": "installonly-parameter", + "applyTo": [ + "install" + ], + "destination": { + "env": "INSTALLONLY" + } + }, + "jsonobject": { + "definition": "jsonobject-parameter", + "destination": { + "env": "JSONOBJECT" + } + }, + "log_level": { + "definition": "log_level-parameter", + "description": "How unhelpful would you like the logs to be?", + "destination": { + "env": "LOG_LEVEL" + } + }, + "mysql-connstr": { + "definition": "mysql-connstr-parameter", + "destination": { + "env": "MYSQL_CONNSTR" + } + }, + "notype-file": { + "definition": "notype-file-parameter", + "destination": { + "path": "/cnab/app/config.toml" + } + }, + "notype-string": { + "definition": "notype-string-parameter", + "destination": { + "env": "NOTYPE_STRING" + } + }, + "password": { + "definition": "password-parameter", + "description": "The super secret data", + "destination": { + "env": "PASSWORD" + } + }, + "porter-debug": { + "definition": "porter-debug-parameter", + "description": "Print debug information from Porter when executing the bundle", + "destination": { + "env": "PORTER_DEBUG" + } + }, + "porter-msg-output": { + "definition": "porter-msg-output", + "description": "Wires up the msg output for use as a parameter. Porter internal parameter that should not be set manually.", + "destination": { + "env": "PORTER_MSG_OUTPUT" + } + }, + "porter-state": { + "definition": "porter-state", + "description": "Supports persisting state for bundles. Porter internal parameter that should not be set manually.", + "destination": { + "path": "/porter/state.tgz" + } + }, + "sensitive": { + "definition": "sensitive-parameter", + "destination": { + "env": "SENSITIVE" + } + }, + "tfstate": { + "definition": "tfstate-parameter", + "applyTo": [ + "upgrade", + "uninstall" + ], + "destination": { + "path": "/cnab/app/tfstate" + }, + "required": true + } + }, + "credentials": { + "password": { + "path": "/tmp/password", + "required": true, + "applyTo": [ + "boom" + ] + }, + "username": { + "env": "ROOT_USERNAME", + "description": "The name you want on the audit log" + } + }, + "outputs": { + "connStr": { + "definition": "connStr-output", + "applyTo": [ + "install" + ], + "path": "/cnab/app/outputs/connStr" + }, + "msg": { + "definition": "msg-output", + "applyTo": [ + "install", + "upgrade", + "uninstall" + ], + "path": "/cnab/app/outputs/msg" + }, + "mylogs": { + "definition": "mylogs-output", + "applyTo": [ + "install", + "upgrade" + ], + "path": "/cnab/app/outputs/mylogs" + }, + "porter-state": { + "definition": "porter-state", + "description": "Supports persisting state for bundles. Porter internal parameter that should not be set manually.", + "path": "/cnab/app/outputs/porter-state" + }, + "result": { + "definition": "result-output", + "applyTo": [ + "install", + "upgrade" + ], + "path": "/cnab/app/outputs/result" + }, + "tfstate": { + "definition": "tfstate-output", + "applyTo": [ + "install", + "upgrade", + "uninstall" + ], + "path": "/cnab/app/outputs/tfstate" + } + }, + "definitions": { + "aboolean-parameter": { + "default": true, + "type": "boolean" + }, + "afile-parameter": { + "contentEncoding": "base64", + "default": "", + "type": "string" + }, + "ainteger-parameter": { + "default": 1, + "maximum": 10, + "minimum": 0, + "type": "integer" + }, + "anumber-parameter": { + "default": 0.5, + "exclusiveMaximum": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + "astring-parameter": { + "default": "boop!", + "maxLength": 10, + "minLength": 1, + "type": "string" + }, + "astringenum-parameter": { + "default": "blue", + "enum": [ + "blue", + "red", + "purple", + "pink" + ], + "type": "string" + }, + "cfg-parameter": { + "contentEncoding": "base64", + "default": "", + "description": "A json config file", + "type": "string" + }, + "chaos_monkey-parameter": { + "default": false, + "description": "Set to true to make the bundle fail", + "type": "boolean" + }, + "connStr-output": { + "$id": "porter.sh/interfaces/mysql.connection-string", + "default": "", + "type": "string" + }, + "installonly-parameter": { + "default": false, + "type": "boolean" + }, + "jsonobject-parameter": { + "default": "\"myobject\": { \"foo\": \"true\", \"bar\": [ 1, 2, 3 ] }", + "type": "string" + }, + "log_level-parameter": { + "default": 5, + "description": "How unhelpful would you like the logs to be?", + "maximum": 11, + "minimum": 1, + "type": "integer" + }, + "msg-output": { + "default": "", + "type": "string" + }, + "mylogs-output": { + "type": "string" + }, + "mysql-connstr-parameter": { + "default": "", + "type": "string" + }, + "notype-file-parameter": { + "contentEncoding": "base64", + "default": "", + "type": "string" + }, + "notype-string-parameter": { + "default": "", + "type": "string" + }, + "password-parameter": { + "default": "default-secret", + "description": "The super secret data", + "type": "string", + "writeOnly": true + }, + "porter-debug-parameter": { + "$comment": "porter-internal", + "$id": "https://porter.sh/generated-bundle/#porter-debug", + "default": false, + "description": "Print debug information from Porter when executing the bundle", + "type": "boolean" + }, + "porter-msg-output": { + "$comment": "porter-internal", + "$id": "https://porter.sh/generated-bundle/#porter-parameter-source-definition", + "default": "", + "type": "string" + }, + "porter-state": { + "$comment": "porter-internal", + "$id": "https://porter.sh/generated-bundle/#porter-state", + "contentEncoding": "base64", + "description": "Supports persisting state for bundles. Porter internal parameter that should not be set manually.", + "type": "string" + }, + "result-output": { + "type": "string", + "writeOnly": true + }, + "sensitive-parameter": { + "default": "passw0rd123", + "type": "string", + "writeOnly": true + }, + "tfstate-output": { + "contentEncoding": "base64", + "type": "string" + }, + "tfstate-parameter": { + "contentEncoding": "base64", + "type": "string" + } + }, + "requiredExtensions": [ + "sh.porter.file-parameters", + "org.getporter.dependencies@v2", + "io.cnab.parameter-sources", + "io.cnab.docker" + ], + "custom": { + "app": { + "version": "1.2.3" + }, + "foo": { + "test1": true, + "test2": 1, + "test3": "value", + "test4": [ + "one", + "two", + "three" + ], + "test5": { + "1": "one", + "two": "two" + } + }, + "io.cnab.docker": null, + "io.cnab.parameter-sources": { + "mysql-connstr": { + "priority": [ + "dependencies.output" + ], + "sources": { + "dependencies.output": { + "dependency": "db", + "name": "connstr" + } + } + }, + "porter-msg-output": { + "priority": [ + "output" + ], + "sources": { + "output": { + "name": "msg" + } + } + }, + "porter-state": { + "priority": [ + "output" + ], + "sources": { + "output": { + "name": "porter-state" + } + } + }, + "tfstate": { + "priority": [ + "output" + ], + "sources": { + "output": { + "name": "tfstate" + } + } + } + }, + "org.getporter.dependencies@v2": { + "requires": { + "db": { + "bundle": "localhost:5000/mydb:v0.1.0", + "sharing": { + "group": {} + }, + "parameters": { + "database": "bigdb" + } + } + } + }, + "sh.porter": { + "manifestDigest": "", + "mixins": { + "exec": { + "version": "v1.2.3" + } + }, + "manifest": "IyBUaGlzIGlzIGEgdGVzdCBidW5kbGUgdGhhdCBtYWtlcyBubyBsb2dpY2FsIHNlbnNlLCBidXQgaXQgZG9lcyBleGVyY2lzZSBsb3RzIG9mIGRpZmZlcmVudCBidW5kbGUgZmVhdHVyZXMKc2NoZW1hVHlwZTogQnVuZGxlCnNjaGVtYVZlcnNpb246IDEuMC4xCm5hbWU6IG15YnVucwp2ZXJzaW9uOiAwLjEuMgpkZXNjcmlwdGlvbjogIkEgdmVyeSB0aG9yb3VnaCB0ZXN0IGJ1bmRsZSIKcmVnaXN0cnk6IGxvY2FsaG9zdDo1MDAwCmRvY2tlcmZpbGU6IERvY2tlcmZpbGUudG1wbAoKbWFpbnRhaW5lcnM6Ci0gbmFtZTogIkpvaG4gRG9lIgogIGVtYWlsOiAiam9obi5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9hIgotIG5hbWU6ICJKYW5lIERvZSIKICB1cmw6ICJodHRwczovL2V4YW1wbGUuY29tL2IiCi0gbmFtZTogIkphbmluZSBEb2UiCiAgZW1haWw6ICJqYW5pbmUuZG9lQGV4YW1wbGUuY29tIgotIGVtYWlsOiAibWlrZS5kb2VAZXhhbXBsZS5jb20iCiAgdXJsOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9jIgoKY3VzdG9tOgogIGFwcDoKICAgIHZlcnNpb246IDEuMi4zCiAgZm9vOgogICAgdGVzdDE6IHRydWUKICAgIHRlc3QyOiAxCiAgICB0ZXN0MzogdmFsdWUKICAgIHRlc3Q0OgogICAgICAtIG9uZQogICAgICAtIHR3bwogICAgICAtIHRocmVlCiAgICB0ZXN0NToKICAgICAgMTogb25lCiAgICAgIHR3bzogdHdvCgpyZXF1aXJlZDoKICAtIGRvY2tlcgoKY3JlZGVudGlhbHM6CiAgLSBuYW1lOiB1c2VybmFtZQogICAgZGVzY3JpcHRpb246ICJUaGUgbmFtZSB5b3Ugd2FudCBvbiB0aGUgYXVkaXQgbG9nIgogICAgZW52OiBST09UX1VTRVJOQU1FCiAgICByZXF1aXJlZDogZmFsc2UKICAtIG5hbWU6IHBhc3N3b3JkCiAgICBwYXRoOiAvdG1wL3Bhc3N3b3JkCiAgICBhcHBseVRvOgogICAgICAtIGJvb20KCnBhcmFtZXRlcnM6CiAgLSBuYW1lOiBsb2dfbGV2ZWwKICAgIGRlc2NyaXB0aW9uOiAiSG93IHVuaGVscGZ1bCB3b3VsZCB5b3UgbGlrZSB0aGUgbG9ncyB0byBiZT8iCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBtaW5pbXVtOiAxCiAgICBtYXhpbXVtOiAxMQogICAgZGVmYXVsdDogNQogIC0gbmFtZTogcGFzc3dvcmQKICAgIGRlc2NyaXB0aW9uOiAiVGhlIHN1cGVyIHNlY3JldCBkYXRhIgogICAgdHlwZTogc3RyaW5nCiAgICBkZWZhdWx0OiAiZGVmYXVsdC1zZWNyZXQiCiAgICBzZW5zaXRpdmU6IHRydWUKICAtIG5hbWU6IG15c3FsLWNvbm5zdHIKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIgIyBTZXR0aW5nIGEgZGVmYXVsdCBzbyB0aGF0IHRoaXMgaXNuJ3QgcmVxdWlyZWQgZm9yIGluc3RhbGwKICAgIHNvdXJjZToKICAgICAgZGVwZW5kZW5jeTogZGIKICAgICAgb3V0cHV0OiBjb25uc3RyCiAgLSBuYW1lOiBjaGFvc19tb25rZXkKICAgIGRlc2NyaXB0aW9uOiAiU2V0IHRvIHRydWUgdG8gbWFrZSB0aGUgYnVuZGxlIGZhaWwiCiAgICB0eXBlOiBib29sZWFuCiAgICBkZWZhdWx0OiBmYWxzZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIHNvdXJjZToKICAgICAgb3V0cHV0OiB0ZnN0YXRlCiAgICBhcHBseVRvOgogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNmZwogICAgZGVzY3JpcHRpb246ICJBIGpzb24gY29uZmlnIGZpbGUiCiAgICB0eXBlOiBmaWxlCiAgICBkZWZhdWx0OiAnJwogICAgcGF0aDogYnVuY2ZnLmpzb24KICAtIG5hbWU6IGFpbnRlZ2VyCiAgICB0eXBlOiBpbnRlZ2VyCiAgICBkZWZhdWx0OiAxCiAgICBtaW5pbXVtOiAwCiAgICBtYXhpbXVtOiAxMAogIC0gbmFtZTogYW51bWJlcgogICAgdHlwZTogbnVtYmVyCiAgICBkZWZhdWx0OiAwLjUgIyBUaGlzIGlzIGEgcmVncmVzc2lvbiB0ZXN0IHRoYXQgd2UgY2FuIGJvdGggYnVpbGQgYW5kIHB1c2ggYSBidW5kbGUgdGhhdCB1c2VzIG51bWVyaWMgdHlwZXMKICAgIGV4Y2x1c2l2ZU1pbmltdW06IDAKICAgIGV4Y2x1c2l2ZU1heGltdW06IDEKICAtIG5hbWU6IGFzdHJpbmdlbnVtCiAgICB0eXBlOiBzdHJpbmcKICAgIGRlZmF1bHQ6IGJsdWUKICAgIGVudW06CiAgICAgIC0gYmx1ZQogICAgICAtIHJlZAogICAgICAtIHB1cnBsZQogICAgICAtIHBpbmsKICAtIG5hbWU6IGFzdHJpbmcKICAgIHR5cGU6IHN0cmluZwogICAgbWluTGVuZ3RoOiAxCiAgICBtYXhMZW5ndGg6IDEwCiAgICBkZWZhdWx0OiAnYm9vcCEnCiAgLSBuYW1lOiBhYm9vbGVhbgogICAgdHlwZTogYm9vbGVhbgogICAgZGVmYXVsdDogdHJ1ZQogIC0gbmFtZTogaW5zdGFsbG9ubHkKICAgIHR5cGU6IGJvb2xlYW4KICAgIGRlZmF1bHQ6IGZhbHNlCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAtIG5hbWU6IHNlbnNpdGl2ZQogICAgdHlwZTogc3RyaW5nCiAgICBzZW5zaXRpdmU6IHRydWUKICAgIGRlZmF1bHQ6ICJwYXNzdzByZDEyMyIKICAtIG5hbWU6IGpzb25vYmplY3QKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogJyJteW9iamVjdCI6IHsKICAgICAgICAiZm9vIjogInRydWUiLAogICAgICAgICJiYXIiOiBbCiAgICAgICAgICAxLAogICAgICAgICAgMiwKICAgICAgICAgIDMKICAgICAgICBdCiAgICAgIH0nCiAgLSBuYW1lOiBhZmlsZQogICAgdHlwZTogZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9ob21lL25vbnJvb3QvLmt1YmUvY29uZmlnCiAgLSBuYW1lOiBub3R5cGUtZmlsZQogICAgZGVmYXVsdDogJycKICAgIHBhdGg6IC9jbmFiL2FwcC9jb25maWcudG9tbAogIC0gbmFtZTogbm90eXBlLXN0cmluZwogICAgZGVmYXVsdDogJycKCm91dHB1dHM6CiAgLSBuYW1lOiBtc2cKICAgIHR5cGU6IHN0cmluZwogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKICAtIG5hbWU6IGNvbm5TdHIKICAgICRpZDogInBvcnRlci5zaC9pbnRlcmZhY2VzL215c3FsLmNvbm5lY3Rpb24tc3RyaW5nIgogICAgZGVmYXVsdDogIiIKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogIC0gbmFtZTogbXlsb2dzCiAgICBhcHBseVRvOgogICAgICAtIGluc3RhbGwKICAgICAgLSB1cGdyYWRlCiAgLSBuYW1lOiByZXN1bHQKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgIHNlbnNpdGl2ZTogdHJ1ZQogIC0gbmFtZTogdGZzdGF0ZQogICAgdHlwZTogZmlsZQogICAgcGF0aDogL2NuYWIvYXBwL3Rmc3RhdGUKICAgIGFwcGx5VG86CiAgICAgIC0gaW5zdGFsbAogICAgICAtIHVwZ3JhZGUKICAgICAgLSB1bmluc3RhbGwKCnN0YXRlOgogIC0gbmFtZTogbWFnaWNfZmlsZQogICAgcGF0aDogbWFnaWMudHh0CgpkZXBlbmRlbmNpZXM6CiAgcmVxdWlyZXM6CiAgICAtIG5hbWU6IGRiCiAgICAgIGJ1bmRsZToKICAgICAgICByZWZlcmVuY2U6ICJsb2NhbGhvc3Q6NTAwMC9teWRiOnYwLjEuMCIKICAgICAgcGFyYW1ldGVyczoKICAgICAgICBkYXRhYmFzZTogYmlnZGIKCmltYWdlczoKICB3aGFsZXNheWQ6CiAgICBkZXNjcmlwdGlvbjogIldoYWxlc2F5IGFzIGEgc2VydmljZSIKICAgIGltYWdlVHlwZTogImRvY2tlciIKICAgIHJlcG9zaXRvcnk6IGNhcm9seW52cy93aGFsZXNheWQKICAgIHRhZzogImxhdGVzdCIKCm1peGluczoKICAtIGV4ZWMKICAtIHRlc3RtaXhpbjoKICAgICAgY2xpZW50VmVyc2lvbjogMS4yLjMKCmN1c3RvbUFjdGlvbnM6CiAgZHJ5LXJ1bjoKICAgIGRlc2NyaXB0aW9uOiAiTWFrZSBzdXJlIGl0IHdpbGwgd29yayBiZWZvcmUgeW91IHJ1biBpdCIKICAgIHN0YXRlbGVzczogdHJ1ZQogICAgbW9kaWZpZXM6IGZhbHNlCiAgc3RhdHVzOgogICAgZGVzY3JpcHRpb246ICJQcmludCB0aGUgaW5zdGFsbGF0aW9uIHN0YXR1cyIKICAgIHN0YXRlbGVzczogZmFsc2UKICAgIG1vZGlmaWVzOiBmYWxzZQoKaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgdGhlIGRvY2tlciBzb2NrZXQiCiAgICAgIGNvbW1hbmQ6IHN0YXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gL3Zhci9ydW4vZG9ja2VyLnNvY2sKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiTGV0J3MgbWFrZSBzb21lIG1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFrZU1hZ2ljCiAgICAgICAgLSAiJHsgYnVuZGxlLmNyZWRlbnRpYWxzLnVzZXJuYW1lIH0gaXMgYSB1bmljb3JuIHdpdGggJHsgYnVuZGxlLnBhcmFtZXRlcnMucGFzc3dvcmQgfSBzZWNyZXQuIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJpbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gaW5zdGFsbAogICAgICBvdXRwdXRzOgogICAgICAgIC0gbmFtZTogbXlsb2dzCiAgICAgICAgICByZWdleDogIiguKikiCiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogInJvbGwgdGhlIGRpY2Ugd2l0aCB5b3VyIGNoYW9zIG1vbmtleSIKICAgICAgY29tbWFuZDogLi9oZWxwZXJzLnNoCiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtIGNoYW9zX21vbmtleQogICAgICAgIC0gJHsgYnVuZGxlLnBhcmFtZXRlcnMuY2hhb3NfbW9ua2V5IH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IHJlc3VsdAogICAgICAgICAgcmVnZXg6ICIoLiopIgoKZHJ5LXJ1bjoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgc29tZSB0aGluZ3MiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIkFsbCBjbGVhciEiCgpzdGF0dXM6CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IGNvbmZpZyIKICAgICAgY29tbWFuZDogY2F0CiAgICAgIGFyZ3VtZW50czoKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNmZyB9CiAgLSBleGVjOgogICAgICBkZXNjcmlwdGlvbjogIlByaW50IG1hZ2ljIgogICAgICBjb21tYW5kOiBjYXQKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gbWFnaWMudHh0Cgpib29tOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJtb2RpZnkgdGhlIGJ1bmRsZSBpbiB1bmtub3dhYmxlIHdheXMiCiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIllPTE8iCgp1cGdyYWRlOgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJFbnN1cmUgbWFnaWMiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBlbnN1cmVNYWdpYwogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJ1cGdyYWRlIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdXBncmFkZQogICAgICAgIC0gJHsgYnVuZGxlLm91dHB1dHMubXNnIH0KICAgICAgb3V0cHV0czoKICAgICAgICAtIG5hbWU6IG15bG9ncwogICAgICAgICAgcmVnZXg6ICIoLiopIgogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9CiAgICAgIG91dHB1dHM6CiAgICAgICAgLSBuYW1lOiByZXN1bHQKICAgICAgICAgIHJlZ2V4OiAiKC4qKSIKCnVuaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAiRW5zdXJlIE1hZ2ljIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gZW5zdXJlTWFnaWMKICAtIGV4ZWM6CiAgICAgIGRlc2NyaXB0aW9uOiAidW5pbnN0YWxsIgogICAgICBjb21tYW5kOiAuL2hlbHBlcnMuc2gKICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gdW5pbnN0YWxsCiAgICAgICAgLSAkeyBidW5kbGUub3V0cHV0cy5tc2cgfQogIC0gZXhlYzoKICAgICAgZGVzY3JpcHRpb246ICJyb2xsIHRoZSBkaWNlIHdpdGggeW91ciBjaGFvcyBtb25rZXkiCiAgICAgIGNvbW1hbmQ6IC4vaGVscGVycy5zaAogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSBjaGFvc19tb25rZXkKICAgICAgICAtICR7IGJ1bmRsZS5wYXJhbWV0ZXJzLmNoYW9zX21vbmtleSB9Cg==", + "version": "", + "commit": "", + "preserveTags": true + }, + "sh.porter.file-parameters": {} + } +} \ No newline at end of file diff --git a/pkg/cnab/config-adapter/testdata/myenv-depsv2.bundle.json b/pkg/cnab/config-adapter/testdata/myenv-depsv2.bundle.json index 11d4d4b16..b3f390d9f 100644 --- a/pkg/cnab/config-adapter/testdata/myenv-depsv2.bundle.json +++ b/pkg/cnab/config-adapter/testdata/myenv-depsv2.bundle.json @@ -195,7 +195,8 @@ }, "manifest": "c2NoZW1hVmVyc2lvbjogMS4xLjAKbmFtZTogbXllbnYKdmVyc2lvbjogMC4xLjAKZGVzY3JpcHRpb246ICJBICdtZXRhJyBidW5kbGUgdGhhdCBkZXBsb3lzIGV2ZXJ5dGhpbmcgaXQgbmVlZHMgYnkgYWRkaW5nIGRlcGVuZGVuY2llcyIKcmVnaXN0cnk6ICJsb2NhbGhvc3Q6NTAwMCIKCmNyZWRlbnRpYWxzOgogIC0gbmFtZTogdG9rZW4KCnBhcmFtZXRlcnM6CiAgLSBuYW1lOiBsb2dMZXZlbAogICAgdHlwZTogc3RyaW5nCiAgICBkZWZhdWx0OiBpbmZvCgpvdXRwdXRzOgogIC0gbmFtZTogZW5kcG9pbnQKICAgIHR5cGU6IHN0cmluZwoKZGVwZW5kZW5jaWVzOgogIHJlcXVpcmVzOgogICAgLSBuYW1lOiBpbmZyYQogICAgICBidW5kbGU6CiAgICAgICAgaWQ6ICJodHRwczovL3BvcnRlci5zaC9pbnRlcmZhY2VzL215c3FsIgogICAgICAgIHJlZmVyZW5jZTogImxvY2FsaG9zdDo1MDAwL215aW5mcmE6djAuMS4wIgogICAgICAgICMgVE9ETyhQRVAwMDMpOiBJbXBsZW1lbnQgd2l0aCBodHRwczovL2dpdGh1Yi5jb20vZ2V0cG9ydGVyL3BvcnRlci9pc3N1ZXMvMjU0OAogICAgICAgICNpbnRlcmZhY2U6CiAgICAgICAgIyAgZG9jdW1lbnQ6CiAgICAgICAgIyAgICBvdXRwdXRzOgogICAgICAgICMgICAgICAtIG5hbWU6IG15c3FsLWNvbm5zdHIKICAgICAgICAjICAgICAgICAkaWQ6ICJwb3J0ZXIuc2gvaW50ZXJmYWNlcy9teXNxbC5jb25uZWN0aW9uLXN0cmluZyIKICAgICAgY3JlZGVudGlhbHM6CiAgICAgICAgdG9rZW46ICR7YnVuZGxlLmNyZWRlbnRpYWxzLnRva2VufQogICAgICBwYXJhbWV0ZXJzOgogICAgICAgIGRhdGFiYXNlOiBteWVudmRiCiAgICAgICAgbG9nTGV2ZWw6ICR7YnVuZGxlLnBhcmFtZXRlcnMubG9nTGV2ZWx9CiAgICAtIG5hbWU6IGFwcAogICAgICBidW5kbGU6CiAgICAgICAgcmVmZXJlbmNlOiAibG9jYWxob3N0OjUwMDAvbXlhcHA6djEuMi4zIgogICAgICBjcmVkZW50aWFsczoKICAgICAgICBkYi1jb25uc3RyOiAke2J1bmRsZS5kZXBlbmRlbmNpZXMuaW5mcmEub3V0cHV0cy5teXNxbC1jb25uc3RyfQogICAgICBwYXJhbWV0ZXJzOgogICAgICAgIGxvZ0xldmVsOiAke2J1bmRsZS5wYXJhbWV0ZXJzLmxvZ0xldmVsfQogICAgICBvdXRwdXRzOgogICAgICAgIGVuZHBvaW50OiAiaHR0cHM6Ly8ke2J1bmRsZS5kZXBlbmRlbmNpZXMuaW5mcmEub3V0cHV0cy5pcH06JHtvdXRwdXRzLnBvcnR9L215YXBwIgoKIyBUaGUgcmVzdCBiZWxvdyBpcyBib2lsZXJwbGF0ZSB0byBtYWtlIHBvcnRlciBoYXBweQojIFNpbmNlIHRoaXMgaXMgYSAibWV0YSIgYnVuZGxlLCBpdCBkb2Vzbid0IGRvIGFueXRoaW5nIGl0c2VsZiwganVzdCByZWZlcmVuY2VzIG90aGVyIGJ1bmRsZXMKbWl4aW5zOgogIC0gZXhlYwoKaW5zdGFsbDoKICAtIGV4ZWM6CiAgICAgIGNvbW1hbmQ6IGVjaG8KICAgICAgYXJndW1lbnRzOgogICAgICAgIC0gIkluc3RhbGxpbmcgYW4gZW52aXJvbm1lbnQiCgp1cGdyYWRlOgogIC0gZXhlYzoKICAgICAgY29tbWFuZDogZWNobwogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSAiVXBncmFkaW5nIGFuIGVudmlyb25tZW50IgoKdW5pbnN0YWxsOgogIC0gZXhlYzoKICAgICAgY29tbWFuZDogZWNobwogICAgICBhcmd1bWVudHM6CiAgICAgICAgLSAiVW5pbnN0YWxsaW5nIGFuIGVudmlyb25tZW50Igo=", "version": "", - "commit": "" + "commit": "", + "preserveTags": false }, "sh.porter.file-parameters": {} } diff --git a/pkg/porter/build.go b/pkg/porter/build.go index 0902df00b..1d8bea1ec 100644 --- a/pkg/porter/build.go +++ b/pkg/porter/build.go @@ -143,7 +143,7 @@ func (p *Porter) Build(ctx context.Context, opts BuildOptions) error { // bundle.json will *not* be correct until the image is actually pushed // to a registry. The bundle.json will need to be updated after publishing // and provided just-in-time during bundle execution. - if err := p.buildBundle(ctx, m, ""); err != nil { + if err := p.buildBundle(ctx, m, "", opts.PreserveTags); err != nil { return span.Error(fmt.Errorf("unable to build bundle: %w", err)) } @@ -227,7 +227,7 @@ func (p *Porter) getUsedMixins(ctx context.Context, m *manifest.Manifest) ([]mix return usedMixins, nil } -func (p *Porter) buildBundle(ctx context.Context, m *manifest.Manifest, digest digest.Digest) error { +func (p *Porter) buildBundle(ctx context.Context, m *manifest.Manifest, digest digest.Digest, preserveTags bool) error { imageDigests := map[string]string{m.Image: digest.String()} mixins, err := p.getUsedMixins(ctx, m) @@ -235,7 +235,7 @@ func (p *Porter) buildBundle(ctx context.Context, m *manifest.Manifest, digest d return err } - converter := configadapter.NewManifestConverter(p.Config, m, imageDigests, mixins) + converter := configadapter.NewManifestConverter(p.Config, m, imageDigests, mixins, preserveTags) bun, err := converter.ToBundle(ctx) if err != nil { return err diff --git a/pkg/porter/build_integration_test.go b/pkg/porter/build_integration_test.go index 1998f86f9..330a2af90 100644 --- a/pkg/porter/build_integration_test.go +++ b/pkg/porter/build_integration_test.go @@ -186,7 +186,7 @@ func TestPorter_paramRequired(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, p.Config, config.Name) require.NoError(t, err) - err = p.buildBundle(ctx, m, "digest") + err = p.buildBundle(ctx, m, "digest", false) require.NoError(t, err) bundleBytes, err := p.FileSystem.ReadFile(build.LOCAL_BUNDLE) @@ -278,7 +278,7 @@ func TestPorter_BuildWithCustomValues(t *testing.T) { m, err := manifest.LoadManifestFrom(ctx, p.Config, config.Name) require.NoError(t, err) - err = p.buildBundle(ctx, m, "digest") + err = p.buildBundle(ctx, m, "digest", false) require.NoError(t, err) opts := BuildOptions{Customs: []string{"customKey1=editedCustomValue1"}} @@ -292,3 +292,35 @@ func TestPorter_BuildWithCustomValues(t *testing.T) { assert.Equal(t, bun.Custom["customKey1"], "editedCustomValue1") } + +func TestPorter_BuildWithPreserveTags(t *testing.T) { + p := NewTestPorter(t) + defer p.Close() + + p.TestConfig.TestContext.AddTestFile("./testdata/porter-with-image-tag.yaml", config.Name) + + ctx := context.Background() + m, err := manifest.LoadManifestFrom(ctx, p.Config, config.Name) + require.NoError(t, err) + + err = p.buildBundle(ctx, m, "digest", true) + require.NoError(t, err) + + opts := BuildOptions{ + BundleDefinitionOptions: BundleDefinitionOptions{ + PreserveTags: true, + }, + } + require.NoError(t, opts.Validate(p.Porter), "Validate failed") + + err = p.Build(ctx, opts) + require.NoError(t, err) + + bun, err := p.CNAB.LoadBundle(build.LOCAL_BUNDLE) + require.NoError(t, err) + + stamp, err := configadapter.LoadStamp(bun) + require.NoError(t, err) + assert.Equal(t, stamp.PreserveTags, true) + assert.Empty(t, bun.Images["something"].Digest) +} diff --git a/pkg/porter/cnab.go b/pkg/porter/cnab.go index f48d25790..3c446109a 100644 --- a/pkg/porter/cnab.go +++ b/pkg/porter/cnab.go @@ -43,6 +43,9 @@ type BundleDefinitionOptions struct { // definition has changed since it was last built and automatically build before // executing the requested command. AutoBuildDisabled bool + + // PreserveTags keep the original tag name on referenced images. + PreserveTags bool } func (o *BundleDefinitionOptions) Validate(cxt *portercontext.Context) error { diff --git a/pkg/porter/copy.go b/pkg/porter/copy.go index e33193b5b..e84ab1dce 100644 --- a/pkg/porter/copy.go +++ b/pkg/porter/copy.go @@ -20,6 +20,7 @@ type CopyOpts struct { InsecureRegistry bool Force bool SignBundle bool + PreserveTags bool } // Validate performs validation logic on the options specified for a bundle copy @@ -98,7 +99,6 @@ func (p *Porter) CopyBundle(ctx context.Context, opts *CopyOpts) error { } bunRef.Reference = destinationRef - bunRef, err = p.Registry.PushBundle(ctx, bunRef, regOpts) if err != nil { return span.Error(fmt.Errorf("unable to copy bundle to new location: %w", err)) diff --git a/pkg/porter/generateManifest.go b/pkg/porter/generateManifest.go index 4c0a5e941..ece7880f9 100644 --- a/pkg/porter/generateManifest.go +++ b/pkg/porter/generateManifest.go @@ -93,26 +93,48 @@ func (p *Porter) generateInternalManifest(ctx context.Context, opts BuildOptions if err != nil { return span.Errorf("failed to parse image %s reference: %w", img.Repository, err) } + if opts.PreserveTags { + if img.Tag == "" { + var path string + for _, p := range nc.PathStack { + switch t := p.(type) { + case string: + path += fmt.Sprintf("%s.", t) + case int: + path = strings.TrimSuffix(path, ".") + path += fmt.Sprintf("[%s].", strconv.Itoa(t)) + default: + continue + } + } + + return e.SetValue(path+"tag", "latest") + } + } else { - digest, err := p.getImageDigest(ctx, ref, regOpts) - if err != nil { - return span.Error(err) - } - span.SetAttributes(attribute.String("digest", digest.Encoded())) - - var path string - for _, p := range nc.PathStack { - switch t := p.(type) { - case string: - path += fmt.Sprintf("%s.", t) - case int: - path = strings.TrimSuffix(path, ".") - path += fmt.Sprintf("[%s].", strconv.Itoa(t)) - default: - continue + digest, err := p.getImageDigest(ctx, ref, regOpts) + if err != nil { + return span.Error(err) + } + span.SetAttributes(attribute.String("digest", digest.Encoded())) + + var path string + for _, p := range nc.PathStack { + switch t := p.(type) { + case string: + path += fmt.Sprintf("%s.", t) + case int: + path = strings.TrimSuffix(path, ".") + path += fmt.Sprintf("[%s].", strconv.Itoa(t)) + default: + continue + } } + + return e.SetValue(path+"digest", digest.String()) } - return e.SetValue(path+"digest", digest.String()) + + return nil }) if err != nil { return err diff --git a/pkg/porter/generateManifest_test.go b/pkg/porter/generateManifest_test.go index 8340a13ea..3427e984f 100644 --- a/pkg/porter/generateManifest_test.go +++ b/pkg/porter/generateManifest_test.go @@ -28,6 +28,10 @@ func Test_generateInternalManifest(t *testing.T) { name: "no opts", opts: BuildOptions{}, wantManifest: "expected-result.yaml", + }, { + name: "preserve tags", + opts: BuildOptions{BundleDefinitionOptions: BundleDefinitionOptions{PreserveTags: true}}, + wantManifest: "expected-result-preserve-tags.yaml", }, { name: "--file set", opts: BuildOptions{ diff --git a/pkg/porter/publish.go b/pkg/porter/publish.go index 5a44c1a9f..c32a66334 100644 --- a/pkg/porter/publish.go +++ b/pkg/porter/publish.go @@ -11,6 +11,7 @@ import ( "get.porter.sh/porter/pkg/build" "get.porter.sh/porter/pkg/cnab" cnabtooci "get.porter.sh/porter/pkg/cnab/cnab-to-oci" + configadapter "get.porter.sh/porter/pkg/cnab/config-adapter" "get.porter.sh/porter/pkg/config" "get.porter.sh/porter/pkg/manifest" "get.porter.sh/porter/pkg/tracing" @@ -104,7 +105,7 @@ func (p *Porter) publishFromFile(ctx context.Context, opts PublishOptions) error BundleDefinitionOptions: opts.BundleDefinitionOptions, InsecureRegistry: opts.InsecureRegistry, } - _, err := p.ensureLocalBundleIsUpToDate(ctx, buildOpts) + bundleRef, err := p.ensureLocalBundleIsUpToDate(ctx, buildOpts) if err != nil { return err } @@ -172,7 +173,7 @@ func (p *Porter) publishFromFile(ctx context.Context, opts PublishOptions) error return log.Errorf("porter.yaml is missing registry or reference values needed for publishing") } - var bundleRef cnab.BundleReference + // var bundleRef cnab.BundleReference bundleRef.Reference, err = cnab.ParseOCIReference(m.Reference) if err != nil { return log.Errorf("invalid reference %s: %w", m.Reference, err) @@ -206,7 +207,11 @@ func (p *Porter) publishFromFile(ctx context.Context, opts PublishOptions) error return log.Errorf("unable to push bundle image %q: %w", m.Image, err) } - bundleRef.Definition, err = p.rewriteBundleWithBundleImageDigest(ctx, m, bundleRef.Digest) + stamp, err := configadapter.LoadStamp(bundleRef.Definition) + if err != nil { + return log.Errorf("failed to load stamp from bundle definition: %w", err) + } + bundleRef.Definition, err = p.rewriteBundleWithBundleImageDigest(ctx, m, bundleRef.Digest, stamp.PreserveTags) if err != nil { return err } @@ -335,6 +340,10 @@ func (p *Porter) publishFromArchive(ctx context.Context, opts PublishOptions) er } bundleRef, err = p.Registry.PushBundle(ctx, bundleRef, regOpts) + if err != nil { + return err + } + if opts.SignBundle { log.Debugf("Signing bundle %s...", bundleRef.String()) err = p.signImage(ctx, bundleRef.Reference) @@ -343,10 +352,6 @@ func (p *Porter) publishFromArchive(ctx context.Context, opts PublishOptions) er } } - if err != nil { - return err - } - // Perhaps we have a cached version of a bundle with the same tag, previously pulled // If so, replace it, as it is most likely out-of-date per this publish err = p.refreshCachedBundle(bundleRef) @@ -439,7 +444,7 @@ func getNewImageNameFromBundleReference(origImg, bundleTag string) (image.Name, return image.NewName(newImgRef.String()) } -func (p *Porter) rewriteBundleWithBundleImageDigest(ctx context.Context, m *manifest.Manifest, digest digest.Digest) (cnab.ExtendedBundle, error) { +func (p *Porter) rewriteBundleWithBundleImageDigest(ctx context.Context, m *manifest.Manifest, digest digest.Digest, preserveTags bool) (cnab.ExtendedBundle, error) { taggedImage, err := p.rewriteImageWithDigest(m.Image, digest.String()) if err != nil { return cnab.ExtendedBundle{}, fmt.Errorf("unable to update bundle image reference: %w", err) @@ -447,7 +452,7 @@ func (p *Porter) rewriteBundleWithBundleImageDigest(ctx context.Context, m *mani m.Image = taggedImage fmt.Fprintln(p.Out, "\nRewriting CNAB bundle.json...") - err = p.buildBundle(ctx, m, digest) + err = p.buildBundle(ctx, m, digest, preserveTags) if err != nil { return cnab.ExtendedBundle{}, fmt.Errorf("unable to rewrite CNAB bundle.json with updated bundle image digest: %w", err) } diff --git a/pkg/porter/stamp.go b/pkg/porter/stamp.go index c585ba790..feadb6111 100644 --- a/pkg/porter/stamp.go +++ b/pkg/porter/stamp.go @@ -137,7 +137,7 @@ func (p *Porter) IsBundleUpToDate(ctx context.Context, opts BundleDefinitionOpti return false, span.Error(err) } - converter := configadapter.NewManifestConverter(p.Config, m, nil, mixins) + converter := configadapter.NewManifestConverter(p.Config, m, nil, mixins, opts.PreserveTags) newDigest, err := converter.DigestManifest() if err != nil { err = fmt.Errorf("the current manifest digest cannot be calculated: %w", err) @@ -145,12 +145,19 @@ func (p *Porter) IsBundleUpToDate(ctx context.Context, opts BundleDefinitionOpti return false, span.Error(err) } - manifestChanged := oldStamp.ManifestDigest != newDigest + preserveTagsChanged := oldStamp.PreserveTags != opts.PreserveTags + digestChanged := oldStamp.ManifestDigest != newDigest + manifestChanged := digestChanged || preserveTagsChanged if manifestChanged { - span.Debugf("%s because the cached bundle is stale", rebuildMessagePrefix) + if preserveTagsChanged { + span.Debugf("PreserveTags is set to %t in the stamp, but the build is being run with PreserveTags set to %t", oldStamp.PreserveTags, opts.PreserveTags) + } + if digestChanged { + span.Debugf("%s because the cached bundle is stale", rebuildMessagePrefix) + } if span.IsTracingEnabled() { previousStampB, _ := json.Marshal(oldStamp) - currentStamp, _ := converter.GenerateStamp(ctx) + currentStamp, _ := converter.GenerateStamp(ctx, opts.PreserveTags) currentStampB, _ := json.Marshal(currentStamp) span.SetAttributes( attribute.String("previous-stamp", string(previousStampB)), diff --git a/pkg/porter/testdata/generateManifest/expected-result-preserve-tags.yaml b/pkg/porter/testdata/generateManifest/expected-result-preserve-tags.yaml new file mode 100644 index 000000000..280085a07 --- /dev/null +++ b/pkg/porter/testdata/generateManifest/expected-result-preserve-tags.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1.0.0-alpha.1 +name: porter-hello +version: 0.1.0 +description: "An example Porter configuration" +registry: "localhost:5000" +custom: + key1: value1 + key2: + nestedKey2: value2 +mixins: + - exec +images: + whalesayd: + description: "Whalesay as a service" + imageType: "docker" + repository: "test/whalesayd" + tag: latest +install: + - exec: + description: "Install Hello World" + command: ./helpers.sh + arguments: + - install +status: + - exec: + description: "World Status" + command: ./helpers.sh + arguments: + - status +uninstall: + - exec: + description: "Uninstall Hello World" + command: ./helpers.sh + arguments: + - uninstall +# comments n stuff diff --git a/pkg/porter/testdata/porter-with-image-tag.yaml b/pkg/porter/testdata/porter-with-image-tag.yaml new file mode 100644 index 000000000..7ccdc0116 --- /dev/null +++ b/pkg/porter/testdata/porter-with-image-tag.yaml @@ -0,0 +1,82 @@ +schemaVersion: 1.0.0 +name: porter-hello +version: 0.1.0 +description: "A bundle with a custom action" +registry: "localhost:5000" + +custom: + customKey1: "customValue1" + +credentials: + - name: my-first-cred + env: MY_FIRST_CRED + - name: my-second-cred + description: "My second cred" + path: /path/to/my-second-cred + +images: + something: + description: "an image" + imageType: "docker" + repository: "getporter/boo" + tag: "v1.1.1" + +parameters: + - name: my-first-param + type: integer + default: 9 + env: MY_FIRST_PARAM + applyTo: + - "install" + - name: my-second-param + description: "My second parameter" + type: string + default: spring-music-demo + path: /path/to/my-second-param + sensitive: true + +outputs: + - name: my-first-output + type: string + applyTo: + - "install" + - "upgrade" + sensitive: true + - name: my-second-output + description: "My second output" + type: boolean + sensitive: false + - name: kubeconfig + type: file + path: /home/nonroot/.kube/config + +mixins: + - exec + +install: + - exec: + description: "Install Hello World with custom arguments" + command: echo + arguments: + - ${ bundle.custom.customKey1 } + +upgrade: + - exec: + description: "World 2.0" + command: bash + flags: + c: echo World 2.0 + +zombies: + - exec: + description: "Trigger zombie apocalypse" + command: bash + flags: + c: echo oh noes my brains + +uninstall: + - exec: + description: "Uninstall Hello World" + command: bash + flags: + c: echo Goodbye World diff --git a/tests/integration/copy_test.go b/tests/integration/copy_test.go index 18be267f5..f00e953de 100644 --- a/tests/integration/copy_test.go +++ b/tests/integration/copy_test.go @@ -10,6 +10,7 @@ import ( "get.porter.sh/porter/pkg/cnab" "get.porter.sh/porter/tests/testdata" "get.porter.sh/porter/tests/tester" + "github.com/google/go-containerregistry/pkg/crane" "github.com/stretchr/testify/require" ) @@ -58,3 +59,53 @@ func TestCopy_UsesRelocationMap(t *testing.T) { invocationImage := images[0].(map[string]interface{}) require.Contains(t, invocationImage["originalImage"].(string), fmt.Sprintf("%s/orig-mydb", reg1)) } + +func TestCopy_PreserveTags(t *testing.T) { + testcases := []struct { + name string + preserveTags bool + }{ + {"preserve tags", true}, + {"do not preserve tags", false}, + } + + for _, tc := range testcases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + test, err := tester.NewTest(t) + defer test.Close() + require.NoError(t, err, "test setup failed") + + // Start a temporary registry, that uses plain http (no TLS) + reg1 := test.StartTestRegistry(tester.TestRegistryOptions{UseTLS: false}) + defer reg1.Close() + + // Publish the bundle to the insecure registry + origRef := fmt.Sprintf("%s/orig-mydb:v0.1.1", reg1) + opts := []func(*tester.TestBundleOptions){} + if tc.preserveTags { + opts = append(opts, tester.PreserveTags) + } + test.MakeTestBundle(testdata.EmbeddedImg, origRef, opts...) + + // Start a temporary (insecure) registry on a random port, with a self-signed certificate + reg2 := test.StartTestRegistry(tester.TestRegistryOptions{UseTLS: true}) + defer reg2.Close() + + // Copy the bundle to the integration test registry, using --insecure-registry + // because the destination uses a self-signed certificate + copiedRef := fmt.Sprintf("%s/copy-mydb:v0.1.1", reg2) + test.RequirePorter("copy", "--source", origRef, "--destination", copiedRef, "--insecure-registry") + + reg1.Close() + + // Get the original image from the relocation map + _, err = crane.Digest(fmt.Sprintf("%s/alpine:3.20.3", reg2), crane.Insecure) + if tc.preserveTags { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/tests/integration/publish_test.go b/tests/integration/publish_test.go index e82ed24ce..c5a809005 100644 --- a/tests/integration/publish_test.go +++ b/tests/integration/publish_test.go @@ -3,13 +3,16 @@ package integration import ( + "encoding/json" "fmt" "path" "testing" "get.porter.sh/porter/pkg/yaml" "get.porter.sh/porter/tests" + "get.porter.sh/porter/tests/testdata" "get.porter.sh/porter/tests/tester" + "github.com/google/go-containerregistry/pkg/crane" "github.com/stretchr/testify/require" ) @@ -47,3 +50,50 @@ func TestPublish(t *testing.T) { _, output = test.RequirePorter("publish", "--registry", reg.String(), "--insecure-registry") tests.RequireOutputContains(t, output, fmt.Sprintf("Bundle %s/porter-hello:v0.0.0 pushed successfully", reg)) } + +func TestPublish_PreserveTags(t *testing.T) { + test, err := tester.NewTest(t) + defer test.Close() + require.NoError(t, err, "test setup failed") + + // Start a temporary registry, that uses plain http (no TLS) + reg := test.StartTestRegistry(tester.TestRegistryOptions{UseTLS: false}) + defer reg.Close() + + ref := fmt.Sprintf("%s/embeddedimg:v0.1.1", reg) + test.MakeTestBundle(testdata.EmbeddedImg, ref, tester.PreserveTags) + + taggedDigest, err := crane.Digest(fmt.Sprintf("%s/alpine:3.20.3", reg), crane.Insecure) + require.NoError(t, err) + + // Confirm that the digest is the same + output, _ := test.RequirePorter("inspect", ref, "-o", "json", "--verbosity", "info") + var images struct { + Images []struct { + Digest string `json:"contentDigest"` + } `json:"images"` + } + require.NoError(t, json.Unmarshal([]byte(output), &images)) + require.Equal(t, 1, len(images.Images)) + require.Equal(t, taggedDigest, images.Images[0].Digest) +} + +func TestPublish_PreserveTagsChanged(t *testing.T) { + test, err := tester.NewTest(t) + defer test.Close() + require.NoError(t, err, "test setup failed") + + // Start a temporary registry, that uses plain http (no TLS) + reg := test.StartTestRegistry(tester.TestRegistryOptions{UseTLS: false}) + defer reg.Close() + + ref := fmt.Sprintf("%s/embeddedimg:v0.1.1", reg) + test.MakeTestBundle(testdata.EmbeddedImg, ref) + _, err = crane.Digest(fmt.Sprintf("%s/alpine:3.20.3", reg), crane.Insecure) + require.Error(t, err) + + ref = fmt.Sprintf("%s/embeddedimg:v0.1.2", reg) + test.MakeTestBundle(testdata.EmbeddedImg, ref, tester.PreserveTags) + _, err = crane.Digest(fmt.Sprintf("%s/alpine:3.20.3", reg), crane.Insecure) + require.NoError(t, err) +} diff --git a/tests/integration/testdata/bundles/bundle-with-image/helpers.sh b/tests/integration/testdata/bundles/bundle-with-image/helpers.sh new file mode 100755 index 000000000..7bb760cc7 --- /dev/null +++ b/tests/integration/testdata/bundles/bundle-with-image/helpers.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +install() { + echo Hello World +} + +upgrade() { + echo World 2.0 +} + +uninstall() { + echo Goodbye World +} + +zombies() { + echo oh noes my brains +} + +dump-myfile() { + cat /cnab/app/myfile +} + +# Call the requested function and pass the arguments as-is +"$@" diff --git a/tests/integration/testdata/bundles/bundle-with-image/porter.yaml b/tests/integration/testdata/bundles/bundle-with-image/porter.yaml new file mode 100644 index 000000000..ec9eb7e43 --- /dev/null +++ b/tests/integration/testdata/bundles/bundle-with-image/porter.yaml @@ -0,0 +1,34 @@ +schemaVersion: 1.0.0-alpha.1 +name: mybun +version: 0.1.0 +description: "An example Porter configuration" +registry: "localhost:5000" + +images: + mybun: + image: "docker.io/getporter/porter-hello" + tag: "v0.1.1" + +mixins: + - exec + +install: + - exec: + description: "Install Hello World" + command: ./helpers.sh + arguments: + - install + +upgrade: + - exec: + description: "Upgrade Hello World" + command: ./helpers.sh + arguments: + - upgrade + +uninstall: + - exec: + description: "Uninstall Hello World" + command: ./helpers.sh + arguments: + - uninstall diff --git a/tests/testdata/embeddedimg/.dockerignore b/tests/testdata/embeddedimg/.dockerignore new file mode 100644 index 000000000..3e393c257 --- /dev/null +++ b/tests/testdata/embeddedimg/.dockerignore @@ -0,0 +1,4 @@ +# See https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Put files here that you don't want copied into your bundle image +.gitignore +Dockerfile.tmpl diff --git a/tests/testdata/embeddedimg/.gitignore b/tests/testdata/embeddedimg/.gitignore new file mode 100644 index 000000000..e08a3e22b --- /dev/null +++ b/tests/testdata/embeddedimg/.gitignore @@ -0,0 +1 @@ +.cnab/ diff --git a/tests/testdata/embeddedimg/connection-string.txt b/tests/testdata/embeddedimg/connection-string.txt new file mode 100644 index 000000000..c7b8c1f11 --- /dev/null +++ b/tests/testdata/embeddedimg/connection-string.txt @@ -0,0 +1 @@ +this is a connection string \ No newline at end of file diff --git a/tests/testdata/embeddedimg/porter.yaml b/tests/testdata/embeddedimg/porter.yaml new file mode 100644 index 000000000..1d2d46a94 --- /dev/null +++ b/tests/testdata/embeddedimg/porter.yaml @@ -0,0 +1,69 @@ +# This is a test bundle that can be used as a dependency + +schemaVersion: 1.0.1 +name: embeddedimg +version: 0.1.0 +description: "A test bundle dependency" +registry: localhost:5000 + +images: + alpine: + description: Alpine image + repository: alpine + imageType: docker + tag: 3.20.3 + +parameters: + - name: database + type: string + default: "(default)" + +outputs: + - name: connStr + type: file + path: /cnab/app/connection-string.txt + applyTo: + - install + - upgrade + +mixins: + - exec + +dry-run: + - exec: + command: echo + arguments: + - "ready to install mydb" + +install: + - exec: + command: echo + arguments: + - "installing mydb" + - exec: + command: echo + arguments: + - "database: ${ bundle.parameters.database }" + - exec: + description: "Debug" + command: echo + arguments: + - "image:${ bundle.installerImage }" + +status: + - exec: + command: echo + arguments: + - "mydb is looking great!" + +upgrade: + - exec: + command: echo + arguments: + - "upgrading mydb" + +uninstall: + - exec: + command: echo + arguments: + - "uninstalling mydb" diff --git a/tests/testdata/helpers.go b/tests/testdata/helpers.go index fd5cc03f5..c4f849f44 100644 --- a/tests/testdata/helpers.go +++ b/tests/testdata/helpers.go @@ -36,4 +36,7 @@ const ( // MyAppRef is the full reference to the myapp test bundle. MyAppRef = "localhost:5000/myapp:v1.2.3" + + // EmbeddedImg is the test bundle that exercies embedded images. + EmbeddedImg = "embeddedimg" ) diff --git a/tests/tester/helpers.go b/tests/tester/helpers.go index 10d3fb92c..6b8a1c60a 100644 --- a/tests/tester/helpers.go +++ b/tests/tester/helpers.go @@ -15,6 +15,14 @@ import ( "github.com/stretchr/testify/require" ) +type TestBundleOptions struct { + PreserveTags bool +} + +func PreserveTags(opts *TestBundleOptions) { + opts.PreserveTags = true +} + // PrepareTestBundle ensures that the mybuns test bundle is ready to use. func (t Tester) PrepareTestBundle() { // Build and publish an interesting test bundle and its dependency @@ -34,24 +42,31 @@ func (t Tester) ApplyTestBundlePrerequisites() { t.RequirePorter("credentials", "apply", filepath.Join(t.RepoRoot, "tests/testdata/creds/mybuns.yaml"), "--namespace=") } -func (t Tester) MakeTestBundle(name string, ref string) { - // Skip if we've already pushed it for another test +func (t Tester) MakeTestBundle(name string, ref string, options ...func(*TestBundleOptions)) { + opts := TestBundleOptions{} + for _, option := range options { + option(&opts) + } + if _, _, err := t.RunPorter("explain", ref); err == nil { return } - pwd, _ := os.Getwd() defer t.Chdir(pwd) t.Chdir(filepath.Join(t.RepoRoot, "tests/testdata/", name)) - - // TODO(carolynvs): porter publish detection of needing a build should do this output, err := shx.OutputS("docker", "inspect", strings.Replace(ref, name, name+"-installer", 1)) if output == "[]" || err != nil { - t.RequirePorter("build") + cmd := []string{"build"} + if opts.PreserveTags { + cmd = append(cmd, "--preserve-tags") + } + t.RequirePorter(cmd...) } - - // Rely on the auto build functionality to avoid long slow rebuilds when nothing has changed - t.RequirePorter("publish", "--reference", ref) + cmd := []string{"publish", "--reference", ref, "--verbosity", "debug"} + if opts.PreserveTags { + cmd = append(cmd, "--preserve-tags") + } + t.RequirePorter(cmd...) } func (t Tester) ShowInstallation(namespace string, name string) (porter.DisplayInstallation, error) { From 2f6b0e2640d5618a19bfffe9b19cbf140a1a9670 Mon Sep 17 00:00:00 2001 From: Kim Christensen Date: Thu, 10 Oct 2024 22:26:17 +0200 Subject: [PATCH 2/2] Make unstable unit test stable Signed-off-by: Kim Christensen --- pkg/runtime/runtime_manifest_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/runtime/runtime_manifest_test.go b/pkg/runtime/runtime_manifest_test.go index 02d54be08..6ee6fc818 100644 --- a/pkg/runtime/runtime_manifest_test.go +++ b/pkg/runtime/runtime_manifest_test.go @@ -329,11 +329,11 @@ install: require.Len(t, args, 3) assert.Equal(t, "deliciou$dubonnet", args[0]) - assert.Equal(t, "{\"secret\":\"this_is_secret\"}", args[1]) + assert.Equal(t, "{\"secret\":\"this_is_secret\"}", args[1]) assert.Equal(t, "regular param value", args[2]) // There should now be one sensitive value tracked under the manifest - assert.Equal(t, []string{"deliciou$dubonnet", "{\"secret\":\"this_is_secret\"}"}, rm.GetSensitiveValues()) + assert.ElementsMatch(t, []string{"deliciou$dubonnet", "{\"secret\":\"this_is_secret\"}"}, rm.GetSensitiveValues()) } func TestResolveCredential(t *testing.T) {