github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/misc/chrome/extensions/extensions_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 extensions_test 16 17 import ( 18 "runtime" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/go-cmp/cmp/cmpopts" 23 "github.com/google/osv-scalibr/extractor" 24 "github.com/google/osv-scalibr/extractor/filesystem/misc/chrome/extensions" 25 "github.com/google/osv-scalibr/extractor/filesystem/simplefileapi" 26 "github.com/google/osv-scalibr/purl" 27 "github.com/google/osv-scalibr/testing/extracttest" 28 ) 29 30 func TestExtractor_FileRequired(t *testing.T) { 31 tests := []struct { 32 inputPath string 33 want bool 34 GOOS string 35 }{ 36 {inputPath: "", want: false}, 37 {GOOS: "windows", inputPath: `%LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\version\manifest.json`, want: true}, 38 {GOOS: "windows", inputPath: `%LOCALAPPDATA%\Google\Chrome Beta\User Data\Default\Extensions\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\version\manifest.json`, want: true}, 39 {GOOS: "windows", inputPath: `%LOCALAPPDATA%\Google\Chrome SxS\User Data\Default\Extensions\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\version\manifest.json`, want: true}, 40 {GOOS: "windows", inputPath: `%LOCALAPPDATA%\Google\Chrome for Testing\User Data\Default\Extensions\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\version\manifest.json`, want: true}, 41 {GOOS: "windows", inputPath: `%LOCALAPPDATA%\Chromium\User Data\Default\Extensions\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\version\manifest.json`, want: true}, 42 43 {GOOS: "windows", inputPath: `%LOCALAPPDATA%\Chromium\User Data\Default\Extensions\invalid-id\version\manifest.json`, want: false}, 44 {GOOS: "windows", inputPath: `%LOCALAPPDATA%\Chromium\User Data\Default\Extensions\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bad\path\manifest.json`, want: false}, 45 46 {GOOS: "darwin", inputPath: `~/Library/Application Support/Google/Chrome/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 47 {GOOS: "darwin", inputPath: `~/Library/Application Support/Google/Chrome Beta/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 48 {GOOS: "darwin", inputPath: `~/Library/Application Support/Google/Chrome Canary/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 49 {GOOS: "darwin", inputPath: `~/Library/Application Support/Google/Chrome for Testing/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 50 {GOOS: "darwin", inputPath: `~/Library/Application Support/Chromium/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 51 {GOOS: "darwin", inputPath: `/Users/username/Library/Application Support/Google/Chrome/Default/Extensions/aapbdbdomjkkjkaonfhkkikfgjllcleb/1.0.0.6_0/manifest.json`, want: true}, 52 53 {GOOS: "darwin", inputPath: `~/Library/Application Support/Chromium/Default/Extensions/invalid-id/version/manifest.json`, want: false}, 54 {GOOS: "darwin", inputPath: `~/Library/Application Support/Chromium/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bad/path/manifest.json`, want: false}, 55 56 {GOOS: "linux", inputPath: `~/.config/google-chrome/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 57 {GOOS: "linux", inputPath: `~/.config/google-chrome-beta/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 58 {GOOS: "linux", inputPath: `~/.config/google-chrome-unstable/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 59 {GOOS: "linux", inputPath: `~/.config/google-chrome-for-testing/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 60 {GOOS: "linux", inputPath: `~/.config/chromium/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/version/manifest.json`, want: true}, 61 62 {GOOS: "linux", inputPath: `~/.config/chromium/Default/Extensions/invalid-id/version/manifest.json`, want: false}, 63 {GOOS: "linux", inputPath: `~/.config/chromium/Default/Extensions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bad/path/manifest.json`, want: false}, 64 } 65 for _, tt := range tests { 66 t.Run(tt.inputPath, func(t *testing.T) { 67 if tt.GOOS != "" && tt.GOOS != runtime.GOOS { 68 t.Skipf("Skipping test for unsupported OS %q", runtime.GOOS) 69 } 70 e := extensions.Extractor{} 71 got := e.FileRequired(simplefileapi.New(tt.inputPath, nil)) 72 if got != tt.want { 73 t.Errorf("FileRequired(%s) got = %v, want %v", tt.inputPath, got, tt.want) 74 } 75 }) 76 } 77 } 78 79 func TestExtractor_Extract(t *testing.T) { 80 tests := []extracttest.TestTableEntry{ 81 { 82 Name: "invalid manifest", 83 InputConfig: extracttest.ScanInputMockConfig{ 84 Path: "testdata/invalid-manifest.json", 85 }, 86 WantErr: extracttest.ContainsErrStr{Str: "bad format"}, 87 }, 88 { 89 Name: "no locale specified", 90 InputConfig: extracttest.ScanInputMockConfig{ 91 Path: "testdata/caaadbdomjkkjkaonfhkkikfgjllcleb/1.2.85/manifest.json", 92 }, 93 WantPackages: []*extractor.Package{ 94 { 95 Name: "caaadbdomjkkjkaonfhkkikfgjllcleb", 96 Version: "1.2.85", 97 PURLType: purl.TypeGeneric, 98 Metadata: &extensions.Metadata{ 99 Description: "A decentralized wallet for blockchain transactions.", 100 HostPermissions: []string{"file://*/*", "http://*/*", "https://*/*"}, 101 ManifestVersion: 3, 102 Name: "CryptoX Blockchain Wallet", 103 Permissions: []string{"storage", "tabs", "alarms"}, 104 UpdateURL: "https://clients2.google.com/service/update2/crx", 105 }, 106 }, 107 }, 108 }, 109 { 110 Name: "default locale specified but no message file provided", 111 InputConfig: extracttest.ScanInputMockConfig{ 112 Path: "testdata/nolocaleoekpmoecnnnilnnbdlolhkhi/1.89.1/manifest.json", 113 }, 114 WantErr: extracttest.ContainsErrStr{Str: "could not extract locale info"}, 115 }, 116 { 117 Name: "locale specified", 118 InputConfig: extracttest.ScanInputMockConfig{ 119 Path: "testdata/ghbmnnjooekpmoecnnnilnnbdlolhkhi/1.89.1/manifest.json", 120 }, 121 WantPackages: []*extractor.Package{ 122 { 123 Name: "ghbmnnjooekpmoecnnnilnnbdlolhkhi", 124 Version: "1.89.1", 125 PURLType: purl.TypeGeneric, 126 Metadata: &extensions.Metadata{ 127 AuthorEmail: "docs-hosted-app-own@google.com", 128 Description: "Edit, create, and view your documents, spreadsheets, and presentations — all without internet access.", 129 HostPermissions: []string{"https://docs.google.com/*", "https://drive.google.com/*"}, 130 ManifestVersion: 3, 131 MinimumChromeVersion: "88", 132 Name: "Google Docs Offline", 133 Permissions: []string{"alarms", "storage", "unlimitedStorage", "offscreen"}, 134 UpdateURL: "https://clients2.google.com/service/update2/crx", 135 }, 136 }, 137 }, 138 }, 139 } 140 141 for _, tt := range tests { 142 t.Run(tt.Name, func(t *testing.T) { 143 extr := extensions.Extractor{} 144 145 scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig) 146 defer extracttest.CloseTestScanInput(t, scanInput) 147 148 got, err := extr.Extract(t.Context(), &scanInput) 149 150 if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" { 151 t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 152 return 153 } 154 155 if diff := cmp.Diff(tt.WantPackages, got.Packages, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" { 156 t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 157 } 158 }) 159 } 160 }