github.com/verrazzano/verrazzano@v1.7.1/tools/vz/pkg/helpers/vzsanitize_test.go (about)

     1  // Copyright (c) 2022, 2024, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package helpers
     5  
     6  import (
     7  	"encoding/csv"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/verrazzano/verrazzano/tools/vz/pkg/constants"
    15  )
    16  
    17  var (
    18  	testIPToRemove           = "127.255.255.255"
    19  	testIP                   = "az0/:" + testIPToRemove + "l2/}"
    20  	testOCIDToRemove         = "ocid1.tenancy.oc1..a763cu5f3m7qpzwnvr2so2655cpzgxmglgtui3v7q"
    21  	testOCID                 = "az0/:" + testOCIDToRemove + "/}az"
    22  	testSSHToRemove          = "ssh-NewKey-Format9@. AAAAB3NzaCDo798PWwYniRpZ/DEKAapLQDfrHeR/OO59T4ZUr4ln/5EoUGYu1HRVWmvQx4wsKZRwl4u8pi9gYOW1pL/IYp3cumJef9Y99+/=foo @foo-mac z"
    23  	testSSH                  = "abcd/0: " + testSSHToRemove + "\n xYz123"
    24  	testSSHToRemovenoComment = "ssh-NewKey-Format9@. AAAAB3NzaCDo798PWwYniRpZ/DEKAapLQDfrHeR/OO59T4ZUr4ln/5EoUGYu1HRVWmvQx4wsKZRwl4u8pi9gYOW1pL/IYp3cumJef9Y99+/="
    25  	testSSHnoComment         = "abcd/0: " + testSSHToRemovenoComment + "\n xYz123"
    26  	testSSHToRemoveRSA       = "ssh-rsa AAAAB3NzaCDo798PWwYniRpZ/DEKAapLQDfrHeR/OO59T4ZUr4ln/5EoUGYu1HRVWmvQx4wsKZRwl4u8pi9gYOW1pL/IYp3cumJef9Y99+/=foo @foo-mac z"
    27  	testSSHrsa               = "abcd/0: " + testSSHToRemoveRSA + "\n xYz123"
    28  	testSSHToRemoveSk25519   = "sk-ssh-ed25519@openssh.com AAAAW2XXFA0S2f2tHUFyEb6ktadcbfO2MczKg7z/5EoUGYu1HRVWmvQx4wsKZRwl4u8pi9gYOW1pL/IYp3cumJef9Y99+/== z@dxy fyz-ru"
    29  	testSSHsk25519           = "abcd/0: " + testSSHToRemoveSk25519 + "\n xYz123"
    30  	testSSHToRemoveSkEcdsa   = "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNYniRpZ/DEKAapLQDfrHeR/OO59T4ZUr4ln/5EoUGYu1HRVWmvQx4wsKZRwl4u8pi9gYOW1pL/YniRpZ/DEKAapLQDfrHeR/OO59T4ZUr4ln/5EoUGYu1HRVWmvQx4wsKZRwl4u8pi9gYOW1pL/IYp3cumJef9Y99+/=== z@dxy fyz-ru"
    31  	testSSHskEcdsa           = "edcsa-abcd/0: " + testSSHToRemoveSkEcdsa + "\n xYz123"
    32  	testSSHToRemoveEcdsaSha2 = "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBADz1oA4gh3qZExdiS6krVOHXhh3KAMG9SHj1RqMXskDy2sTmO9mPF0P2HJfkm0OgCSMo3BZfvh2rh23fMfUI67gigAmOm41fGQ8B/K82sWj0LuskUR2TqRGQFwwWOVZYtUVtiboTg+XgL5fcGitxL+biT9LMTSOAiRw39cHmk6+B0kXBw== z@dxy fyz-ru"
    33  	testSSHecdsaSha2         = "ecdsa-abcd " + testSSHToRemoveEcdsaSha2 + "\n xYz123"
    34  	testSSHToRemoveEd25519   = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/PsfEX91dggIwWL4edgvgVgn4FJdtZd9ZFXXXXXXXX z@dxy fyz-ru"
    35  	testSSHed25519           = "ecdsa-abcd0 " + testSSHToRemoveEd25519 + "\n xYz123"
    36  	testSSHToRemoveDss       = "ssh-dss AAAAB3NzaC1kc3MAAACBAM6RtXQiwMnnreGmgpT9yinlWLFA8tycOT7or/7iXG06cp7BixJg65Xkl2zKXbq9/Sv+PAFfy7uK0ROSlya1IirMTDFWjMCXaOPwyHb+pM6uBA5UFQxQ9/I+KhWcfelqVVaGK36Xz7N8tCf+IwPvlkK4JeOnbmFfF0a3+nmlPsuXAAAAFQDFlq/WHwSVHlQXzBGRw6Kx7fbj6wAAAIAUZSEIPUFW7bKn8zQ7G7OXpIyMjxnWrpoDb38qTKyhcVrlMgH8cLb558SO/itTkLNRyNPLlSVuxM6qngm1jzPK0NzZbnVtxhTQjCbPmIml3nFjpXpJDUo7nXdR/Gzk15ffQTN/44cqkY/90x87ZgwqNLF8x44B1IUDyyG7NvTNcQAAAIEAy18U+7rh21k5pHBzOY0peZu/x/9/Cu7eJMFpmY7Za+XChjGHmuu2lw9xqebP3SQDIFyMQzXnV39bJXggAHPeGD+Rg2028PcF8w8veBh/+8OgQn+AyFinBRSir7huSApU223R+HvSMZsmXY9I9ycmVULOFy7/WLAcOXXXXX3ig1I= z@dxy fyz-ru"
    37  	testSSHdss               = "ssh-xyz " + testSSHToRemoveDss + "\n xYz123"
    38  	testUserDataToRemove     = "\"user_data\": \"abcABC012=+\""
    39  	testUserData             = "az0:/" + testUserDataToRemove + "az0:/"
    40  	testOPCIDToRemove        = "  a634bbc217b8188f263d98bc0b3d5c05/9AG80960E22B0EDFEFE506BA8D73DF3C/814906C375D7F4651B8A47987CCB4478"
    41  	testOPCID                = "\"message\": \"Request a service limit increase from the service limits page in the console. . http status code: 400. Opc request id:" + testOPCIDToRemove + "\", xyz123"
    42  
    43  	// Specifies the location and name of the CSV file written to by WriteRedactionMapFile for these tests.
    44  	redactMapFileLocation = os.TempDir()
    45  )
    46  
    47  // TestSanitizeALine tests the SanitizeString function.
    48  // GIVEN a variety of input strings,
    49  // WHEN I call SanitizeString,
    50  // THEN I expect the output strings to be properly sanitized.
    51  func TestSanitizeALine(t *testing.T) {
    52  	testRedactedValues := make(map[string]string)
    53  	strictCheck := func(message string, toRemove string) {
    54  		assert.Contains(t, message, toRemove, "The test case does not contain the expression to remove: "+toRemove)
    55  		i := strings.Index(message, toRemove)
    56  		sanitized := SanitizeString(message, testRedactedValues)
    57  		assert.NotContains(t, sanitized, toRemove, "Failed to remove expression from string: "+toRemove)
    58  		hashLength := (len(sanitized) - len(message)) + len(toRemove)
    59  		reconstructed := sanitized[:i] + toRemove + sanitized[i+hashLength:]
    60  		assert.Equal(t, message, reconstructed, "Extra character(s) removed from the message. Message: "+message+"\n reconstructed message: "+reconstructed)
    61  	}
    62  	strictCheck(testIP, testIPToRemove)
    63  	strictCheck(testOCID, testOCIDToRemove)
    64  	strictCheck(testSSH, testSSHToRemove)
    65  	strictCheck(testSSHnoComment, testSSHToRemovenoComment)
    66  	strictCheck(testSSHrsa, testSSHToRemoveRSA)
    67  	strictCheck(testSSHsk25519, testSSHToRemoveSk25519)
    68  	strictCheck(testSSHskEcdsa, testSSHToRemoveSkEcdsa)
    69  	strictCheck(testSSHecdsaSha2, testSSHToRemoveEcdsaSha2)
    70  	strictCheck(testSSHed25519, testSSHToRemoveEd25519)
    71  	strictCheck(testSSHdss, testSSHToRemoveDss)
    72  	strictCheck(testUserData, testUserDataToRemove)
    73  	strictCheck(testOPCID, testOPCIDToRemove)
    74  }
    75  
    76  // TestWriteRedactionMapFileEmpty tests that a CSV file is successfully created upon calling WriteRedactionMapFile.
    77  // GIVEN zero calls to the redact function,
    78  // WHEN I call WriteRedactionMapFile,
    79  // THEN I expect it to still successfully create a CSV file.
    80  func TestWriteRedactionMapFileEmpty(t *testing.T) {
    81  	a := assert.New(t)
    82  	testRedactedValues := make(map[string]string)
    83  	redactMapFilePath := filepath.Join(redactMapFileLocation, "empty-redaction-map.csv")
    84  
    85  	// Should create the CSV file
    86  	err := WriteRedactionMapFile(redactMapFilePath, testRedactedValues)
    87  	a.Nil(err)
    88  
    89  	// Open the file
    90  	f, err := os.Open(redactMapFilePath)
    91  	a.Nil(err)
    92  	defer f.Close()
    93  	defer os.Remove(f.Name())
    94  
    95  	// Check the file is empty
    96  	reader := csv.NewReader(f)
    97  	data, err := reader.ReadAll()
    98  	a.Nil(err)
    99  	a.Zero(len(data))
   100  }
   101  
   102  // TestWriteRedactionMapFile tests that WriteRedactionMapFile correctly writes redacted string mapping to a CSV file.
   103  // GIVEN a few calls to the redact function,
   104  // WHEN I call WriteRedactionMapFile,
   105  // THEN I expect it create a CSV file which contains mappings for all the previously redacted strings.
   106  func TestWriteRedactionMapFile(t *testing.T) {
   107  	a := assert.New(t)
   108  	testRedactedValues := make(map[string]string)
   109  	redactMapFilePath := filepath.Join(redactMapFileLocation, "test-redaction-map.csv")
   110  
   111  	// redact a variety of inputs, as well as inputting a value more than once.
   112  	testInputs := []string{testIP, testOCID, testSSH, testUserData, testOPCID, testIP}
   113  	for _, input := range testInputs {
   114  		redact(input, testRedactedValues)
   115  	}
   116  	numUniqueInputs := 5
   117  	a.Len(testRedactedValues, numUniqueInputs)
   118  
   119  	// write the redacted values to the CSV file
   120  	err := WriteRedactionMapFile(redactMapFilePath, testRedactedValues)
   121  	a.Nil(err)
   122  
   123  	// open the file
   124  	f, err := os.Open(redactMapFilePath)
   125  	a.Nil(err)
   126  	defer f.Close()
   127  	defer os.Remove(f.Name())
   128  
   129  	// read the file line by line
   130  	numLines := 0
   131  	reader := csv.NewReader(f)
   132  	record, err := reader.Read()
   133  	for record != nil {
   134  		numLines++
   135  		a.Nil(err)
   136  
   137  		// check that this line of the CSV file is as expected
   138  		hash, found := testRedactedValues[record[1]]
   139  		a.True(found)
   140  		a.Equal(record[0], hash)
   141  
   142  		record, err = reader.Read()
   143  	}
   144  
   145  	// expected number of lines in the csv
   146  	a.Equal(numUniqueInputs, numLines)
   147  }
   148  
   149  // TestRedact tests the redact function.
   150  // WHEN I call redact on various input strings,
   151  // THEN the output redacted strings should follow a specific format.
   152  func TestRedact(t *testing.T) {
   153  	a := assert.New(t)
   154  	testRedactedValues := make(map[string]string)
   155  
   156  	// test that redacting the same value repeatedly returns the same value
   157  	redactedIP := redact(testIP, testRedactedValues)
   158  	a.Contains(redactedIP, constants.RedactionPrefix)
   159  	a.NotContains(redactedIP, testIP)
   160  	for i := 0; i < 2; i++ {
   161  		r := redact(testIP, testRedactedValues)
   162  		a.Equal(redactedIP, r)
   163  	}
   164  
   165  	// test a redacting a different value
   166  	redactedSSH := redact(testSSH, testRedactedValues)
   167  	a.Contains(redactedSSH, constants.RedactionPrefix)
   168  	a.NotContains(redactedSSH, testSSH)
   169  	a.NotEqual(redactedSSH, redactedIP)
   170  
   171  	// test redacting the same value yet again returns the same value
   172  	r := redact(testIP, testRedactedValues)
   173  	a.Equal(redactedIP, r)
   174  }