Skip to content

Commit

Permalink
[TUF] Don't use new autoupdater yet; don't set env var (#1362)
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany authored Sep 21, 2023
1 parent d64473a commit 3b04930
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 164 deletions.
46 changes: 23 additions & 23 deletions cmd/launcher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,28 @@ func main() {
// fork-bombing itself. This is an ENV, because there's no
// good way to pass it through the flags.
if !env.Bool("LAUNCHER_SKIP_UPDATES", false) {
runNewerLauncherIfAvailable(ctx, logger)
if tuf.UsingNewAutoupdater() {
runNewerLauncherIfAvailable(ctx, logger)
} else {
newerBinary, err := autoupdate.FindNewestSelf(ctx)
if err != nil {
logutil.Fatal(logger, err, "checking for updated version")
}

if newerBinary != "" {
level.Debug(logger).Log(
"msg", "preparing to exec new binary",
"oldVersion", version.Version().Version,
"newBinary", newerBinary,
)
if err := execwrapper.Exec(ctx, newerBinary, os.Args, os.Environ()); err != nil {
logutil.Fatal(logger, err, "exec")
}
panic("how")
} else {
level.Debug(logger).Log("msg", "Nothing new")
}
}
}

// if the launcher is being ran with a positional argument,
Expand Down Expand Up @@ -147,16 +168,6 @@ func runSubcommands() error {
// runNewerLauncherIfAvailable checks the autoupdate library for a newer version
// of launcher than the currently-running one. If found, it will exec that version.
func runNewerLauncherIfAvailable(ctx context.Context, logger log.Logger) {
// If the legacy autoupdate path variable isn't already set, set it to help
// the legacy autoupdater find its update directory even when the newer binary
// runs out of a different directory.
if _, ok := os.LookupEnv(autoupdate.LegacyLauncherAutoupdatePathEnvVar); !ok {
currentPath, err := os.Executable()
if err == nil {
os.Setenv(autoupdate.LegacyLauncherAutoupdatePathEnvVar, currentPath)
}
}

newerBinary, err := latestLauncherPath(ctx, logger)
if err != nil {
logutil.Fatal(logger, "msg", "checking for updated version", "err", err)
Expand Down Expand Up @@ -185,18 +196,7 @@ func runNewerLauncherIfAvailable(ctx context.Context, logger log.Logger) {
func latestLauncherPath(ctx context.Context, logger log.Logger) (string, error) {
newerBinary, err := tuf.CheckOutLatestWithoutConfig("launcher", logger)
if err != nil {
level.Error(logger).Log(
"msg", "could not check out latest launcher, will fall back to old autoupdate library",
"err", err,
)

// Fall back to legacy autoupdate library
newerBinaryPath, err := autoupdate.FindNewestSelf(ctx)
if err != nil {
return "", fmt.Errorf("finding newest self: %w", err)
}

return newerBinaryPath, nil
return "", fmt.Errorf("checking out latest launcher: %w", err)
}

currentPath, _ := os.Executable()
Expand Down
14 changes: 0 additions & 14 deletions pkg/autoupdate/findnew.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ const defaultBuildTimestamp = "0"
// This suffix is added to the binary path to find the updates
const updateDirSuffix = "-updates"

const (
LegacyLauncherAutoupdatePathEnvVar = "LAUNCHER_LEGACY_AUTOUPDATE_PATH"
)

type newestSettings struct {
deleteOld bool
deleteCorrupt bool
Expand Down Expand Up @@ -251,11 +247,6 @@ func FindNewest(ctx context.Context, fullBinaryPath string, opts ...newestOption
//
// It makes some string assumptions about how things are named.
func getUpdateDir(fullBinaryPath string) string {
if installedPath := os.Getenv(LegacyLauncherAutoupdatePathEnvVar); installedPath != "" {
binaryName := filepath.Base(fullBinaryPath)
fullBinaryPath = filepath.Join(filepath.Dir(installedPath), binaryName)
}

if strings.Contains(fullBinaryPath, ".app") {
binary := filepath.Base(fullBinaryPath)
return filepath.Join(FindBaseDir(fullBinaryPath), binary+updateDirSuffix)
Expand Down Expand Up @@ -332,11 +323,6 @@ func FindBaseDir(path string) string {
return ""
}

if installedPath := os.Getenv(LegacyLauncherAutoupdatePathEnvVar); installedPath != "" {
binaryName := filepath.Base(path)
path = filepath.Join(filepath.Dir(installedPath), binaryName)
}

// If this is an app bundle installation, we need to adjust the directory -- otherwise we end up with a library
// of updates at /usr/local/<identifier>/Kolide.app/Contents/MacOS/launcher-updates.
if strings.Contains(path, ".app") {
Expand Down
102 changes: 0 additions & 102 deletions pkg/autoupdate/findnew_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,67 +88,6 @@ func TestGetUpdateDir(t *testing.T) {
}
}

func TestGetUpdateDir_WithEnvVar(t *testing.T) { //nolint:paralleltest
// Since we're setting an environment variable, we don't want to run this test at the
// same time as other tests.

t.Cleanup(func() {
os.Setenv(LegacyLauncherAutoupdatePathEnvVar, "")
})

var tests = []struct {
installPath string
currentPath string
out string
}{
{
currentPath: "/a/path/var/id/hostname/updates/binary/1.2.3/binary",
installPath: filepath.Clean("/a/bin/launcher"),
out: filepath.Clean("/a/bin/binary-updates"),
},
{
currentPath: "/a/path/var/id/hostname/updates/binary/1.2.3/binary",
installPath: filepath.Clean("/a/Test.app/Contents/MacOS/launcher"),
out: filepath.Clean("/a/bin/binary-updates"),
},
{
currentPath: "/a/path/var/id/hostname/updates/binary/1.2.3/Test.app/Contents/MacOS/binary",
installPath: filepath.Clean("/a/bin/launcher"),
out: filepath.Clean("/a/bin/binary-updates"),
},
{
currentPath: "/a/path/var/id/hostname/updates/binary/1.2.3/Test.app/Contents/MacOS/binary",
installPath: filepath.Clean("/a/Test.app/Contents/MacOS/launcher"),
out: filepath.Clean("/a/bin/binary-updates"),
},
{
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/launcher",
installPath: filepath.Clean("/a/bin/launcher"),
out: filepath.Clean("/a/bin/launcher-updates"),
},
{
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/launcher",
installPath: filepath.Clean("/a/Test.app/Contents/MacOS/launcher"),
out: filepath.Clean("/a/bin/launcher-updates"),
},
{
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/Test.app/Contents/MacOS/launcher",
installPath: filepath.Clean("/a/bin/launcher"),
out: filepath.Clean("/a/bin/launcher-updates"),
},
{
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/Test.app/Contents/MacOS/launcher",
installPath: filepath.Clean("/a/Test.app/Contents/MacOS/launcher"),
out: filepath.Clean("/a/bin/launcher-updates"),
},
}

for _, tt := range tests {
os.Setenv(LegacyLauncherAutoupdatePathEnvVar, tt.installPath)
require.Equal(t, tt.out, getUpdateDir(tt.currentPath), "input: install path %s, current path %s", tt.installPath, tt.currentPath)
}
}

func TestFindBaseDir(t *testing.T) {
t.Parallel()

Expand All @@ -171,47 +110,6 @@ func TestFindBaseDir(t *testing.T) {
}
}

func TestFindBaseDir_WithEnvVar(t *testing.T) { //nolint:paralleltest
// Since we're setting an environment variable, we don't want to run this test at the
// same time as other tests.

t.Cleanup(func() {
os.Setenv(LegacyLauncherAutoupdatePathEnvVar, "")
})

var tests = []struct {
installPath string
currentPath string
out string
}{
{
installPath: "/a/path/bin/launcher",
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/launcher",
out: filepath.Clean("/a/path/bin"),
},
{
installPath: "/a/path/bin/launcher",
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/Test.app/Contents/MacOS/launcher",
out: filepath.Clean("/a/path/bin"),
},
{
installPath: "/a/path/Test.app/Contents/MacOS/launcher",
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/launcher",
out: filepath.Clean("/a/path/bin"),
},
{
installPath: "/a/path/Test.app/Contents/MacOS/launcher",
currentPath: "/a/path/var/id/hostname/updates/launcher/1.2.3/Test.app/Contents/MacOS/launcher",
out: filepath.Clean("/a/path/bin"),
},
}

for _, tt := range tests {
os.Setenv(LegacyLauncherAutoupdatePathEnvVar, tt.installPath)
require.Equal(t, tt.out, FindBaseDir(tt.currentPath), "input: install path %s, current path %s", tt.installPath, tt.currentPath)
}
}

func TestFindNewestEmpty(t *testing.T) {
t.Parallel()

Expand Down
28 changes: 17 additions & 11 deletions pkg/autoupdate/tuf/autoupdate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,18 @@ func TestExecute_launcherUpdate(t *testing.T) {
// Assert expectation that we added the expected `testReleaseVersion` to the updates library
mockLibraryManager.AssertExpectations(t)

// Check log lines to confirm that we see the log `received interrupt to restart launcher after update, stopping`, indicating that
// the autoupdater shut down at the end
logLines := strings.Split(strings.TrimSpace(logBytes.String()), "\n")

// We expect at least 1 log for the shutdown line.
require.GreaterOrEqual(t, len(logLines), 1)

// Check that we shut down
require.Contains(t, logLines[len(logLines)-1], "received interrupt to restart launcher after update, stopping")
// In the future, we expect that we'd restart launcher. For now, we don't want unnecessary restarts.
/*
// Check log lines to confirm that we see the log `received interrupt to restart launcher after update, stopping`, indicating that
// the autoupdater shut down at the end
logLines := strings.Split(strings.TrimSpace(logBytes.String()), "\n")
// We expect at least 1 log for the shutdown line.
require.GreaterOrEqual(t, len(logLines), 1)
// Check that we shut down
require.Contains(t, logLines[len(logLines)-1], "received interrupt to restart launcher after update, stopping")
*/
}

func TestExecute_launcherUpdate_noRestartIfUsingLegacyAutoupdater(t *testing.T) {
Expand Down Expand Up @@ -277,8 +280,11 @@ func TestExecute_osquerydUpdate(t *testing.T) {
// We expect at least 1 log for the restart line.
require.GreaterOrEqual(t, len(logLines), 1)

// Check that we restarted osqueryd
require.Contains(t, logLines[len(logLines)-1], "restarted binary after update")
// // In the future, we expect that we'd restart osquery. For now, we don't want unnecessary restarts.
/*
// Check that we restarted osqueryd
require.Contains(t, logLines[len(logLines)-1], "restarted binary after update")
*/

// The autoupdater won't stop after an osqueryd download, so interrupt it and let it shut down
autoupdater.Interrupt(errors.New("test error"))
Expand Down
15 changes: 13 additions & 2 deletions pkg/autoupdate/tuf/library_lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ type autoupdateConfig struct {
}

var channelsUsingLegacyAutoupdate = map[string]bool{
"stable": true,
"beta": true,
"stable": true,
"beta": true,
"alpha": true,
"nightly": true,
}

// CheckOutLatestWithoutConfig returns information about the latest downloaded executable for our binary,
Expand All @@ -49,6 +51,15 @@ func CheckOutLatestWithoutConfig(binary autoupdatableBinary, logger log.Logger)
return CheckOutLatest(binary, cfg.rootDirectory, cfg.updateDirectory, cfg.channel, logger)
}

func UsingNewAutoupdater() bool {
cfg, err := getAutoupdateConfig()
if err != nil {
return false
}

return usingNewAutoupdater(cfg.channel)
}

// getAutoupdateConfig reads launcher's config file to determine the configuration values
// needed to work with the autoupdate library.
func getAutoupdateConfig() (*autoupdateConfig, error) {
Expand Down
41 changes: 29 additions & 12 deletions pkg/autoupdate/tuf/library_lookup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import (
"github.com/stretchr/testify/require"
)

func TestCheckOutLatest_withTufRepository(t *testing.T) {
t.Parallel()
func TestCheckOutLatest_withTufRepository(t *testing.T) { //nolint: paralleltest
delete(channelsUsingLegacyAutoupdate, "nightly")
defer func() {
channelsUsingLegacyAutoupdate["nightly"] = true
}()

for _, binary := range binaries {
for _, binary := range binaries { //nolint: paralleltest
binary := binary
t.Run(string(binary), func(t *testing.T) {
t.Parallel()

// Set up an update library
rootDir := t.TempDir()
updateDir := defaultLibraryDirectory(rootDir)
Expand Down Expand Up @@ -52,14 +53,15 @@ func TestCheckOutLatest_withTufRepository(t *testing.T) {
}
}

func TestCheckOutLatest_withoutTufRepository(t *testing.T) {
t.Parallel()
func TestCheckOutLatest_withoutTufRepository(t *testing.T) { // nolint:paralleltest
delete(channelsUsingLegacyAutoupdate, "nightly")
defer func() {
channelsUsingLegacyAutoupdate["nightly"] = true
}()

for _, binary := range binaries {
for _, binary := range binaries { //nolint: paralleltest
binary := binary
t.Run(string(binary), func(t *testing.T) {
t.Parallel()

// Set up an update library, but no TUF repo
rootDir := t.TempDir()
updateDir := defaultLibraryDirectory(rootDir)
Expand Down Expand Up @@ -99,6 +101,21 @@ func TestCheckOutLatest_NotAvailableOnNonNightlyChannels(t *testing.T) {
}
}

func TestUsingNewAutoupdater(t *testing.T) {
t.Parallel()

for _, binary := range binaries {
binary := binary
for _, channel := range []string{"beta", "stable", "nightly", "alpha"} {
channel := channel
t.Run(fmt.Sprintf("%s-%s", binary, channel), func(t *testing.T) {
t.Parallel()
require.False(t, UsingNewAutoupdater())
})
}
}
}

func Test_mostRecentVersion(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -190,11 +207,11 @@ func Test_usingNewAutoupdater(t *testing.T) {
}{
{
channelName: "nightly",
usesNewAutoupdater: true,
usesNewAutoupdater: false,
},
{
channelName: "alpha",
usesNewAutoupdater: true,
usesNewAutoupdater: false,
},
{
channelName: "stable",
Expand Down

0 comments on commit 3b04930

Please sign in to comment.