Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type Options struct {
ScaleFromZeroCreds string
ScaleFromZeroCredentialsSecret string
ScaleFromZeroCredentialsSecretKey string
RenderSensitive bool
}

func (o *Options) Validate() error {
Expand Down
18 changes: 18 additions & 0 deletions cmd/install/install_render.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
hyperapi "github.com/openshift/hypershift/support/api"
"github.com/openshift/hypershift/support/config"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
Expand Down Expand Up @@ -69,6 +70,7 @@ func NewRenderCommand(opts *Options) *cobra.Command {
cmd.Flags().StringVar(&opts.Format, "format", RenderFormatYaml, fmt.Sprintf("Output format for the manifests, supports %s and %s", RenderFormatYaml, RenderFormatJson))
cmd.Flags().StringVar(&opts.OutputTypes, "outputs", string(OutputAll), fmt.Sprintf("Which manifests to output, one of %s, %s, or %s. Output CRDs separately to allow applying them first and waiting for them to be established.", OutputAll, OutputCRDs, OutputResources))
cmd.Flags().StringVar(&opts.OutputFile, "output-file", "", "File to write the rendered manifests to. Writes to STDOUT if not specified.")
cmd.Flags().BoolVar(&opts.RenderSensitive, "render-sensitive", false, "Render secrets in the output. By default secrets are excluded to avoid leaking private key material into GitOps repositories")
cmd.MarkFlagsMutuallyExclusive("template", "outputs")

cmd.RunE = func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -103,6 +105,10 @@ func RenderHyperShiftOperator(ctx context.Context, cmdOut io.Writer, opts *Optio
return err
}

if opts.Template && !opts.RenderSensitive {
return fmt.Errorf("--template requires --render-sensitive=true because Template output can embed Secret objects")
}

var crds []crclient.Object
var objects []crclient.Object

Expand All @@ -129,6 +135,18 @@ func RenderHyperShiftOperator(ctx context.Context, cmdOut io.Writer, opts *Optio
case OutputResources:
objectsToRender = objects
}

if !opts.RenderSensitive {
filtered := make([]crclient.Object, 0, len(objectsToRender))
for _, obj := range objectsToRender {
if _, isSecret := obj.(*corev1.Secret); isSecret {
continue
}
filtered = append(filtered, obj)
}
objectsToRender = filtered
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

var out io.Writer
if opts.OutputFile != "" {
file, err := os.Create(opts.OutputFile)
Expand Down
15 changes: 13 additions & 2 deletions cmd/install/install_render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func TestMultiDocYamlRendering(t *testing.T) {
}

func TestTemplateYamlRendering(t *testing.T) {
template, err := ExecuteTemplateYamlGenerationCommand([]string{"--oidc-storage-provider-s3-bucket-name", "bucket", "--oidc-storage-provider-s3-region", "us-east-1", "--oidc-storage-provider-s3-secret", "secret", "render", "--format", "yaml", "--template"})
template, err := ExecuteTemplateYamlGenerationCommand([]string{"--oidc-storage-provider-s3-bucket-name", "bucket", "--oidc-storage-provider-s3-region", "us-east-1", "--oidc-storage-provider-s3-secret", "secret", "render", "--format", "yaml", "--template", "--render-sensitive"})
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -104,6 +104,17 @@ func ExecuteJsonGenerationCommand(args []string) (map[string]interface{}, error)
return doc, nil
}

func TestWhenTemplateWithoutRenderSensitiveItShouldFail(t *testing.T) {
_, err := ExecuteTestCommand([]string{"--oidc-storage-provider-s3-bucket-name", "bucket", "--oidc-storage-provider-s3-region", "us-east-1", "--oidc-storage-provider-s3-secret", "secret", "render", "--format", "yaml", "--template"})
if err == nil {
t.Fatal("expected error when using --template without --render-sensitive")
}
expectedMsg := "--template requires --render-sensitive=true because Template output can embed Secret objects"
if err.Error() != expectedMsg {
t.Fatalf("expected error message %q, got %q", expectedMsg, err.Error())
}
}

func TestJsonListRendering(t *testing.T) {
doc, err := ExecuteJsonGenerationCommand([]string{"--oidc-storage-provider-s3-bucket-name", "bucket", "--oidc-storage-provider-s3-region", "us-east-1", "--oidc-storage-provider-s3-secret", "secret", "render", "--format", "json"})
if err != nil {
Expand All @@ -120,7 +131,7 @@ func TestJsonListRendering(t *testing.T) {
}

func TestJsonTemplateRendering(t *testing.T) {
doc, err := ExecuteJsonGenerationCommand([]string{"--oidc-storage-provider-s3-bucket-name", "bucket", "--oidc-storage-provider-s3-region", "us-east-1", "--oidc-storage-provider-s3-secret", "secret", "render", "--format", "json", "--template"})
doc, err := ExecuteJsonGenerationCommand([]string{"--oidc-storage-provider-s3-bucket-name", "bucket", "--oidc-storage-provider-s3-region", "us-east-1", "--oidc-storage-provider-s3-secret", "secret", "render", "--format", "json", "--template", "--render-sensitive"})
if err != nil {
t.Fatal(err)
}
Expand Down
59 changes: 59 additions & 0 deletions cmd/install/install_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package install

import (
"bytes"
"context"
"io"
"io/fs"
Expand Down Expand Up @@ -490,6 +491,64 @@ func TestSetupCRDs(t *testing.T) {
}
}

func TestRenderHyperShiftOperator_RenderSensitive(t *testing.T) {
tests := []struct {
name string
renderSensitive bool
expectSecrets bool
}{
{
name: "When render-sensitive is false it should exclude secrets from output",
renderSensitive: false,
expectSecrets: false,
},
{
name: "When render-sensitive is true it should include secrets in output",
renderSensitive: true,
expectSecrets: true,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
g := NewGomegaWithT(t)

var buf bytes.Buffer
opts := &Options{
PrivatePlatform: string(hyperv1.NonePlatform),
EnableDefaultingWebhook: true,
EnableValidatingWebhook: true,
EnableConversionWebhook: true,
RenderSensitive: tc.renderSensitive,
Format: RenderFormatYaml,
OutputTypes: string(OutputAll),
}
err := RenderHyperShiftOperator(t.Context(), &buf, opts)
g.Expect(err).ToNot(HaveOccurred())

var secretNames []string
decodedCount := 0
for doc := range strings.SplitSeq(buf.String(), "\n---\n") {
if strings.TrimSpace(doc) == "" {
continue
}
obj, _, err := hyperapi.YamlSerializer.Decode([]byte(doc), nil, nil)
g.Expect(err).ToNot(HaveOccurred(), "failed to decode rendered manifest")
decodedCount++
if secret, ok := obj.(*corev1.Secret); ok {
secretNames = append(secretNames, secret.Name)
}
}
g.Expect(decodedCount).To(BeNumerically(">", 0), "expected rendered manifests to be decodable")
if tc.expectSecrets {
g.Expect(secretNames).ToNot(BeEmpty(), "expected secrets in rendered output")
} else {
g.Expect(secretNames).To(BeEmpty(), "expected no secrets in rendered output")
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
})
}
}

func TestHyperShiftOperatorManifests_SharedIngress(t *testing.T) {
tests := []struct {
name string
Expand Down