github.com/google/osv-scalibr@v0.4.1/detector/cis/generic_linux/etcpasswdpermissions/etcpasswdpermissions_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 etcpasswdpermissions_test
    16  
    17  import (
    18  	"io/fs"
    19  	"runtime"
    20  	"slices"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/google/go-cmp/cmp/cmpopts"
    25  	"github.com/google/osv-scalibr/detector/cis/generic_linux/etcpasswdpermissions"
    26  	"github.com/google/osv-scalibr/extractor"
    27  	scalibrfs "github.com/google/osv-scalibr/fs"
    28  	"github.com/google/osv-scalibr/inventory"
    29  	"github.com/google/osv-scalibr/packageindex"
    30  )
    31  
    32  // A fake implementation of fs.FS where the only file is /etc/passwd and it has configurable permissions.
    33  type fakeFS struct {
    34  	exists bool
    35  	perms  fs.FileMode
    36  	uid    uint32
    37  	gid    uint32
    38  }
    39  
    40  func TestScan(t *testing.T) {
    41  	if !slices.Contains([]string{"linux"}, runtime.GOOS) {
    42  		t.Skipf("Skipping test for unsupported OS %q", runtime.GOOS)
    43  	}
    44  
    45  	wantTitle := "Ensure permissions on /etc/passwd are configured"
    46  	wantDesc := "The /etc/passwd file contains user account information that " +
    47  		"is used by many system utilities and therefore must be readable for these " +
    48  		"utilities to operate."
    49  	wantRec := "Run the following command to set permissions on /etc/passwd :\n" +
    50  		"# chown root:root /etc/passwd\n" +
    51  		"# chmod 644 /etc/passwd"
    52  	wantAdv := &inventory.GenericFindingAdvisory{
    53  		ID: &inventory.AdvisoryID{
    54  			Publisher: "CIS",
    55  			Reference: "etc-passwd-permissions",
    56  		},
    57  		Title:          wantTitle,
    58  		Description:    wantDesc,
    59  		Recommendation: wantRec,
    60  		Sev:            inventory.SeverityMinimal,
    61  	}
    62  
    63  	px, _ := packageindex.New([]*extractor.Package{})
    64  	testCases := []struct {
    65  		desc         string
    66  		fsys         scalibrfs.FS
    67  		wantFindings []*inventory.GenericFinding
    68  		wantErr      error
    69  	}{
    70  		{
    71  			desc:         "File doesn't exist",
    72  			fsys:         &fakeFS{exists: false},
    73  			wantFindings: nil,
    74  		},
    75  		{
    76  			desc:         "Permissions correct",
    77  			fsys:         &fakeFS{exists: true, perms: 0644, uid: 0, gid: 0},
    78  			wantFindings: nil,
    79  		},
    80  		{
    81  			desc: "Permissions_incorrect",
    82  			fsys: &fakeFS{exists: true, perms: 0777, uid: 0, gid: 0},
    83  			wantFindings: []*inventory.GenericFinding{{
    84  				Adv: wantAdv,
    85  				Target: &inventory.GenericFindingTargetDetails{
    86  					Extra: "/etc/passwd: file permissions 777, expected 644\n",
    87  				},
    88  			}},
    89  		},
    90  		{
    91  			desc: "Permissions_and_uid_incorrect",
    92  			fsys: &fakeFS{exists: true, perms: 0777, uid: 10, gid: 0},
    93  			wantFindings: []*inventory.GenericFinding{{
    94  				Adv: wantAdv,
    95  				Target: &inventory.GenericFindingTargetDetails{
    96  					Extra: "/etc/passwd: file permissions 777, expected 644\nfile owner 10, expected 0/root\n",
    97  				},
    98  			}},
    99  		},
   100  		{
   101  			desc: "Permissions_and_gid_incorrect",
   102  			fsys: &fakeFS{exists: true, perms: 0777, uid: 0, gid: 10},
   103  			wantFindings: []*inventory.GenericFinding{{
   104  				Adv: wantAdv,
   105  				Target: &inventory.GenericFindingTargetDetails{
   106  					Extra: "/etc/passwd: file permissions 777, expected 644\nfile group 10, expected 0/root\n",
   107  				},
   108  			}},
   109  		},
   110  	}
   111  
   112  	for _, tc := range testCases {
   113  		t.Run(tc.desc, func(t *testing.T) {
   114  			det := etcpasswdpermissions.Detector{}
   115  			got, err := det.Scan(t.Context(), &scalibrfs.ScanRoot{FS: tc.fsys}, px)
   116  			findings := got.GenericFindings
   117  			if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" {
   118  				t.Errorf("detector.Scan(%v): unexpected error (-want +got):\n%s", tc.fsys, diff)
   119  			}
   120  			if diff := cmp.Diff(tc.wantFindings, findings); diff != "" {
   121  				t.Errorf("detector.Scan(%v): unexpected findings (-want +got):\n%s", tc.fsys, diff)
   122  			}
   123  		})
   124  	}
   125  }