go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/updates/mac_updates.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package updates
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"strings"
    10  
    11  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    12  	"howett.net/plist"
    13  )
    14  
    15  const (
    16  	MacosUpdateFormat = "macos"
    17  )
    18  
    19  type MacosUpdateManager struct {
    20  	conn shared.Connection
    21  }
    22  
    23  func (um *MacosUpdateManager) Name() string {
    24  	return "macOS Update Manager"
    25  }
    26  
    27  func (um *MacosUpdateManager) Format() string {
    28  	return MacosUpdateFormat
    29  }
    30  
    31  func (um *MacosUpdateManager) List() ([]OperatingSystemUpdate, error) {
    32  	f, err := um.conn.FileSystem().Open("/Library/Preferences/com.apple.SoftwareUpdate.plist")
    33  	defer f.Close()
    34  	if err != nil {
    35  		return nil, fmt.Errorf("could not read package list")
    36  	}
    37  	return ParseSoftwarePlistUpdates(f)
    38  }
    39  
    40  // parse macos system version property list
    41  func ParseSoftwarePlistUpdates(input io.Reader) ([]OperatingSystemUpdate, error) {
    42  	var r io.ReadSeeker
    43  	r, ok := input.(io.ReadSeeker)
    44  
    45  	// if the read seaker is not implemented lets cache stdout in-memory
    46  	if !ok {
    47  		packageList, err := io.ReadAll(input)
    48  		if err != nil {
    49  			return nil, err
    50  		}
    51  		r = strings.NewReader(string(packageList))
    52  	}
    53  
    54  	type recommendedUpdate struct {
    55  		Identifier           string `plist:"Identifier"`
    56  		DisplayName          string `plist:"Display Name"`
    57  		Version              string `plist:"Display Version"`
    58  		MobileSoftwareUpdate bool   `plist:"MobileSoftwareUpdate"`
    59  		ProductKey           string `plist:"Product Key"`
    60  	}
    61  
    62  	type softwareUpdate struct {
    63  		RecommendedUpdates []recommendedUpdate `plist:"RecommendedUpdates"`
    64  	}
    65  
    66  	var data softwareUpdate
    67  	decoder := plist.NewDecoder(r)
    68  	err := decoder.Decode(&data)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	updates := make([]OperatingSystemUpdate, len(data.RecommendedUpdates))
    74  	for i, entry := range data.RecommendedUpdates {
    75  		updates[i].ID = entry.ProductKey
    76  		updates[i].Name = entry.Identifier
    77  		updates[i].Description = entry.DisplayName
    78  		updates[i].Version = entry.Version
    79  
    80  		updates[i].Format = MacosUpdateFormat
    81  	}
    82  
    83  	return updates, nil
    84  }