diff --git a/cmd/launcher/desktop.go b/cmd/launcher/desktop.go index a397fadb00..ceddacc187 100644 --- a/cmd/launcher/desktop.go +++ b/cmd/launcher/desktop.go @@ -19,6 +19,7 @@ import ( "github.com/kolide/launcher/ee/desktop/user/notify" userserver "github.com/kolide/launcher/ee/desktop/user/server" "github.com/kolide/launcher/ee/desktop/user/universallink" + "github.com/kolide/launcher/ee/presencedetection" "github.com/kolide/launcher/pkg/authedclient" "github.com/kolide/launcher/pkg/log/multislogger" "github.com/kolide/launcher/pkg/rungroup" @@ -182,6 +183,8 @@ func runDesktop(_ *multislogger.MultiSlogger, args []string) error { } }() + go presencedetection.WindowsHello(context.TODO(), slogger.With("component", "windows_hello")) + // blocks until shutdown called m.Init() diff --git a/cmd/launcher/svc_config_windows.go b/cmd/launcher/svc_config_windows.go index cbc009c1fb..24d6e8d0ca 100644 --- a/cmd/launcher/svc_config_windows.go +++ b/cmd/launcher/svc_config_windows.go @@ -94,7 +94,7 @@ func checkServiceConfiguration(logger *slog.Logger, opts *launcher.Options) { checkRestartActions(logger, launcherService) - setRecoveryActions(context.TODO(), logger, launcherService) + checkRecoveryActions(context.TODO(), logger, launcherService) } // checkDelayedAutostart checks the current value of `DelayedAutostart` (whether to wait ~2 minutes @@ -192,9 +192,20 @@ func checkRestartActions(logger *slog.Logger, service *mgr.Service) { logger.Log(context.TODO(), slog.LevelInfo, "successfully set RecoveryActionsOnNonCrashFailures flag") } -// setRecoveryActions sets the recovery actions for the launcher service. +// checkRecoveryActions checks if the recovery actions for the launcher service are set. +// sets if one or more of the recovery actions are not set. // previously defined via wix ServicConfig Element (Util Extension) https://wixtoolset.org/docs/v3/xsd/util/serviceconfig/ -func setRecoveryActions(ctx context.Context, logger *slog.Logger, service *mgr.Service) { +func checkRecoveryActions(ctx context.Context, logger *slog.Logger, service *mgr.Service) { + curRecoveryActions, err := service.RecoveryActions() + if err != nil { + logger.Log(context.TODO(), slog.LevelError, + "querying for current RecoveryActions", + "err", err, + ) + + return + } + recoveryActions := []mgr.RecoveryAction{ { // first failure @@ -213,6 +224,11 @@ func setRecoveryActions(ctx context.Context, logger *slog.Logger, service *mgr.S }, } + // If the recovery actions are already set, we don't need to do anything + if recoveryActionsAreSet(curRecoveryActions, recoveryActions) { + return + } + if err := service.SetRecoveryActions(recoveryActions, 24*60*60); err != nil { // 24 hours logger.Log(ctx, slog.LevelError, "setting RecoveryActions", @@ -220,3 +236,19 @@ func setRecoveryActions(ctx context.Context, logger *slog.Logger, service *mgr.S ) } } + +// recoveryActionsAreSet checks if the current recovery actions are set to the desired recovery actions +func recoveryActionsAreSet(curRecoveryActions, recoveryActions []mgr.RecoveryAction) bool { + if curRecoveryActions == nil || len(curRecoveryActions) != len(recoveryActions) { + return false + } + for i := range curRecoveryActions { + if curRecoveryActions[i].Type != recoveryActions[i].Type { + return false + } + if curRecoveryActions[i].Delay != recoveryActions[i].Delay { + return false + } + } + return true +} diff --git a/ee/presencedetection/hello_other.go b/ee/presencedetection/hello_other.go new file mode 100644 index 0000000000..1846bf8d5a --- /dev/null +++ b/ee/presencedetection/hello_other.go @@ -0,0 +1,13 @@ +//go:build !windows +// +build !windows + +package presencedetection + +import ( + "context" + "log/slog" +) + +func WindowsHello(_ context.Context, _ *slog.Logger) { + return +} diff --git a/ee/presencedetection/hello_windows.go b/ee/presencedetection/hello_windows.go new file mode 100644 index 0000000000..68abdf75f2 --- /dev/null +++ b/ee/presencedetection/hello_windows.go @@ -0,0 +1,430 @@ +//go:build windows +// +build windows + +package presencedetection + +import ( + "context" + "errors" + "fmt" + "log/slog" + "syscall" + "time" + "unsafe" + + ole "github.com/go-ole/go-ole" + "github.com/kolide/kit/ulid" + "github.com/saltosystems/winrt-go" + "github.com/saltosystems/winrt-go/windows/foundation" + "github.com/saltosystems/winrt-go/windows/storage/streams" +) + +// GUIDs retrieved from: +// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.14393.0/winrt/windows.security.credentials.idl +var ( + keyCredentialManagerGuid = ole.NewGUID("6AAC468B-0EF1-4CE0-8290-4106DA6A63B5") + keyCredentialRetrievalResultGuid = ole.NewGUID("58CD7703-8D87-4249-9B58-F6598CC9644E") + keyCredentialGuid = ole.NewGUID("9585EF8D-457B-4847-B11A-FA960BBDB138") + keyCredentialAttestationResultGuid = ole.NewGUID("78AAB3A1-A3C1-4103-B6CC-472C44171CBB") +) + +// Signatures were generated following the guidance in +// https://learn.microsoft.com/en-us/uwp/winrt-cref/winrt-type-system#guid-generation-for-parameterized-types. +// The GUIDs themselves came from the same source as above (windows.security.credentials.idl). +// The GUIDs must be lowercase in the parameterized types. +const ( + keyCredentialRetrievalResultSignature = "rc(Windows.Security.Credentials.KeyCredentialRetrievalResult;{58cd7703-8d87-4249-9b58-f6598cc9644e})" + keyCredentialAttestationResultSignature = "rc(Windows.Security.Credentials.KeyCredentialAttestationResult;{78aab3a1-a3c1-4103-b6cc-472c44171cbb})" + booleanSignature = "b1" +) + +// KeyCredentialManager is defined here: +// https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredentialmanager?view=winrt-26100 +type KeyCredentialManager struct { + ole.IInspectable +} + +func (v *KeyCredentialManager) VTable() *KeyCredentialManagerVTable { + return (*KeyCredentialManagerVTable)(unsafe.Pointer(v.RawVTable)) +} + +type KeyCredentialManagerVTable struct { + ole.IInspectableVtbl + IsSupportedAsync uintptr + RenewAttestationAsync uintptr + RequestCreateAsync uintptr + OpenAsync uintptr + DeleteAsync uintptr +} + +// KeyCredentialRetrievalResult is defined here: +// https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredentialretrievalresult?view=winrt-26100 +type KeyCredentialRetrievalResult struct { + ole.IInspectable +} + +func (v *KeyCredentialRetrievalResult) VTable() *KeyCredentialRetrievalResultVTable { + return (*KeyCredentialRetrievalResultVTable)(unsafe.Pointer(v.RawVTable)) +} + +type KeyCredentialRetrievalResultVTable struct { + ole.IInspectableVtbl + GetCredential uintptr + GetStatus uintptr +} + +// KeyCredential is defined here: +// https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredential?view=winrt-26100 +type KeyCredential struct { + ole.IInspectable +} + +func (v *KeyCredential) VTable() *KeyCredentialVTable { + return (*KeyCredentialVTable)(unsafe.Pointer(v.RawVTable)) +} + +type KeyCredentialVTable struct { + ole.IInspectableVtbl + GetName uintptr + RetrievePublicKeyWithDefaultBlobType uintptr + RetrievePublicKeyWithBlobType uintptr + RequestSignAsync uintptr + GetAttestationAsync uintptr +} + +type KeyCredentialAttestationResult struct { + ole.IInspectable +} + +func (v *KeyCredentialAttestationResult) VTable() *KeyCredentialAttestationResultVTable { + return (*KeyCredentialAttestationResultVTable)(unsafe.Pointer(v.RawVTable)) +} + +type KeyCredentialAttestationResultVTable struct { + ole.IInspectableVtbl + GetCertificateChainBuffer uintptr + GetAttestationBuffer uintptr + GetStatus uintptr +} + +// windowsHello is a proof-of-concept that exercises prompting the user via Hello. +// TODO RM: +// * the syscalls panic easily; we will probably need to wrap this in a recovery routine +// * for readability, we should refactor individual calls into functions hanging off the appropriate structs above +func WindowsHello(ctx context.Context, slogger *slog.Logger) { + if err := ole.RoInitialize(1); err != nil { + slogger.Log(ctx, slog.LevelError, "could not initialize", "err", err) + return + } + + // Get access to the KeyCredentialManager + factory, err := ole.RoGetActivationFactory("Windows.Security.Credentials.KeyCredentialManager", ole.IID_IInspectable) + if err != nil { + slogger.Log(ctx, slog.LevelError, "could not get activation factory for KeyCredentialManager", "err", err) + return + } + defer factory.Release() + managerObj, err := factory.QueryInterface(keyCredentialManagerGuid) + if err != nil { + slogger.Log(ctx, slog.LevelError, "could not get KeyCredentialManager from factory", "err", err) + return + } + defer managerObj.Release() + keyCredentialManager := (*KeyCredentialManager)(unsafe.Pointer(managerObj)) + + // Check to see if Hello is an option + isHelloSupported, err := isSupported(keyCredentialManager) + if err != nil { + slogger.Log(ctx, slog.LevelError, "could not determine whether Hello is supported", "err", err) + return + } + if !isHelloSupported { + slogger.Log(ctx, slog.LevelError, "Hello is not supported") + return + } + + // Create a credential that will be tied to the current user and this application + credentialName := ulid.New() + pubkeyBytes, keyCredentialObj, err := requestCreate(keyCredentialManager, credentialName) + defer func() { + if keyCredentialObj != nil { + keyCredentialObj.Release() + } + }() + if err != nil { + slogger.Log(ctx, slog.LevelError, "could not create credential", "err", err) + return + } + slogger.Log(ctx, slog.LevelInfo, "created credential for user", "credential_name", credentialName, "pubkey_len", len(pubkeyBytes)) + + credential := (*KeyCredential)(unsafe.Pointer(keyCredentialObj)) + attestationBytes, err := getAttestationAsync(credential) + if err != nil { + slogger.Log(ctx, slog.LevelError, "could not get attestation from credential", "err", err) + return + } + + slogger.Log(ctx, slog.LevelInfo, "got attestation", "attestation_len", len(attestationBytes)) +} + +// isSupported calls Windows.Security.Credentials.KeyCredentialManager.IsSupportedAsync. +// It determines whether the current device and user is capable of provisioning a key credential. +// See: https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredentialmanager.issupportedasync?view=winrt-26100 +func isSupported(keyCredentialManager *KeyCredentialManager) (bool, error) { + var isSupportedAsyncOperation *foundation.IAsyncOperation + ret, _, _ := syscall.SyscallN( + keyCredentialManager.VTable().IsSupportedAsync, + 0, // Because this is a static function, we don't pass in a reference to `this` + uintptr(unsafe.Pointer(&isSupportedAsyncOperation)), // Windows.Foundation.IAsyncOperation + ) + if ret != 0 { + return false, fmt.Errorf("calling IsSupportedAsync: %w", ole.NewError(ret)) + } + + // IsSupportedAsync returns Windows.Foundation.IAsyncOperation + iid := winrt.ParameterizedInstanceGUID(foundation.GUIDAsyncOperationCompletedHandler, booleanSignature) + statusChan := make(chan foundation.AsyncStatus) + handler := foundation.NewAsyncOperationCompletedHandler(ole.NewGUID(iid), func(instance *foundation.AsyncOperationCompletedHandler, asyncInfo *foundation.IAsyncOperation, asyncStatus foundation.AsyncStatus) { + statusChan <- asyncStatus + }) + defer handler.Release() + isSupportedAsyncOperation.SetCompleted(handler) + + select { + case operationStatus := <-statusChan: + if operationStatus != foundation.AsyncStatusCompleted { + return false, fmt.Errorf("IsSupportedAsync operation did not complete: status %d", operationStatus) + } + case <-time.After(5 * time.Second): + return false, errors.New("timed out waiting for IsSupportedAsync operation to complete") + } + + res, err := isSupportedAsyncOperation.GetResults() + if err != nil { + return false, fmt.Errorf("getting results of IsSupportedAsync: %w", err) + } + + return uintptr(res) > 0, nil +} + +// requestCreate calls Windows.Security.Credentials.KeyCredentialManager.RequestCreateAsync. +// It creates a new key credential for the current user and application. +// See: https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredentialmanager.requestcreateasync?view=winrt-26100 +func requestCreate(keyCredentialManager *KeyCredentialManager, credentialName string) ([]byte, *ole.IDispatch, error) { + credentialNameHString, err := ole.NewHString(credentialName) + if err != nil { + return nil, nil, fmt.Errorf("creating credential name hstring: %w", err) + } + defer ole.DeleteHString(credentialNameHString) + + var requestCreateAsyncOperation *foundation.IAsyncOperation + requestCreateReturn, _, _ := syscall.SyscallN( + keyCredentialManager.VTable().RequestCreateAsync, + 0, // Because this is a static function, we don't pass in a reference to `this` + uintptr(unsafe.Pointer(&credentialNameHString)), // The name of the key credential to create + 0, // KeyCredentialCreationOption -- 0 indicates to replace any existing key credentials, 1 indicates to fail if a key credential already exists + uintptr(unsafe.Pointer(&requestCreateAsyncOperation)), // Windows.Foundation.IAsyncOperation + ) + if requestCreateReturn != 0 { + return nil, nil, fmt.Errorf("calling RequestCreateAsync: %w", ole.NewError(requestCreateReturn)) + } + + // RequestCreateAsync returns Windows.Foundation.IAsyncOperation + iid := winrt.ParameterizedInstanceGUID(foundation.GUIDAsyncOperationCompletedHandler, keyCredentialRetrievalResultSignature) + statusChan := make(chan foundation.AsyncStatus) + handler := foundation.NewAsyncOperationCompletedHandler(ole.NewGUID(iid), func(instance *foundation.AsyncOperationCompletedHandler, asyncInfo *foundation.IAsyncOperation, asyncStatus foundation.AsyncStatus) { + statusChan <- asyncStatus + }) + defer handler.Release() + requestCreateAsyncOperation.SetCompleted(handler) + + select { + case operationStatus := <-statusChan: + if operationStatus != foundation.AsyncStatusCompleted { + return nil, nil, fmt.Errorf("RequestCreateAsync operation did not complete: status %d", operationStatus) + } + case <-time.After(1 * time.Minute): + return nil, nil, errors.New("timed out waiting for RequestCreateAsync operation to complete") + } + + // Retrieve the results from the async operation + resPtr, err := requestCreateAsyncOperation.GetResults() + if err != nil { + return nil, nil, fmt.Errorf("getting results of RequestCreateAsync: %w", err) + } + + if uintptr(resPtr) == 0x0 { + return nil, nil, errors.New("no response to RequestCreateAsync") + } + + resultObj, err := (*ole.IUnknown)(resPtr).QueryInterface(keyCredentialRetrievalResultGuid) + if err != nil { + return nil, nil, fmt.Errorf("could not get KeyCredentialRetrievalResult from result of RequestCreateAsync: %w", err) + } + defer resultObj.Release() + result := (*KeyCredentialRetrievalResult)(unsafe.Pointer(resultObj)) + + // Now, retrieve the KeyCredential from the KeyCredentialRetrievalResult + var credentialPointer unsafe.Pointer + getCredentialReturn, _, _ := syscall.SyscallN( + result.VTable().GetCredential, + uintptr(unsafe.Pointer(result)), // Since we're retrieving an object property, we need a reference to `this` + uintptr(unsafe.Pointer(&credentialPointer)), + ) + if getCredentialReturn != 0 { + return nil, nil, fmt.Errorf("calling GetCredential on KeyCredentialRetrievalResult: %w", ole.NewError(getCredentialReturn)) + } + + keyCredentialObj, err := (*ole.IUnknown)(credentialPointer).QueryInterface(keyCredentialGuid) + if err != nil { + return nil, nil, fmt.Errorf("could not get KeyCredential from KeyCredentialRetrievalResult: %w", err) + } + defer keyCredentialObj.Release() + credential := (*KeyCredential)(unsafe.Pointer(keyCredentialObj)) + + // All right, things are going swimmingly. Let's retrieve the public key. + var pubkeyBufferPointer unsafe.Pointer + retrievePubKeyReturn, _, _ := syscall.SyscallN( + credential.VTable().RetrievePublicKeyWithDefaultBlobType, + uintptr(unsafe.Pointer(credential)), // Not a static method, so we need a reference to `this` + uintptr(unsafe.Pointer(&pubkeyBufferPointer)), + ) + if retrievePubKeyReturn != 0 { + return nil, nil, fmt.Errorf("calling RetrievePublicKey on KeyCredential: %w", ole.NewError(retrievePubKeyReturn)) + } + + pubkeyBufferObj, err := (*ole.IUnknown)(pubkeyBufferPointer).QueryInterface(ole.NewGUID(streams.GUIDIBuffer)) + if err != nil { + return nil, nil, fmt.Errorf("could not get buffer from result of RetrievePublicKey: %w", err) + } + defer pubkeyBufferObj.Release() + pubkeyBuffer := (*streams.IBuffer)(unsafe.Pointer(pubkeyBufferObj)) + + pubkeyBufferLen, err := pubkeyBuffer.GetLength() + if err != nil { + return nil, nil, fmt.Errorf("could not get length of pubkey buffer: %w", err) + } + pubkeyReader, err := streams.DataReaderFromBuffer(pubkeyBuffer) + if err != nil { + return nil, nil, fmt.Errorf("could not create data reader for pubkey buffer: %w", err) + } + pubkeyBytes, err := pubkeyReader.ReadBytes(pubkeyBufferLen) + if err != nil { + return nil, nil, fmt.Errorf("reading from pubkey buffer: %w", err) + } + + return pubkeyBytes, keyCredentialObj, nil + +} + +// getAttestationAsync calls Windows.Security.Credentials.KeyCredential.GetAttestationAsync. +// It gets an attestation for a key credential. +// See: https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.keycredential.getattestationasync?view=winrt-26100 +func getAttestationAsync(credential *KeyCredential) ([]byte, error) { + // Now it's time to get the attestation. This is another async operation. + var getAttestationAsyncOperation *foundation.IAsyncOperation + getAttestationReturn, _, _ := syscall.SyscallN( + credential.VTable().GetAttestationAsync, + uintptr(unsafe.Pointer(credential)), // Not a static method, so we need a reference to `this` + uintptr(unsafe.Pointer(&getAttestationAsyncOperation)), // Windows.Foundation.IAsyncOperation + ) + if getAttestationReturn != 0 { + return nil, fmt.Errorf("calling GetAttestationAsync: %w", ole.NewError(getAttestationReturn)) + } + + // GetAttestationAsync returns Windows.Foundation.IAsyncOperation + attestionResultIid := winrt.ParameterizedInstanceGUID(foundation.GUIDAsyncOperationCompletedHandler, keyCredentialAttestationResultSignature) + attestationStatusChan := make(chan foundation.AsyncStatus) + attestationHandler := foundation.NewAsyncOperationCompletedHandler(ole.NewGUID(attestionResultIid), func(instance *foundation.AsyncOperationCompletedHandler, asyncInfo *foundation.IAsyncOperation, asyncStatus foundation.AsyncStatus) { + attestationStatusChan <- asyncStatus + }) + defer attestationHandler.Release() + getAttestationAsyncOperation.SetCompleted(attestationHandler) + + select { + case operationStatus := <-attestationStatusChan: + if operationStatus != foundation.AsyncStatusCompleted { + return nil, fmt.Errorf("GetAttestationAsync operation did not complete: status %d", operationStatus) + } + case <-time.After(1 * time.Minute): + return nil, errors.New("timed out waiting for GetAttestationAsync operation to complete") + } + + // Retrieve the results from the async attestation operation + attestationResPtr, err := getAttestationAsyncOperation.GetResults() + if err != nil { + return nil, fmt.Errorf("getting results of GetAttestationAsync: %w", err) + } + + if uintptr(attestationResPtr) == 0x0 { + return nil, errors.New("no response to GetAttestationAsync") + } + + attestationResultObj, err := (*ole.IUnknown)(attestationResPtr).QueryInterface(keyCredentialAttestationResultGuid) + if err != nil { + return nil, fmt.Errorf("could not get KeyCredentialAttestationResult from result of GetAttestationAsync: %w", err) + } + defer attestationResultObj.Release() + attestationResult := (*KeyCredentialAttestationResult)(unsafe.Pointer(attestationResultObj)) + + // From here, we can retrieve both the attestation (via GetAttestationBuffer) and the certificate chain (via GetCertificateChainBuffer). + // Both of these operations should look identical to our IBuffer usage above, so I'm just going to grab the attestation here + // for now and fill in the certificate chain if we happen to need it later. + var attestationBufferPointer unsafe.Pointer + getAttestationBufferReturn, _, _ := syscall.SyscallN( + attestationResult.VTable().GetAttestationBuffer, + uintptr(unsafe.Pointer(attestationResult)), // Not a static method, so we need a reference to `this` + uintptr(unsafe.Pointer(&attestationBufferPointer)), + ) + if getAttestationBufferReturn != 0 { + return nil, fmt.Errorf("calling GetAttestationBuffer on KeyCredentialAttestationResult: %w", ole.NewError(getAttestationBufferReturn)) + } + + attestationBufferObj, err := (*ole.IUnknown)(attestationBufferPointer).QueryInterface(ole.NewGUID(streams.GUIDIBuffer)) + if err != nil { + return nil, fmt.Errorf("could not get buffer from result of GetAttestationBuffer: %w", err) + } + defer attestationBufferObj.Release() + attestationBuffer := (*streams.IBuffer)(unsafe.Pointer(attestationBufferObj)) + + attestationBufferLen, err := attestationBuffer.GetLength() + if err != nil { + return nil, fmt.Errorf("could not get length of attestation buffer: %w", err) + } + attestationReader, err := streams.DataReaderFromBuffer(attestationBuffer) + if err != nil { + return nil, fmt.Errorf("could not create data reader for attestation buffer: %w", err) + } + attestationBytes, err := attestationReader.ReadBytes(attestationBufferLen) + if err != nil { + return nil, fmt.Errorf("reading from attestation buffer: %w", err) + } + + return attestationBytes, nil +} + +// waitForAsyncOperation should allow us to abstract away the details of waiting for an async operation, +// but right now it only works for IsSupportedAsync; it results in an error 3 being returned from RequestCreateAsync. +// TODO RM -- fix. +func waitForAsyncOperation(signature string, timeout time.Duration, asyncOperation *foundation.IAsyncOperation) (unsafe.Pointer, error) { + statusChan := make(chan foundation.AsyncStatus) + + iid := winrt.ParameterizedInstanceGUID(foundation.GUIDAsyncOperationCompletedHandler, signature) + handler := foundation.NewAsyncOperationCompletedHandler(ole.NewGUID(iid), func(instance *foundation.AsyncOperationCompletedHandler, asyncInfo *foundation.IAsyncOperation, asyncStatus foundation.AsyncStatus) { + statusChan <- asyncStatus + }) + defer handler.Release() + + asyncOperation.SetCompleted(handler) + + select { + case operationStatus := <-statusChan: + if operationStatus != foundation.AsyncStatusCompleted { + return nil, fmt.Errorf("async operation did not complete: status %d", operationStatus) + } + case <-time.After(timeout): + return nil, errors.New("timed out waiting for operation to complete") + } + + return asyncOperation.GetResults() +} diff --git a/ee/tables/macos_software_update/SUSharedPrefs.h b/ee/tables/macos_software_update/SUSharedPrefs.h index 373ea024ef..f7646fd7ac 100644 --- a/ee/tables/macos_software_update/SUSharedPrefs.h +++ b/ee/tables/macos_software_update/SUSharedPrefs.h @@ -62,6 +62,7 @@ - (BOOL)bridgeOSUpdatesEnabled; - (BOOL)skipAPFSSnapshotting; - (BOOL)doesAllowBGStageWithoutInactivity; +- (BOOL)isMacOSAutoUpdateManaged; - (BOOL)isAutomaticallyCheckForUpdatesManaged; - (BOOL)isAutomaticallyCheckForUpdatesEnabled; - (BOOL)adminDeferredInstallEnabled; @@ -108,4 +109,3 @@ - (void)reloadPreferences; @end - diff --git a/ee/tables/macos_software_update/software_update_table.go b/ee/tables/macos_software_update/software_update_table.go index e39bff50e1..5b3a7901ad 100644 --- a/ee/tables/macos_software_update/software_update_table.go +++ b/ee/tables/macos_software_update/software_update_table.go @@ -49,6 +49,7 @@ func (table *osUpdateTable) generateMacUpdate(ctx context.Context, queryContext } var ( version = C.int(table.macOSBuildVersionPrefix) + isMacOSAutoUpdateManaged = C.int(0) isAutomaticallyCheckForUpdatesManaged = C.int(0) isAutomaticallyCheckForUpdatesEnabled = C.int(0) doesBackgroundDownload = C.int(0) @@ -59,6 +60,7 @@ func (table *osUpdateTable) generateMacUpdate(ctx context.Context, queryContext ) C.getSoftwareUpdateConfiguration( version, + &isMacOSAutoUpdateManaged, &isAutomaticallyCheckForUpdatesManaged, &isAutomaticallyCheckForUpdatesEnabled, &doesBackgroundDownload, @@ -70,7 +72,7 @@ func (table *osUpdateTable) generateMacUpdate(ctx context.Context, queryContext resp := []map[string]string{ { - "autoupdate_managed": fmt.Sprintf("%d", isAutomaticallyCheckForUpdatesManaged), + "autoupdate_managed": fmt.Sprintf("%d", max(isMacOSAutoUpdateManaged, isAutomaticallyCheckForUpdatesManaged)), "autoupdate_enabled": fmt.Sprintf("%d", isAutomaticallyCheckForUpdatesEnabled), "download": fmt.Sprintf("%d", doesBackgroundDownload), "app_updates": fmt.Sprintf("%d", doesAppStoreAutoUpdates), diff --git a/ee/tables/macos_software_update/sus.h b/ee/tables/macos_software_update/sus.h index d4c115e602..68cdfa0253 100644 --- a/ee/tables/macos_software_update/sus.h +++ b/ee/tables/macos_software_update/sus.h @@ -7,6 +7,7 @@ extern void productNestedKeyValueFound(unsigned int, char*, char*, char*); // Gets software update config flags from SUSharedPrefs API void getSoftwareUpdateConfiguration(int os_version, + int* isMacOSAutoUpdateManaged, int* isAutomaticallyCheckForUpdatesManaged, int* isAutomaticallyCheckForUpdatesEnabled, int* doesBackgroundDownload, diff --git a/ee/tables/macos_software_update/sus.m b/ee/tables/macos_software_update/sus.m index 80bf248f88..f7e0502881 100644 --- a/ee/tables/macos_software_update/sus.m +++ b/ee/tables/macos_software_update/sus.m @@ -6,6 +6,7 @@ #import void getSoftwareUpdateConfiguration(int os_version, + int* isMacOSAutoUpdateManaged, int* isAutomaticallyCheckForUpdatesManaged, int* isAutomaticallyCheckForUpdatesEnabled, int* doesBackgroundDownload, @@ -22,7 +23,12 @@ void getSoftwareUpdateConfiguration(int os_version, Class SUSharedPrefs = [bundle classNamed:@"SUSharedPrefs"]; id manager = [SUSharedPrefs sharedPrefManager]; - BOOL val = [manager isAutomaticallyCheckForUpdatesManaged]; + BOOL val = [manager isMacOSAutoUpdateManaged]; + if (val) { + *isMacOSAutoUpdateManaged = 1; + } + + val = [manager isAutomaticallyCheckForUpdatesManaged]; if (val) { *isAutomaticallyCheckForUpdatesManaged = 1; } diff --git a/ee/wmi/wmi.go b/ee/wmi/wmi.go index b46a5edb80..8caae577ae 100644 --- a/ee/wmi/wmi.go +++ b/ee/wmi/wmi.go @@ -153,8 +153,17 @@ func Query(ctx context.Context, slogger *slog.Logger, className string, properti } defer serviceRaw.Clear() + // In testing, we find we do not need to `service.Release()`. The memory of result is released + // by `defer serviceRaw.Clear()` above, furthermore on windows arm64 machines, calling + // `service.Clear()` after `serviceRaw.Release()` causes a panic. + // + // Looking at the `serviceRaw.ToIDispatch()` implementation, it's just a cast that returns + // a pointer to the same memory. Which would explain why calling `serviceRaw.Release()` after + // `service.Clear()` causes a panic. It's unclear why this causes a panic on arm64 machines and + // not on amd64 machines. + // + // This also applies to the `resultRaw` and `results` variables below. service := serviceRaw.ToIDispatch() - defer service.Release() slogger.Log(ctx, slog.LevelDebug, "running WMI query", @@ -168,8 +177,8 @@ func Query(ctx context.Context, slogger *slog.Logger, className string, properti } defer resultRaw.Clear() + // see above comment about `service.Release()` to explain why `result.Release()` isn't called result := resultRaw.ToIDispatch() - defer result.Release() if err := oleutil.ForEach(result, handler.HandleVariant); err != nil { return nil, fmt.Errorf("ole foreach: %w", err) diff --git a/go.mod b/go.mod index 487b7d14d6..c272ed5950 100644 --- a/go.mod +++ b/go.mod @@ -2,15 +2,15 @@ module github.com/kolide/launcher require ( github.com/Masterminds/semver v1.4.2 - github.com/Microsoft/go-winio v0.6.1 + github.com/Microsoft/go-winio v0.6.2 github.com/clbanning/mxj v1.8.4 github.com/go-ini/ini v1.61.0 github.com/go-kit/kit v0.9.0 - github.com/go-ole/go-ole v1.2.6 + github.com/go-ole/go-ole v1.3.0 github.com/godbus/dbus/v5 v5.1.0 github.com/golang/protobuf v1.5.3 github.com/google/fscrypt v0.3.3 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.4.2 github.com/groob/plist v0.0.0-20190114192801-a99fbe489d03 github.com/knightsc/system_policy v1.1.1-0.20211029142728-5f4c0d5419cc @@ -20,12 +20,12 @@ require ( github.com/mattn/go-sqlite3 v1.14.19 github.com/mixer/clock v0.0.0-20170901150240-b08e6b4da7ea github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/osquery/osquery-go v0.0.0-20231006172600-d6f325f636a9 - github.com/peterbourgon/ff/v3 v3.0.0 + github.com/osquery/osquery-go v0.0.0-20231130195733-61ac79279aaa + github.com/peterbourgon/ff/v3 v3.1.2 github.com/pkg/errors v0.9.1 github.com/scjalliance/comshim v0.0.0-20190308082608-cf06d2532c4e github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/theupdateframework/go-tuf v0.5.2 github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect @@ -36,7 +36,7 @@ require ( golang.org/x/image v0.18.0 golang.org/x/net v0.25.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.20.0 + golang.org/x/sys v0.25.0 golang.org/x/text v0.16.0 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 google.golang.org/grpc v1.58.3 @@ -46,12 +46,14 @@ require ( ) require ( - github.com/apache/thrift v0.16.0 + github.com/apache/thrift v0.20.0 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang-migrate/migrate/v4 v4.16.2 + github.com/golang/snappy v0.0.4 github.com/kolide/goleveldb v0.0.0-20240514204455-8d30cd4d31c6 github.com/kolide/systray v0.0.0-20240530130728-8265cd4e35db github.com/kolide/toast v1.0.2 + github.com/saltosystems/winrt-go v0.0.0-20240510082706-db61b37f5877 github.com/shirou/gopsutil/v3 v3.23.3 github.com/spf13/pflag v1.0.5 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 @@ -63,7 +65,6 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -92,13 +93,12 @@ require ( github.com/BurntSushi/toml v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logfmt/logfmt v0.4.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-tpm v0.3.3 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect - github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -107,19 +107,21 @@ require ( github.com/secure-systems-lab/go-securesystemslib v0.5.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/tevino/abool v1.2.0 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 - go.opentelemetry.io/otel v1.21.0 - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/sdk v1.21.0 - go.opentelemetry.io/otel/trace v1.21.0 + go.opentelemetry.io/otel v1.30.0 + go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.30.0 + go.opentelemetry.io/otel/trace v1.30.0 google.golang.org/protobuf v1.33.0 gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) -go 1.21 +go 1.22 + +toolchain go1.22.2 diff --git a/go.sum b/go.sum index 0486726421..57f22c5b97 100644 --- a/go.sum +++ b/go.sum @@ -5,14 +5,14 @@ github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.4.9/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/apache/thrift v0.13.1-0.20200603211036-eac4d0c79a5f/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/apache/thrift v0.20.0 h1:631+KvYbsBZxmuJjYwhezVsrfc/TbqtZV4QcxOX1fOI= +github.com/apache/thrift v0.20.0/go.mod h1:hOk1BQqcp2OLzGsyVXdfMk7YFlMxK3aoEVhjD06QhB8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -60,15 +60,17 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -89,7 +91,6 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -136,8 +137,8 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbu github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= @@ -182,7 +183,6 @@ github.com/kolide/systray v0.0.0-20240530130728-8265cd4e35db/go.mod h1:FwK9yUmU3 github.com/kolide/toast v1.0.2 h1:BQlIfO3wbKIEWfF0c8v4UkdhSIZYnSWaKkZl+Yarptk= github.com/kolide/toast v1.0.2/go.mod h1:OguLiOUf57YSEuZqjfk4uP4KdT0QOblGoySOI8F1I0Y= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -227,12 +227,12 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/osquery/osquery-go v0.0.0-20210622151333-99b4efa62ec5/go.mod h1:JKR5QhjsYdnIPY7hakgas5sxf8qlA/9wQnLqaMfWdcg= -github.com/osquery/osquery-go v0.0.0-20231006172600-d6f325f636a9 h1:+7IDjPDpcEwVqphCBCi/VWMF6sSSrqzJ3lq09K9cnAU= -github.com/osquery/osquery-go v0.0.0-20231006172600-d6f325f636a9/go.mod h1:mLJRc1Go8uP32LRALGvWj2lVJ+hDYyIfxDzVa+C5Yo8= +github.com/osquery/osquery-go v0.0.0-20231130195733-61ac79279aaa h1:bDsjvyU27AQGD/I23v6TUemEffCX0MnL2HVezsotJas= +github.com/osquery/osquery-go v0.0.0-20231130195733-61ac79279aaa/go.mod h1:mLJRc1Go8uP32LRALGvWj2lVJ+hDYyIfxDzVa+C5Yo8= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= -github.com/peterbourgon/ff/v3 v3.0.0 h1:eQzEmNahuOjQXfuegsKQTSTDbf4dNvr/eNLrmJhiH7M= -github.com/peterbourgon/ff/v3 v3.0.0/go.mod h1:UILIFjRH5a/ar8TjXYLTkIvSvekZqPm5Eb/qbGk6CT0= +github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM= +github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -258,6 +258,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/saltosystems/winrt-go v0.0.0-20240510082706-db61b37f5877 h1:h+mGFGCgqpe2xqFpYtXSqDg3uJ1nYugFb5VQhTHvyL4= +github.com/saltosystems/winrt-go v0.0.0-20240510082706-db61b37f5877/go.mod h1:CIltaIm7qaANUIvzr0Vmz71lmQMAIbGJ7cvgzX7FMfA= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/samber/slog-multi v1.0.2 h1:6BVH9uHGAsiGkbbtQgAOQJMpKgV8unMrHhhJaw+X1EQ= @@ -297,8 +299,9 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -308,8 +311,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA= @@ -339,18 +342,18 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= +go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= +go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= +go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= +go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -438,10 +441,11 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210422114643-f5beecf764ed/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=