mirror of
https://github.com/fleetdm/fleet
synced 2026-04-28 17:07:43 +00:00
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #38889 Plan was to convert `osquery_utils` package to slog. Picked up some additional code that was related. # Checklist for submitter - [ ] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - Already have changes ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit # Release Notes ## Refactor * Updated internal logging infrastructure to use improved system-level logging utilities ## Tests * Updated test suite to align with internal logging changes --- **Note:** This release contains internal infrastructure improvements with no user-facing changes or new features. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
145 lines
4.2 KiB
Go
145 lines
4.2 KiB
Go
//go:build darwin || windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/fleetdm/fleet/v4/pkg/file"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
)
|
|
|
|
type AppCommander struct {
|
|
Name string
|
|
Slug string
|
|
UniqueIdentifier string
|
|
Version string
|
|
AppPath string
|
|
UninstallScript string
|
|
InstallScript string
|
|
cfg *Config
|
|
appLogger *slog.Logger
|
|
}
|
|
|
|
func (ac *AppCommander) isFrozen() (bool, error) {
|
|
inputPath := ac.cfg.inputsPath
|
|
parts := strings.Split(ac.Slug, "/")
|
|
if len(parts) != 2 {
|
|
return false, fmt.Errorf("invalid slug format: %s, expected <name>/<platform>", ac.Slug)
|
|
}
|
|
inputPath = filepath.Join(inputPath, parts[0]+".json")
|
|
|
|
fileBytes, err := os.ReadFile(inputPath)
|
|
if err != nil {
|
|
return false, fmt.Errorf("reading app input file: %w", err)
|
|
}
|
|
|
|
var input struct {
|
|
Frozen bool `json:"frozen"`
|
|
}
|
|
if err := json.Unmarshal(fileBytes, &input); err != nil {
|
|
return false, fmt.Errorf("unmarshal app input file: %w", err)
|
|
}
|
|
|
|
return input.Frozen, nil
|
|
}
|
|
|
|
func (ac *AppCommander) extractAppVersion(installerTFR *fleet.TempFileReader) error {
|
|
if ac.Version == "latest" {
|
|
meta, err := file.ExtractInstallerMetadata(installerTFR)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ac.Version = meta.Version
|
|
err = installerTFR.Rewind()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ac *AppCommander) uninstallPreInstalled(ctx context.Context) {
|
|
ac.appLogger.InfoContext(ctx, "App is marked as pre-installed, attempting to run uninstall script...")
|
|
|
|
_, _, listError := ac.expectToChangeFileSystem(ctx,
|
|
func() error {
|
|
uninstalled := ac.uninstallApp(ctx)
|
|
if !uninstalled {
|
|
ac.appLogger.ErrorContext(ctx, "Failed to uninstall pre-installed app")
|
|
}
|
|
return nil
|
|
},
|
|
)
|
|
|
|
if listError != nil {
|
|
ac.appLogger.ErrorContext(ctx, fmt.Sprintf("Error listing %s directory: %v", ac.cfg.installationSearchDirectory, listError))
|
|
}
|
|
}
|
|
|
|
func (ac *AppCommander) uninstallApp(ctx context.Context) bool {
|
|
ac.appLogger.InfoContext(ctx, "Executing uninstall script for app...")
|
|
output, err := executeScript(ac.cfg, ac.UninstallScript)
|
|
if err != nil {
|
|
ac.appLogger.ErrorContext(ctx, fmt.Sprintf("Error uninstalling app: %v", err))
|
|
ac.appLogger.ErrorContext(ctx, fmt.Sprintf("Output: %s", output))
|
|
return false
|
|
}
|
|
ac.appLogger.DebugContext(ctx, fmt.Sprintf("Output: %s", output))
|
|
|
|
existance, err := appExists(ctx, ac.appLogger, ac.Name, ac.UniqueIdentifier, ac.Version, ac.AppPath)
|
|
if err != nil {
|
|
ac.appLogger.ErrorContext(ctx, fmt.Sprintf("Error checking if app exists after uninstall: %v", err))
|
|
return false
|
|
}
|
|
if existance {
|
|
ac.appLogger.ErrorContext(ctx, fmt.Sprintf("App version '%s' was found after uninstall", ac.Version))
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (ac *AppCommander) expectToChangeFileSystem(ctx context.Context, changer func() error) (string, error, error) {
|
|
var preListError, postListError, listError error
|
|
appListPre, err := listDirectoryContents(ac.cfg.installationSearchDirectory)
|
|
if err != nil {
|
|
preListError = fmt.Errorf("Error listing %s directory: %v", ac.cfg.installationSearchDirectory, err)
|
|
}
|
|
|
|
changerError := changer()
|
|
|
|
appListPost, err := listDirectoryContents(ac.cfg.installationSearchDirectory)
|
|
if err != nil {
|
|
postListError = fmt.Errorf("Error listing %s directory: %v", ac.cfg.installationSearchDirectory, err)
|
|
}
|
|
|
|
appPath, changed := detectApplicationChange(ac.cfg.installationSearchDirectory, appListPre, appListPost)
|
|
if appPath == "" {
|
|
ac.appLogger.WarnContext(ctx, fmt.Sprintf("no changes detected in %s directory after running application script.", ac.cfg.installationSearchDirectory))
|
|
} else {
|
|
if changed {
|
|
ac.appLogger.InfoContext(ctx, fmt.Sprintf("New application detected at: %s", appPath))
|
|
} else {
|
|
ac.appLogger.InfoContext(ctx, fmt.Sprintf("Application removal detected at: %s", appPath))
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case preListError != nil && postListError != nil:
|
|
listError = fmt.Errorf("app pre list: %v, app post list: %v", preListError, postListError)
|
|
case preListError != nil:
|
|
listError = fmt.Errorf("app pre list: %v", preListError)
|
|
case postListError != nil:
|
|
listError = fmt.Errorf("app post list: %v", postListError)
|
|
}
|
|
|
|
return appPath, changerError, listError
|
|
}
|