github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/secrets/onepasswordconnecttoken/onepasswordconnecttoken_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package onepasswordconnecttoken_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/google/go-cmp/cmp"
    21  	"github.com/google/go-cmp/cmp/cmpopts"
    22  	"github.com/google/osv-scalibr/extractor/filesystem/secrets/onepasswordconnecttoken"
    23  	"github.com/google/osv-scalibr/extractor/filesystem/simplefileapi"
    24  	"github.com/google/osv-scalibr/inventory"
    25  	"github.com/google/osv-scalibr/testing/extracttest"
    26  )
    27  
    28  func TestFileRequired(t *testing.T) {
    29  	tests := []struct {
    30  		name         string
    31  		path         string
    32  		wantRequired bool
    33  	}{
    34  		{
    35  			name:         "valid onepassword json file",
    36  			path:         "/project/onepassword-token.json",
    37  			wantRequired: true,
    38  		},
    39  		{
    40  			name:         "valid 1password json file",
    41  			path:         "/project/1password-config.json",
    42  			wantRequired: true,
    43  		},
    44  		{
    45  			name:         "onepassword uppercase",
    46  			path:         "/project/ONEPASSWORD-settings.json",
    47  			wantRequired: true,
    48  		},
    49  		{
    50  			name:         "invalid extension",
    51  			path:         "/project/onepassword-token.txt",
    52  			wantRequired: false,
    53  		},
    54  		{
    55  			name:         "no onepassword in name",
    56  			path:         "/project/config.json",
    57  			wantRequired: false,
    58  		},
    59  		{
    60  			name:         "not json file",
    61  			path:         "/tmp/var/scalibr",
    62  			wantRequired: false,
    63  		},
    64  	}
    65  	for _, tt := range tests {
    66  		t.Run(tt.name, func(t *testing.T) {
    67  			e := onepasswordconnecttoken.Extractor{}
    68  			if got := e.FileRequired(simplefileapi.New(tt.path, nil)); got != tt.wantRequired {
    69  				t.Fatalf("FileRequired(%s): got %v, want %v", tt.path, got, tt.wantRequired)
    70  			}
    71  		})
    72  	}
    73  }
    74  
    75  func TestExtract(t *testing.T) {
    76  	tests := []struct {
    77  		name            string
    78  		wantSecrets     []*inventory.Secret
    79  		inputConfigFile extracttest.ScanInputMockConfig
    80  	}{
    81  		{
    82  			name: "valid_onepassword_connect_token",
    83  			inputConfigFile: extracttest.ScanInputMockConfig{
    84  				Path: "testdata/valid",
    85  			},
    86  			wantSecrets: []*inventory.Secret{
    87  				{
    88  					Secret: onepasswordconnecttoken.OnePasswordConnectToken{
    89  						DeviceUUID:        "yrkdmusoblmgm6siuj4kcssxke",
    90  						Version:           "2",
    91  						EncryptedData:     "yQVzCjBZa5mRMHsT5DQF9y9NWR0oY1ZudueqUCuKEUm4agXFGagMLiZJgwX4zn8nCfhtEWgA0OUo10HlR-oMx6hpHw8QsW8Y3e61t0en40LHAzMwjIZtIn_NFKAzSAMJRU3sv4Kz70YsZZopK9Jsgx4czkCcYqgr-3KxVczVpBhsq6PhPYh-xsr8a2tDQ2_ZWYQgTyUH51vV0ZfNOH81Wa6M6Xc2uAtBLx3uxP7odK0h1CH6RhEmokX1lwPy8C5d0wKRF-DJGpzEUZ9wenic8BtDVO00rAOQJT1sUZM6YHPcxL6mco3kWhuXtPVHBcWbDPWWK-WHoRTI_qUKBg3yof-19Y9DBwT2ScwBFbssZgCcQ7pXy8GK_VP0n381zMDbD5w0ZD3qA58jYWTK36_ZWkbcFv_jG1rvk1O5DuGnlQT3cQxv9ELUKT6FB9qqvGjvkWZzKDfljHQ7QThlOzG5iVFYkWKXEAW60BOQmRwI4xikrPvf3KjywE2IFxliUWxt5AMHSWrknyEoHSLkpSThLDL4EhePptc9UBW6rkYhVsC6ZUkiOIIQ1hOBPRqctAteacuCGD1I9CI3x5CgnEL7TNPX_njDO_fkvQBJUBauLaPP7ObjyPDnWLOAKROELWjrFA",
    92  						EncryptionKeyID:   "localauthv2keykid",
    93  						IV:                "nHE-eIYl0_YgVo14",
    94  						UniqueKeyID:       "pol5dybe7lxax42ha6r7rwwdm4",
    95  						VerifierSalt:      "JD6cq4PDx8biZ_WIEo8sJQ",
    96  						VerifierLocalHash: "lLjGM419fBfty9S-a7BwXBLsl40QL0xWmReBF2r9hM8",
    97  					},
    98  					Location: "testdata/valid",
    99  				},
   100  			},
   101  		},
   102  		{
   103  			name: "invalid_json",
   104  			inputConfigFile: extracttest.ScanInputMockConfig{
   105  				Path: "testdata/invalid",
   106  			},
   107  			wantSecrets: nil,
   108  		},
   109  		{
   110  			name: "missing_required_fields",
   111  			inputConfigFile: extracttest.ScanInputMockConfig{
   112  				Path: "testdata/incomplete",
   113  			},
   114  			wantSecrets: nil,
   115  		},
   116  	}
   117  
   118  	for _, tt := range tests {
   119  		t.Run(tt.name, func(t *testing.T) {
   120  			extr := onepasswordconnecttoken.Extractor{}
   121  
   122  			scanInput := extracttest.GenerateScanInputMock(t, tt.inputConfigFile)
   123  			defer extracttest.CloseTestScanInput(t, scanInput)
   124  
   125  			got, err := extr.Extract(t.Context(), &scanInput)
   126  			if err != nil {
   127  				t.Fatalf("Extract() unexpected error = %v", err)
   128  			}
   129  
   130  			if tt.wantSecrets == nil {
   131  				// For invalid cases, we expect empty inventory
   132  				wantInv := inventory.Inventory{}
   133  				if diff := cmp.Diff(wantInv, got); diff != "" {
   134  					t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.inputConfigFile.Path, diff)
   135  				}
   136  				return
   137  			}
   138  
   139  			wantInv := inventory.Inventory{Secrets: tt.wantSecrets}
   140  			if diff := cmp.Diff(wantInv, got, cmpopts.IgnoreUnexported(onepasswordconnecttoken.OnePasswordConnectToken{})); diff != "" {
   141  				t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.inputConfigFile.Path, diff)
   142  			}
   143  		})
   144  	}
   145  }