Skip to content

Commit

Permalink
fix: remove trailing dashes for multidoc yaml
Browse files Browse the repository at this point in the history
Fixes #1330 #1296

Signed-off-by: Tim Heurich <[email protected]>
  • Loading branch information
theurichde committed Sep 22, 2023
1 parent 52e2e55 commit 0ccf1ba
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 25 deletions.
34 changes: 19 additions & 15 deletions pkg/kubeseal/kubeseal.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func Seal(clientConfig ClientConfig, outputFormat string, in io.Reader, out io.W
return err
}

for _, secret := range secrets {
for pos, secret := range secrets {
if len(secret.Data) == 0 && len(secret.StringData) == 0 && !allowEmptyData {
return fmt.Errorf("secret.data is empty in input Secret, assuming this is an error and aborting. To work with empty data, --allow-empty-data can be used")
}
Expand Down Expand Up @@ -270,14 +270,18 @@ func Seal(clientConfig ClientConfig, outputFormat string, in io.Reader, out io.W
if err != nil {
return err
}
if err = sealedSecretOutput(out, outputFormat, codecs, ssecret); err != nil {
if err = sealedSecretOutput(out, outputFormat, codecs, ssecret, needsSeparator(pos, len(secrets))); err != nil {
return err
}
//return nil
}
return nil
}

func needsSeparator(position, length int) bool {
return position > 0 && position < length
}

func ValidateSealedSecret(ctx context.Context, clientConfig ClientConfig, controllerNs, controllerName string, in io.Reader) error {
conf, err := clientConfig.ClientConfig()
if err != nil {
Expand Down Expand Up @@ -351,7 +355,7 @@ func ReEncryptSealedSecret(ctx context.Context, clientConfig ClientConfig, contr
return err
}

for _, secret := range secrets {
for pos, secret := range secrets {
content, err := json.Marshal(secret)
if err != nil {
return err
Expand All @@ -375,20 +379,26 @@ func ReEncryptSealedSecret(ctx context.Context, clientConfig ClientConfig, contr
ssecret.SetCreationTimestamp(metav1.Time{})
ssecret.SetDeletionTimestamp(nil)
ssecret.Generation = 0
if err = sealedSecretOutput(out, outputFormat, codecs, ssecret); err != nil {
if err = sealedSecretOutput(out, outputFormat, codecs, ssecret, needsSeparator(pos, len(secrets))); err != nil {
return err
}
}
return nil
}

func resourceOutput(out io.Writer, outputFormat string, codecs runtimeserializer.CodecFactory, gv runtime.GroupVersioner, obj runtime.Object) error {
func resourceOutput(out io.Writer, outputFormat string, codecs runtimeserializer.CodecFactory, gv runtime.GroupVersioner, obj runtime.Object, needsSeparator bool) error {
var contentType string
switch strings.ToLower(outputFormat) {
case "json", "":
contentType = runtime.ContentTypeJSON
if needsSeparator {
fmt.Fprint(out, "\n")
}
case "yaml":
contentType = runtime.ContentTypeYAML
if needsSeparator {
fmt.Fprint(out, "---\n")
}
default:
return fmt.Errorf("unsupported output format: %s", outputFormat)
}
Expand All @@ -402,17 +412,11 @@ func resourceOutput(out io.Writer, outputFormat string, codecs runtimeserializer
}
_, _ = out.Write(buf)

switch contentType {
case runtime.ContentTypeJSON:
fmt.Fprint(out, "\n")
case runtime.ContentTypeYAML:
fmt.Fprint(out, "---\n")
}
return nil
}

func sealedSecretOutput(out io.Writer, outputFormat string, codecs runtimeserializer.CodecFactory, ssecret *ssv1alpha1.SealedSecret) error {
return resourceOutput(out, outputFormat, codecs, ssv1alpha1.SchemeGroupVersion, ssecret)
func sealedSecretOutput(out io.Writer, outputFormat string, codecs runtimeserializer.CodecFactory, ssecret *ssv1alpha1.SealedSecret, needsSeparator bool) error {
return resourceOutput(out, outputFormat, codecs, ssv1alpha1.SchemeGroupVersion, ssecret, needsSeparator)
}

func decodeSealedSecret(codecs runtimeserializer.CodecFactory, b []byte) (*ssv1alpha1.SealedSecret, error) {
Expand Down Expand Up @@ -468,7 +472,7 @@ func SealMergingInto(clientConfig ClientConfig, outputFormat string, in io.Reade

// updated sealed secret file in-place avoiding clobbering the file upon rendering errors.
var out bytes.Buffer
if err := sealedSecretOutput(&out, outputFormat, codecs, orig); err != nil {
if err := sealedSecretOutput(&out, outputFormat, codecs, orig, false); err != nil {
return err
}

Expand Down Expand Up @@ -619,5 +623,5 @@ func UnsealSealedSecret(w io.Writer, in io.Reader, privKeysFilenames []string, o
return err
}

return resourceOutput(w, outputFormat, codecs, v1.SchemeGroupVersion, sec)
return resourceOutput(w, outputFormat, codecs, v1.SchemeGroupVersion, sec, false)
}
36 changes: 26 additions & 10 deletions pkg/kubeseal/kubeseal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"regexp"
goruntime "runtime"
"strings"
"testing"
Expand Down Expand Up @@ -187,30 +188,44 @@ func TestSealWithMultiDocSecrets(t *testing.T) {
}

testCases := []struct {
name string
asYaml bool
inputSeparator string
outputFormat string
name string
asYaml bool
inputSeparator string
outputFormat string
checkTrailingChars func(t *testing.T, outBytes []byte)
}{
{
name: "multi-doc json",
asYaml: false,
inputSeparator: "\n",
outputFormat: "json",
checkTrailingChars: func(t *testing.T, outBytes []byte) {
endWithTrailingNewLine, _ := regexp.Compile("(\n)\n?$")
if endWithTrailingNewLine.Match(outBytes) {
t.Errorf("output should not end with trailing new line")
}
},
},
{
name: "multi-doc yaml",
asYaml: true,
inputSeparator: "---\n",
outputFormat: "yaml",
checkTrailingChars: func(t *testing.T, outBytes []byte) {
endWithDashes, _ := regexp.Compile("---(\n)?$")
if endWithDashes.Match(outBytes) {
t.Errorf("output should not end with dashes")
}
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s1 := mkTestSecret(t, "foo", "1", withSecretName("s1"), asYAML(tc.asYaml))
s2 := mkTestSecret(t, "bar", "2", withSecretName("s2"), asYAML(tc.asYaml))
multiDocYaml := fmt.Sprintf("%s%s%s", s1, tc.inputSeparator, s2)
s3 := mkTestSecret(t, "foobar", "3", withSecretName("s3"), asYAML(tc.asYaml))
multiDocYaml := fmt.Sprintf("%s%s%s%s%s", s1, tc.inputSeparator, s2, tc.inputSeparator, s3)

clientConfig := testClientConfig()
outputFormat := tc.outputFormat
Expand All @@ -220,15 +235,15 @@ func TestSealWithMultiDocSecrets(t *testing.T) {
t.Fatalf("Error writing to buffer: %v", err)
}

t.Logf("input is: %s", inbuf.String())
t.Logf("input is:\n%s", inbuf.String())

outbuf := bytes.Buffer{}
if err := Seal(clientConfig, outputFormat, &inbuf, &outbuf, scheme.Codecs, key, ssv1alpha1.NamespaceWideScope, false, "", ""); err != nil {
t.Fatalf("seal() returned error: %v", err)
}

outBytes := outbuf.Bytes()
t.Logf("output is %s", outBytes)
t.Logf("output is:\n%s", outBytes)

decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(outBytes), 4096)
var gotSecrets []*ssv1alpha1.SealedSecret
Expand All @@ -244,18 +259,19 @@ func TestSealWithMultiDocSecrets(t *testing.T) {
gotSecrets = append(gotSecrets, &s)
}

if got, want := len(gotSecrets), 2; got != want {
if got, want := len(gotSecrets), 3; got != want {
t.Errorf("Wrong element output length: got: %d, want: %d", got, want)
}

for _, gotSecret := range gotSecrets {
if got, want := gotSecret.GetNamespace(), "testns"; got != want {
t.Errorf("got: %q, want: %q", got, want)
}
if got, want := gotSecret.GetName(), []string{"s1", "s2"}; !slices.Contains(want, got) {
if got, want := gotSecret.GetName(), []string{"s1", "s2", "s3"}; !slices.Contains(want, got) {
t.Errorf("got: %q, want: %q", got, want)
}
}
tc.checkTrailingChars(t, outBytes)
})
}
}
Expand Down Expand Up @@ -959,7 +975,7 @@ func TestReadPrivKeySecret(t *testing.T) {
}
// defer os.RemoveAll(tmp.Name())

if err := resourceOutput(tmp, outputFormat, scheme.Codecs, v1.SchemeGroupVersion, sec); err != nil {
if err := resourceOutput(tmp, outputFormat, scheme.Codecs, v1.SchemeGroupVersion, sec, false); err != nil {
t.Fatal(err)
}
tmp.Close()
Expand Down

0 comments on commit 0ccf1ba

Please sign in to comment.