diff --git a/changes/21773-ingest-fleet-maintained-apps b/changes/21773-ingest-fleet-maintained-apps new file mode 100644 index 000000000000..f5f01a3995e5 --- /dev/null +++ b/changes/21773-ingest-fleet-maintained-apps @@ -0,0 +1 @@ +* Added the definition of the Fleet maintained apps and its ingestion. diff --git a/pkg/optjson/stringor.go b/pkg/optjson/stringor.go new file mode 100644 index 000000000000..8ec112fd6045 --- /dev/null +++ b/pkg/optjson/stringor.go @@ -0,0 +1,31 @@ +package optjson + +import ( + "bytes" + "encoding/json" +) + +// StringOr is a JSON value that can be a string or a different type of object +// (e.g. somewhat common for a string or an array of strings, but can also be +// a string or an object, etc.). +type StringOr[T any] struct { + String string + Other T + IsOther bool +} + +func (s StringOr[T]) MarshalJSON() ([]byte, error) { + if s.IsOther { + return json.Marshal(s.Other) + } + return json.Marshal(s.String) +} + +func (s *StringOr[T]) UnmarshalJSON(data []byte) error { + if bytes.HasPrefix(data, []byte(`"`)) { + s.IsOther = false + return json.Unmarshal(data, &s.String) + } + s.IsOther = true + return json.Unmarshal(data, &s.Other) +} diff --git a/pkg/optjson/stringor_test.go b/pkg/optjson/stringor_test.go new file mode 100644 index 000000000000..21c5d511d518 --- /dev/null +++ b/pkg/optjson/stringor_test.go @@ -0,0 +1,137 @@ +package optjson + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestStringOr(t *testing.T) { + type child struct { + Name string `json:"name"` + } + + type target struct { + Field StringOr[[]string] `json:"field"` + Array []StringOr[*child] `json:"array"` + } + + type nested struct { + Inception StringOr[*target] `json:"inception"` + } + + cases := []struct { + name string + getVar func() any + src string // json source to unmarshal into the value returned by getVar + marshalAs string // how the value should marshal back to json + unmarshalErr string // if non-empty, unmarshal should fail with this error + }{ + { + name: "simple string", + getVar: func() any { var s StringOr[int]; return &s }, + src: `"abc"`, + marshalAs: `"abc"`, + }, + { + name: "simple integer", + getVar: func() any { var s StringOr[int]; return &s }, + src: `123`, + marshalAs: `123`, + }, + { + name: "invalid bool", + getVar: func() any { var s StringOr[int]; return &s }, + src: `true`, + unmarshalErr: "cannot unmarshal bool into Go value of type int", + }, + { + name: "field string", + getVar: func() any { var s target; return &s }, + src: `{"field":"abc"}`, + marshalAs: `{"field":"abc", "array": null}`, + }, + { + name: "field strings", + getVar: func() any { var s target; return &s }, + src: `{"field":["a", "b", "c"]}`, + marshalAs: `{"field":["a", "b", "c"], "array": null}`, + }, + { + name: "field empty array", + getVar: func() any { var s target; return &s }, + src: `{"field":[]}`, + marshalAs: `{"field":[], "array": null}`, + }, + { + name: "field invalid object", + getVar: func() any { var s target; return &s }, + src: `{"field":{}}`, + unmarshalErr: "cannot unmarshal object into Go struct field target.field of type []string", + }, + { + name: "array field null", + getVar: func() any { var s target; return &s }, + src: `{"array":null}`, + marshalAs: `{"array":null, "field": ""}`, + }, + { + name: "array field empty", + getVar: func() any { var s target; return &s }, + src: `{"array":[]}`, + marshalAs: `{"array":[], "field": ""}`, + }, + { + name: "array field single", + getVar: func() any { var s target; return &s }, + src: `{"array":["a"]}`, + marshalAs: `{"array":["a"], "field": ""}`, + }, + { + name: "array field empty child", + getVar: func() any { var s target; return &s }, + src: `{"array":["a", {}]}`, + marshalAs: `{"array":["a", {"name":""}], "field": ""}`, + }, + { + name: "array field set child", + getVar: func() any { var s target; return &s }, + src: `{"array":["a", {"name": "x"}]}`, + marshalAs: `{"array":["a", {"name":"x"}], "field": ""}`, + }, + { + name: "inception string", + getVar: func() any { var s nested; return &s }, + src: `{"inception":"a"}`, + marshalAs: `{"inception":"a"}`, + }, + { + name: "inception target field", + getVar: func() any { var s nested; return &s }, + src: `{"inception":{"field":["a", "b"]}}`, + marshalAs: `{"inception":{"field":["a", "b"], "array": null}}`, + }, + { + name: "inception target field and array", + getVar: func() any { var s nested; return &s }, + src: `{"inception":{"field":["a", "b"], "array": ["c", {"name": "x"}]}}`, + marshalAs: `{"inception":{"field":["a", "b"], "array": ["c", {"name": "x"}]}}`, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + target := c.getVar() + err := json.Unmarshal([]byte(c.src), target) + if c.unmarshalErr != "" { + require.ErrorContains(t, err, c.unmarshalErr) + return + } + require.NoError(t, err) + + data, err := json.Marshal(target) + require.NoError(t, err) + require.JSONEq(t, c.marshalAs, string(data)) + }) + } +} diff --git a/server/datastore/mysql/maintained_apps.go b/server/datastore/mysql/maintained_apps.go new file mode 100644 index 000000000000..5080872d9a77 --- /dev/null +++ b/server/datastore/mysql/maintained_apps.go @@ -0,0 +1,55 @@ +package mysql + +import ( + "context" + + "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/jmoiron/sqlx" +) + +func (ds *Datastore) UpsertMaintainedApp(ctx context.Context, app *fleet.MaintainedApp) error { + const upsertStmt = ` +INSERT INTO + fleet_library_apps ( + name, token, version, platform, installer_url, filename, + sha256, bundle_identifier, install_script_content_id, uninstall_script_content_id + ) +VALUES + ( ?, ?, ?, ?, ?, ?, + ?, ?, ?, ? ) +ON DUPLICATE KEY UPDATE + name = VALUES(name), + version = VALUES(version), + platform = VALUES(platform), + installer_url = VALUES(installer_url), + filename = VALUES(filename), + sha256 = VALUES(sha256), + bundle_identifier = VALUES(bundle_identifier), + install_script_content_id = VALUES(install_script_content_id), + uninstall_script_content_id = VALUES(uninstall_script_content_id) +` + + return ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error { + var err error + + // ensure the install script exists + installRes, err := insertScriptContents(ctx, tx, app.InstallScript) + if err != nil { + return ctxerr.Wrap(ctx, err, "insert install script content") + } + installScriptID, _ := installRes.LastInsertId() + + // ensure the uninstall script exists + uninstallRes, err := insertScriptContents(ctx, tx, app.UninstallScript) + if err != nil { + return ctxerr.Wrap(ctx, err, "insert uninstall script content") + } + uninstallScriptID, _ := uninstallRes.LastInsertId() + + // upsert the maintained app + _, err = tx.ExecContext(ctx, upsertStmt, app.Name, app.Token, app.Version, app.Platform, app.InstallerURL, app.Filename, + app.SHA256, app.BundleIdentifier, installScriptID, uninstallScriptID) + return ctxerr.Wrap(ctx, err, "upsert maintained app") + }) +} diff --git a/server/datastore/mysql/maintained_apps_test.go b/server/datastore/mysql/maintained_apps_test.go new file mode 100644 index 000000000000..b011ad8fa2f2 --- /dev/null +++ b/server/datastore/mysql/maintained_apps_test.go @@ -0,0 +1,87 @@ +package mysql + +import ( + "context" + "os" + "testing" + + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/fleetdm/fleet/v4/server/mdm/maintainedapps" + "github.com/go-kit/kit/log" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/require" +) + +func TestMaintainedApps(t *testing.T) { + ds := CreateMySQLDS(t) + + cases := []struct { + name string + fn func(t *testing.T, ds *Datastore) + }{ + {"UpsertMaintainedApps", testUpsertMaintainedApps}, + {"IngestWithBrew", testIngestWithBrew}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + defer TruncateTables(t, ds) + c.fn(t, ds) + }) + } +} + +func testUpsertMaintainedApps(t *testing.T, ds *Datastore) { + ctx := context.Background() + + listSavedApps := func() []*fleet.MaintainedApp { + var apps []*fleet.MaintainedApp + ExecAdhocSQL(t, ds, func(q sqlx.ExtContext) error { + return sqlx.SelectContext(ctx, q, &apps, "SELECT name, version, platform FROM fleet_library_apps ORDER BY token") + }) + return apps + } + + expectedApps := maintainedapps.IngestMaintainedApps(t, ds) + require.Equal(t, expectedApps, listSavedApps()) + + // ingesting again results in no changes + maintainedapps.IngestMaintainedApps(t, ds) + require.Equal(t, expectedApps, listSavedApps()) + + // upsert the figma app, changing the version + err := ds.UpsertMaintainedApp(ctx, &fleet.MaintainedApp{ + Name: "Figma", + Token: "figma", + InstallerURL: "https://desktop.figma.com/mac-arm/Figma-999.9.9.zip", + Version: "999.9.9", + Platform: fleet.MacOSPlatform, + }) + require.NoError(t, err) + + // change the expected app data for figma + for _, app := range expectedApps { + if app.Name == "Figma" { + app.Version = "999.9.9" + break + } + } + require.Equal(t, expectedApps, listSavedApps()) +} + +func testIngestWithBrew(t *testing.T, ds *Datastore) { + if os.Getenv("NETWORK_TEST") == "" { + t.Skip("set environment variable NETWORK_TEST=1 to run") + } + + ctx := context.Background() + err := maintainedapps.Refresh(ctx, ds, log.NewNopLogger()) + require.NoError(t, err) + + expectedTokens := maintainedapps.ExpectedAppTokens(t) + var actualTokens []string + ExecAdhocSQL(t, ds, func(q sqlx.ExtContext) error { + return sqlx.SelectContext(ctx, q, &actualTokens, "SELECT token FROM fleet_library_apps ORDER BY token") + }) + require.ElementsMatch(t, expectedTokens, actualTokens) +} diff --git a/server/datastore/mysql/migrations/tables/20240909145426_AddFleetLibraryAppsTable.go b/server/datastore/mysql/migrations/tables/20240909145426_AddFleetLibraryAppsTable.go index 7a75dfef709a..8fdaed81a997 100644 --- a/server/datastore/mysql/migrations/tables/20240909145426_AddFleetLibraryAppsTable.go +++ b/server/datastore/mysql/migrations/tables/20240909145426_AddFleetLibraryAppsTable.go @@ -12,21 +12,24 @@ func init() { func Up_20240909145426(tx *sql.Tx) error { _, err := tx.Exec(` CREATE TABLE fleet_library_apps ( - id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, + name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, -- the "full_token" field from homebrew's JSON API response -- see e.g. https://formulae.brew.sh/api/cask/1password.json - token varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - version varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - platform varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - installer_url varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - filename varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + token varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + version varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + platform varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + installer_url varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + filename varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, -- hash of the binary downloaded from installer_url, allows us to validate we got the right bytes -- before sending to S3 (and we store installers on S3 under that sha256 hash as identifier). - sha256 varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + sha256 varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + -- bundle_identifier is used to match the library app with a software title in the software_titles table, + -- it is expected to be provided by the hard-coded JSON list of apps in the Fleet library. + bundle_identifier varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - created_at timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6), - updated_at timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), + created_at timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6), + updated_at timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), -- foreign-key ids of the script_contents table. install_script_content_id int unsigned NOT NULL, diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index 8e4df14b7272..dd5e0c12e3e1 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -211,6 +211,7 @@ CREATE TABLE `fleet_library_apps` ( `installer_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `sha256` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `bundle_identifier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `created_at` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6), `updated_at` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `install_script_content_id` int unsigned NOT NULL, diff --git a/server/fleet/datastore.go b/server/fleet/datastore.go index 2689b1114c55..203a126a1618 100644 --- a/server/fleet/datastore.go +++ b/server/fleet/datastore.go @@ -1685,6 +1685,10 @@ type Datastore interface { GetPastActivityDataForVPPAppInstall(ctx context.Context, commandResults *mdm.CommandResults) (*User, *ActivityInstalledAppStoreApp, error) GetVPPTokenByLocation(ctx context.Context, loc string) (*VPPTokenDB, error) + + // UpsertMaintainedApp inserts or updates a maintained app using the updated + // metadata provided via app. + UpsertMaintainedApp(ctx context.Context, app *MaintainedApp) error } // MDMAppleStore wraps nanomdm's storage and adds methods to deal with diff --git a/server/fleet/maintained_apps.go b/server/fleet/maintained_apps.go new file mode 100644 index 000000000000..e78c2a810031 --- /dev/null +++ b/server/fleet/maintained_apps.go @@ -0,0 +1,21 @@ +package fleet + +// MaintainedApp represets an app in the Fleet library of maintained apps, +// as stored in the fleet_library_apps table. +type MaintainedApp struct { + ID uint `json:"id" db:"id"` + Name string `json:"name" db:"name"` + Token string `json:"-" db:"name"` + Version string `json:"version" db:"version"` + Platform AppleDevicePlatform `json:"platform" db:"platform"` + InstallerURL string `json:"-" db:"installer_url"` + Filename string `json:"filename" db:"filename"` + SHA256 string `json:"-" db:"sha256"` + BundleIdentifier string `json:"-" db:"bundle_identifier"` + + // InstallScript and UninstallScript are not stored directly in the table, they + // must be filled via a JOIN on script_contents. On insert/update/upsert, these + // fields are used to provide the content of those scripts. + InstallScript string `json:"install_script" db:"install_script"` + UninstallScript string `json:"uninstall_script" db:"uninstall_script"` +} diff --git a/server/mdm/maintainedapps/apps.json b/server/mdm/maintainedapps/apps.json new file mode 100644 index 000000000000..86aa33ba5cdf --- /dev/null +++ b/server/mdm/maintainedapps/apps.json @@ -0,0 +1,97 @@ +[ + { + "identifier": "1password", + "bundle_identifier": "com.1password.1password", + "installer_format": "zip:app" + }, + { + "identifier": "adobe-acrobat-reader", + "bundle_identifier": "com.adobe.Reader", + "installer_format": "dmg:pkg" + }, + { + "identifier": "box-drive", + "bundle_identifier": "???", + "installer_format": "pkg" + }, + { + "identifier": "brave-browser", + "bundle_identifier": "com.brave.Browser", + "installer_format": "dmg:app" + }, + { + "identifier": "cloudflare-warp", + "bundle_identifier": "com.cloudflare.1dot1dot1dot1.macos", + "installer_format": "pkg" + }, + { + "identifier": "docker", + "bundle_identifier": "com.electron.dockerdesktop", + "installer_format": "dmg:app" + }, + { + "identifier": "figma", + "bundle_identifier": "com.figma.Desktop", + "installer_format": "zip:app" + }, + { + "identifier": "firefox", + "bundle_identifier": "org.mozilla.firefox", + "installer_format": "dmg:app" + }, + { + "identifier": "google-chrome", + "bundle_identifier": "com.google.Chrome", + "installer_format": "dmg:app" + }, + { + "identifier": "microsoft-edge", + "bundle_identifier": "com.microsoft.edgemac", + "installer_format": "pkg" + }, + { + "identifier": "microsoft-excel", + "bundle_identifier": "com.microsoft.Excel", + "installer_format": "pkg" + }, + { + "identifier": "microsoft-teams", + "bundle_identifier": "com.microsoft.teams", + "installer_format": "pkg" + }, + { + "identifier": "microsoft-word", + "bundle_identifier": "com.microsoft.Word", + "installer_format": "pkg" + }, + { + "identifier": "notion", + "bundle_identifier": "notion.id", + "installer_format": "dmg:app" + }, + { + "identifier": "slack", + "bundle_identifier": "com.tinyspeck.slackmacgap", + "installer_format": "dmg:app" + }, + { + "identifier": "teamviewer", + "bundle_identifier": "???", + "installer_format": "pkg" + }, + { + "identifier": "visual-studio-code", + "bundle_identifier": "com.microsoft.VSCode", + "installer_format": "zip:app" + }, + { + "identifier": "whatsapp", + "bundle_identifier": "desktop.WhatsApp", + "installer_format": "zip:app" + }, + { + "identifier": "zoom", + "bundle_identifier": "us.zoom.xos", + "installer_format": "pkg" + } +] diff --git a/server/mdm/maintainedapps/ingest.go b/server/mdm/maintainedapps/ingest.go new file mode 100644 index 000000000000..96fa8cc415a7 --- /dev/null +++ b/server/mdm/maintainedapps/ingest.go @@ -0,0 +1,220 @@ +package maintainedapps + +import ( + "context" + _ "embed" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "os" + "path" + "strings" + "time" + + "github.com/fleetdm/fleet/v4/pkg/fleethttp" + "github.com/fleetdm/fleet/v4/pkg/optjson" + "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" + "github.com/fleetdm/fleet/v4/server/fleet" + kitlog "github.com/go-kit/log" + "golang.org/x/sync/errgroup" +) + +//go:embed apps.json +var appsJSON []byte + +type maintainedApp struct { + Identifier string `json:"identifier"` + BundleIdentifier string `json:"bundle_identifier"` + InstallerFormat string `json:"installer_format"` +} + +const baseBrewAPIURL = "https://formulae.brew.sh/api/" + +// Refresh fetches the latest information about maintained apps from the brew +// API and updates the Fleet database with the new information. +func Refresh(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger) error { + var apps []maintainedApp + if err := json.Unmarshal(appsJSON, &apps); err != nil { + return ctxerr.Wrap(ctx, err, "unmarshal embedded apps.json") + } + + // allow mocking of the brew API for tests + baseURL := baseBrewAPIURL + if v := os.Getenv("FLEET_DEV_BREW_API_URL"); v != "" { + baseURL = v + } + + i := ingester{ + baseURL: baseURL, + ds: ds, + logger: logger, + } + return i.ingest(ctx, apps) +} + +type ingester struct { + baseURL string + ds fleet.Datastore + logger kitlog.Logger +} + +func (i ingester) ingest(ctx context.Context, apps []maintainedApp) error { + var g errgroup.Group + + if !strings.HasSuffix(i.baseURL, "/") { + i.baseURL += "/" + } + + client := fleethttp.NewClient(fleethttp.WithTimeout(10 * time.Second)) + + // run at most 3 concurrent requests to avoid overwhelming the brew API + g.SetLimit(3) + for _, app := range apps { + app := app // capture loop variable, not required in Go 1.23+ + g.Go(func() error { + return i.ingestOne(ctx, app, client) + }) + } + return ctxerr.Wrap(ctx, g.Wait(), "ingest apps") +} + +func (i ingester) ingestOne(ctx context.Context, app maintainedApp, client *http.Client) error { + apiURL := fmt.Sprintf("%scask/%s.json", i.baseURL, app.Identifier) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil) + if err != nil { + return ctxerr.Wrap(ctx, err, "create http request") + } + + res, err := client.Do(req) + if err != nil { + return ctxerr.Wrap(ctx, err, "execute http request") + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return ctxerr.Wrap(ctx, err, "read http response body") + } + + switch res.StatusCode { + case http.StatusOK: + // success, go on + case http.StatusNotFound: + // TODO: delete the existing entry? do nothing and succeed? doing the latter for now. + return nil + default: + if len(body) > 512 { + body = body[:512] + } + return ctxerr.Errorf(ctx, "brew API returned status %d: %s", res.StatusCode, string(body)) + } + + var cask brewCask + if err := json.Unmarshal(body, &cask); err != nil { + return ctxerr.Wrapf(ctx, err, "unmarshal brew cask for %s", app.Identifier) + } + + // validate required fields + if len(cask.Name) == 0 || cask.Name[0] == "" { + return ctxerr.Errorf(ctx, "missing name for cask %s", app.Identifier) + } + if cask.Token == "" { + return ctxerr.Errorf(ctx, "missing token for cask %s", app.Identifier) + } + if cask.Version == "" { + return ctxerr.Errorf(ctx, "missing version for cask %s", app.Identifier) + } + if cask.URL == "" { + return ctxerr.Errorf(ctx, "missing URL for cask %s", app.Identifier) + } + parsedURL, err := url.Parse(cask.URL) + if err != nil { + return ctxerr.Wrapf(ctx, err, "parse URL for cask %s", app.Identifier) + } + filename := path.Base(parsedURL.Path) + + installScript := installScriptForApp(app, &cask) + uninstallScript := uninstallScriptForApp(app, &cask) + + err = i.ds.UpsertMaintainedApp(ctx, &fleet.MaintainedApp{ + Name: cask.Name[0], + Token: cask.Token, + Version: cask.Version, + // for now, maintained apps are always macOS (darwin) + Platform: fleet.MacOSPlatform, + InstallerURL: cask.URL, + Filename: filename, + SHA256: cask.SHA256, + BundleIdentifier: app.BundleIdentifier, + InstallScript: installScript, + UninstallScript: uninstallScript, + }) + return ctxerr.Wrap(ctx, err, "upsert maintained app") +} + +func installScriptForApp(app maintainedApp, cask *brewCask) string { + // TODO: implement install script based on cask and app installer format + return "install" +} + +func uninstallScriptForApp(app maintainedApp, cask *brewCask) string { + // TODO: implement uninstall script based on cask and app installer format + return "uninstall" +} + +type brewCask struct { + Token string `json:"token"` + FullToken string `json:"full_token"` + Tap string `json:"tap"` + Name []string `json:"name"` + Desc string `json:"desc"` + URL string `json:"url"` + Version string `json:"version"` + SHA256 string `json:"sha256"` + Artifacts []*brewArtifact `json:"artifacts"` +} + +// brew artifacts are objects that have one and only one of their fields set. +type brewArtifact struct { + App []string `json:"app"` + // Pkg is a bit like Binary, it is an array with a string and an object as + // first two elements. The object has a choices field with an array of + // objects. See Microsoft Edge. + Pkg []optjson.StringOr[*brewPkgChoices] `json:"pkg"` + Uninstall []*brewUninstall `json:"uninstall"` + Zap []*brewZap `json:"zap"` + // Binary is an array with a string and an object as first two elements. See + // the "docker" and "firefox" casks. + Binary []optjson.StringOr[*brewBinaryTarget] `json:"binary"` +} + +type brewPkgChoices struct { + // At the moment we don't care about the "choices" field on the pkg. + Choices []any `json:"choices"` +} + +type brewBinaryTarget struct { + Target string `json:"target"` +} + +// unlike brewArtifact, a single brewUninstall can have many fields set. +// All fields can have one or multiple strings (string or []string). +type brewUninstall struct { + LaunchCtl optjson.StringOr[[]string] `json:"launchctl"` + Quit optjson.StringOr[[]string] `json:"quit"` + PkgUtil optjson.StringOr[[]string] `json:"pkgutil"` + Script optjson.StringOr[[]string] `json:"script"` + // format: [0]=signal, [1]=process name + Signal optjson.StringOr[[]string] `json:"signal"` + Delete optjson.StringOr[[]string] `json:"delete"` + RmDir optjson.StringOr[[]string] `json:"rmdir"` +} + +// same as brewUninstall, can be []string or string (see Microsoft Teams). +type brewZap struct { + Trash optjson.StringOr[[]string] `json:"trash"` + RmDir optjson.StringOr[[]string] `json:"rmdir"` +} diff --git a/server/mdm/maintainedapps/ingest_test.go b/server/mdm/maintainedapps/ingest_test.go new file mode 100644 index 000000000000..3f1ae68f67ac --- /dev/null +++ b/server/mdm/maintainedapps/ingest_test.go @@ -0,0 +1,168 @@ +package maintainedapps + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "path" + "strings" + "testing" + + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/fleetdm/fleet/v4/server/mock" + "github.com/go-kit/log" + "github.com/stretchr/testify/require" +) + +func TestIngestValidations(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var cask brewCask + + appToken := strings.TrimSuffix(path.Base(r.URL.Path), ".json") + switch appToken { + case "fail": + w.WriteHeader(http.StatusInternalServerError) + return + + case "notfound": + w.WriteHeader(http.StatusNotFound) + return + + case "noname": + cask = brewCask{ + Token: appToken, + Name: nil, + URL: "https://example.com", + Version: "1.0", + } + + case "emptyname": + cask = brewCask{ + Token: appToken, + Name: []string{""}, + URL: "https://example.com", + Version: "1.0", + } + + case "notoken": + cask = brewCask{ + Token: "", + Name: []string{appToken}, + URL: "https://example.com", + Version: "1.0", + } + + case "noversion": + cask = brewCask{ + Token: appToken, + Name: []string{appToken}, + URL: "https://example.com", + Version: "", + } + + case "nourl": + cask = brewCask{ + Token: appToken, + Name: []string{appToken}, + URL: "", + Version: "1.0", + } + + case "invalidurl": + cask = brewCask{ + Token: appToken, + Name: []string{appToken}, + URL: "https://\x00\x01\x02", + Version: "1.0", + } + + case "ok": + cask = brewCask{ + Token: appToken, + Name: []string{appToken}, + URL: "https://example.com", + Version: "1.0", + } + + default: + w.WriteHeader(http.StatusBadRequest) + t.Fatalf("unexpected app token %s", appToken) + } + + err := json.NewEncoder(w).Encode(cask) + require.NoError(t, err) + })) + t.Cleanup(srv.Close) + + ctx := context.Background() + ds := new(mock.Store) + ds.UpsertMaintainedAppFunc = func(ctx context.Context, app *fleet.MaintainedApp) error { + return nil + } + + cases := []struct { + appToken string + wantErr string + upsertCalled bool + }{ + {"fail", "brew API returned status 500", false}, + {"notfound", "", false}, + {"noname", "missing name for cask noname", false}, + {"emptyname", "missing name for cask emptyname", false}, + {"notoken", "missing token for cask notoken", false}, + {"noversion", "missing version for cask noversion", false}, + {"nourl", "missing URL for cask nourl", false}, + {"invalidurl", "parse URL for cask invalidurl", false}, + {"ok", "", true}, + {"multi:ok", "", true}, + {"multi:fail", "brew API returned status 500", true}, + } + for _, c := range cases { + t.Run(c.appToken, func(t *testing.T) { + i := ingester{baseURL: srv.URL, ds: ds, logger: log.NewNopLogger()} + + var apps []maintainedApp + var ignoreDSCheck bool + if strings.HasPrefix(c.appToken, "multi:") { + token := strings.TrimPrefix(c.appToken, "multi:") + if token == "fail" { + // do not check the DS call, as it may or may not have happened depending + // on the concurrent execution + ignoreDSCheck = true + // send 3 ok, one fail + apps = []maintainedApp{ + {Identifier: "ok", BundleIdentifier: "abc", InstallerFormat: "pkg"}, + {Identifier: "fail", BundleIdentifier: "def", InstallerFormat: "pkg"}, + {Identifier: "ok", BundleIdentifier: "ghi", InstallerFormat: "pkg"}, + {Identifier: "ok", BundleIdentifier: "klm", InstallerFormat: "pkg"}, + } + } else { + // send 4 apps with ok + apps = []maintainedApp{ + {Identifier: token, BundleIdentifier: "abc", InstallerFormat: "pkg"}, + {Identifier: token, BundleIdentifier: "def", InstallerFormat: "pkg"}, + {Identifier: token, BundleIdentifier: "ghi", InstallerFormat: "pkg"}, + {Identifier: token, BundleIdentifier: "klm", InstallerFormat: "pkg"}, + } + } + } else { + apps = []maintainedApp{ + {Identifier: c.appToken, BundleIdentifier: "abc", InstallerFormat: "pkg"}, + } + } + + err := i.ingest(ctx, apps) + if c.wantErr == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, c.wantErr) + } + + if !ignoreDSCheck { + require.Equal(t, c.upsertCalled, ds.UpsertMaintainedAppFuncInvoked) + } + ds.UpsertMaintainedAppFuncInvoked = false + }) + } +} diff --git a/server/mdm/maintainedapps/testdata/1password.json b/server/mdm/maintainedapps/testdata/1password.json new file mode 100644 index 000000000000..4b769c7b99fa --- /dev/null +++ b/server/mdm/maintainedapps/testdata/1password.json @@ -0,0 +1,130 @@ +{ + "token": "1password", + "full_token": "1password", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "1Password" + ], + "desc": "Password manager that keeps all passwords secure behind one password", + "homepage": "https://1password.com/", + "url": "https://downloads.1password.com/mac/1Password-8.10.44-aarch64.zip", + "url_specs": {}, + "version": "8.10.44", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "2b9f242f27ba3a6e45893e4436a81eebd62478746abf655c761c08e1984024d3", + "artifacts": [ + { + "app": [ + "1Password.app" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/2BUA8C4S2C.com.1password*", + "~/Library/Application Scripts/2BUA8C4S2C.com.agilebits", + "~/Library/Application Scripts/com.1password.1password-launcher", + "~/Library/Application Scripts/com.1password.browser-support", + "~/Library/Application Support/1Password", + "~/Library/Application Support/Arc/User Data/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.1password.1password.sfl*", + "~/Library/Application Support/CrashReporter/1Password*", + "~/Library/Application Support/Google/Chrome Beta/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Google/Chrome Canary/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Google/Chrome Dev/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Microsoft Edge Beta/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Microsoft Edge Canary/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Microsoft Edge Dev/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Microsoft Edge/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Mozilla/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Application Support/Vivaldi/NativeMessagingHosts/com.1password.1password.json", + "~/Library/Containers/2BUA8C4S2C.com.1password.browser-helper", + "~/Library/Containers/com.1password.1password*", + "~/Library/Containers/com.1password.browser-support", + "~/Library/Group Containers/2BUA8C4S2C.com.1password", + "~/Library/Group Containers/2BUA8C4S2C.com.agilebits", + "~/Library/Logs/1Password", + "~/Library/Preferences/com.1password.1password.plist", + "~/Library/Preferences/group.com.1password.plist", + "~/Library/Saved Application State/com.1password.1password.savedState" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": { + "cask": [ + "1password@beta", + "1password@nightly" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/1/1password.rb", + "ruby_source_checksum": { + "sha256": "277e7b256383ac4dd2ea259c936a426120c95aeeae895fae3916c09da955d35d" + }, + "variations": { + "sequoia": { + "url": "https://downloads.1password.com/mac/1Password-8.10.44-x86_64.zip", + "sha256": "fd26d4fcac880c2ecd7c0886a1ecbc5a727b580c7790e2b7c1fdb8713d026f3f" + }, + "sonoma": { + "url": "https://downloads.1password.com/mac/1Password-8.10.44-x86_64.zip", + "sha256": "fd26d4fcac880c2ecd7c0886a1ecbc5a727b580c7790e2b7c1fdb8713d026f3f" + }, + "ventura": { + "url": "https://downloads.1password.com/mac/1Password-8.10.44-x86_64.zip", + "sha256": "fd26d4fcac880c2ecd7c0886a1ecbc5a727b580c7790e2b7c1fdb8713d026f3f" + }, + "monterey": { + "url": "https://downloads.1password.com/mac/1Password-8.10.44-x86_64.zip", + "sha256": "fd26d4fcac880c2ecd7c0886a1ecbc5a727b580c7790e2b7c1fdb8713d026f3f" + }, + "big_sur": { + "url": "https://downloads.1password.com/mac/1Password-8.10.44-x86_64.zip", + "sha256": "fd26d4fcac880c2ecd7c0886a1ecbc5a727b580c7790e2b7c1fdb8713d026f3f" + }, + "catalina": { + "url": "https://downloads.1password.com/mac/1Password-8.10.44-x86_64.zip", + "sha256": "fd26d4fcac880c2ecd7c0886a1ecbc5a727b580c7790e2b7c1fdb8713d026f3f" + } + }, + "analytics": { + "install": { + "30d": { + "1password": 3585 + }, + "90d": { + "1password": 10054 + }, + "365d": { + "1password": 41293 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/adobe-acrobat-reader.json b/server/mdm/maintainedapps/testdata/adobe-acrobat-reader.json new file mode 100644 index 000000000000..719d8386f7ca --- /dev/null +++ b/server/mdm/maintainedapps/testdata/adobe-acrobat-reader.json @@ -0,0 +1,97 @@ +{ + "token": "adobe-acrobat-reader", + "full_token": "adobe-acrobat-reader", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Adobe Acrobat Reader" + ], + "desc": "View, print, and comment on PDF documents", + "homepage": "https://www.adobe.com/acrobat/pdf-reader.html", + "url": "https://ardownload2.adobe.com/pub/adobe/reader/mac/AcrobatDC/2400221005/AcroRdrDC_2400221005_MUI.dmg", + "url_specs": {}, + "version": "24.002.21005", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "55a53014b5e060658921f6d3a6d20fa64aae5b09fc9f6ea3d78e9c2378dab934", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.adobe.ARMDC.Communicator", + "com.adobe.ARMDC.SMJobBlessHelper", + "com.adobe.ARMDCHelper.cc24aef4a1b90ed56a725c38014c95072f92651fb65e1bf9c8e43c37a23d420d" + ], + "quit": [ + "com.adobe.AdobeRdrCEF", + "com.adobe.AdobeRdrCEFHelper", + "com.adobe.Reader" + ], + "pkgutil": [ + "com.adobe.acrobat.DC.reader.*", + "com.adobe.armdc.app.pkg", + "com.adobe.RdrServicesUpdater" + ], + "delete": [ + "/Applications/Adobe Acrobat Reader.app", + "/Library/Preferences/com.adobe.reader.DC.WebResource.plist" + ] + } + ] + }, + { + "pkg": [ + "AcroRdrDC_2400221005_MUI.pkg" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Caches/com.adobe.Reader", + "~/Library/HTTPStorages/com.adobe.Reader.binarycookies", + "~/Library/Preferences/com.adobe.AdobeRdrCEFHelper.plist", + "~/Library/Preferences/com.adobe.crashreporter.plist", + "~/Library/Preferences/com.adobe.Reader.plist" + ] + } + ] + } + ], + "caveats": null, + "depends_on": {}, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/a/adobe-acrobat-reader.rb", + "ruby_source_checksum": { + "sha256": "8d9c2e12ab57cb1c4c33ef523a35caf2a5ae923631fdf8d3eae2162a901d44ad" + }, + "variations": {}, + "analytics": { + "install": { + "30d": { + "adobe-acrobat-reader": 1826 + }, + "90d": { + "adobe-acrobat-reader": 6682 + }, + "365d": { + "adobe-acrobat-reader": 36717 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/box-drive.json b/server/mdm/maintainedapps/testdata/box-drive.json new file mode 100644 index 000000000000..543d1959ea1f --- /dev/null +++ b/server/mdm/maintainedapps/testdata/box-drive.json @@ -0,0 +1,102 @@ +{ + "token": "box-drive", + "full_token": "box-drive", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Box Drive" + ], + "desc": "Client for the Box cloud storage service", + "homepage": "https://www.box.com/drive", + "url": "https://e3.boxcdn.net/desktop/releases/mac/BoxDrive-2.40.345.pkg", + "url_specs": { + "verified": "e3.boxcdn.net/desktop/releases/mac/" + }, + "version": "2.40.345", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "203493ec8aedce5502d36464e02665a1d9e01ad0aed3d86468b3df12280ffb1c", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.box.desktop.helper", + "quit": [ + "com.box.Box-Local-Com-Server", + "com.box.desktop", + "com.box.desktop.findersyncext", + "com.box.desktop.helper", + "com.box.desktop.ui" + ], + "script": "/Library/Application Support/Box/uninstall_box_drive", + "pkgutil": "com.box.desktop.installer.*" + } + ] + }, + { + "pkg": [ + "BoxDrive-2.40.345.pkg" + ] + }, + { + "zap": [ + { + "trash": [ + "~/.Box_*", + "~/Library/Application Support/Box/Box", + "~/Library/Application Support/FileProvider/com.box.desktop.boxfileprovider", + "~/Library/Containers/com.box.desktop.findersyncext", + "~/Library/Logs/Box/Box", + "~/Library/Preferences/com.box.desktop.plist", + "~/Library/Preferences/com.box.desktop.ui.plist" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.11" + ] + } + }, + "conflicts_with": { + "cask": [ + "box-sync" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/b/box-drive.rb", + "ruby_source_checksum": { + "sha256": "8f773c3189e6f031e0f454c25943ce602bdc2a42dc891a1db7fe3b63e17be249" + }, + "variations": {}, + "analytics": { + "install": { + "30d": { + "box-drive": 81 + }, + "90d": { + "box-drive": 209 + }, + "365d": { + "box-drive": 1066 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/brave-browser.json b/server/mdm/maintainedapps/testdata/brave-browser.json new file mode 100644 index 000000000000..dfe62913e855 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/brave-browser.json @@ -0,0 +1,106 @@ +{ + "token": "brave-browser", + "full_token": "brave-browser", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Brave" + ], + "desc": "Web browser focusing on privacy", + "homepage": "https://brave.com/", + "url": "https://updates-cdn.bravesoftware.com/sparkle/Brave-Browser/stable-arm64/169.162/Brave-Browser-arm64.dmg", + "url_specs": { + "verified": "updates-cdn.bravesoftware.com/sparkle/Brave-Browser/" + }, + "version": "1.69.162.0", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "f73ee45cf385182bde54bcbddad65d45ac2b1e9fd14798660af9d7e34f539d1a", + "artifacts": [ + { + "app": [ + "Brave Browser.app" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Support/BraveSoftware", + "~/Library/Caches/BraveSoftware", + "~/Library/Caches/com.brave.Browser", + "~/Library/HTTPStorages/com.brave.Browser", + "~/Library/Preferences/com.brave.Browser.plist", + "~/Library/Saved Application State/com.brave.Browser.savedState" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/b/brave-browser.rb", + "ruby_source_checksum": { + "sha256": "5f2f1bab8cf16032cf73ab0a91c5f83df42333350245e28565abc08da1d0b575" + }, + "variations": { + "sequoia": { + "url": "https://updates-cdn.bravesoftware.com/sparkle/Brave-Browser/stable/169.162/Brave-Browser-x64.dmg", + "sha256": "26d0744c077c74684b09c378e6ee4c55138d3c935b651f9028d04f9b9d61b0e9" + }, + "sonoma": { + "url": "https://updates-cdn.bravesoftware.com/sparkle/Brave-Browser/stable/169.162/Brave-Browser-x64.dmg", + "sha256": "26d0744c077c74684b09c378e6ee4c55138d3c935b651f9028d04f9b9d61b0e9" + }, + "ventura": { + "url": "https://updates-cdn.bravesoftware.com/sparkle/Brave-Browser/stable/169.162/Brave-Browser-x64.dmg", + "sha256": "26d0744c077c74684b09c378e6ee4c55138d3c935b651f9028d04f9b9d61b0e9" + }, + "monterey": { + "url": "https://updates-cdn.bravesoftware.com/sparkle/Brave-Browser/stable/169.162/Brave-Browser-x64.dmg", + "sha256": "26d0744c077c74684b09c378e6ee4c55138d3c935b651f9028d04f9b9d61b0e9" + }, + "big_sur": { + "url": "https://updates-cdn.bravesoftware.com/sparkle/Brave-Browser/stable/169.162/Brave-Browser-x64.dmg", + "sha256": "26d0744c077c74684b09c378e6ee4c55138d3c935b651f9028d04f9b9d61b0e9" + }, + "catalina": { + "url": "https://updates-cdn.bravesoftware.com/sparkle/Brave-Browser/stable/169.162/Brave-Browser-x64.dmg", + "sha256": "26d0744c077c74684b09c378e6ee4c55138d3c935b651f9028d04f9b9d61b0e9" + } + }, + "analytics": { + "install": { + "30d": { + "brave-browser": 5244 + }, + "90d": { + "brave-browser": 14764 + }, + "365d": { + "brave-browser": 60400 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/cloudflare-warp.json b/server/mdm/maintainedapps/testdata/cloudflare-warp.json new file mode 100644 index 000000000000..2981f0bc8911 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/cloudflare-warp.json @@ -0,0 +1,95 @@ +{ + "token": "cloudflare-warp", + "full_token": "cloudflare-warp", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Cloudflare WARP" + ], + "desc": "Free app that makes your Internet safer", + "homepage": "https://cloudflarewarp.com/", + "url": "https://1111-releases.cloudflareclient.com/mac/Cloudflare_WARP_2024.6.474.0.pkg", + "url_specs": { + "verified": "1111-releases.cloudflareclient.com/mac/" + }, + "version": "2024.6.474.0", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "2a07e1c509fc3d95f7fe9b90362b4d853fcc0433808a1d68aaabf10406145be0", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.cloudflare.1dot1dot1dot1.macos.loginlauncherapp", + "com.cloudflare.1dot1dot1dot1.macos.warp.daemon" + ], + "quit": "com.cloudflare.1dot1dot1dot1.macos", + "pkgutil": "com.cloudflare.1dot1dot1dot1.macos" + } + ] + }, + { + "pkg": [ + "Cloudflare_WARP_2024.6.474.0.pkg" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.cloudflare.1dot1dot1dot1.macos.loginlauncherapp", + "~/Library/Application Support/com.cloudflare.1dot1dot1dot1.macos", + "~/Library/Caches/com.cloudflare.1dot1dot1dot1.macos", + "~/Library/Caches/com.plausiblelabs.crashreporter.data/com.cloudflare.1dot1dot1dot1.macos", + "~/Library/Containers/com.cloudflare.1dot1dot1dot1.macos.loginlauncherapp", + "~/Library/HTTPStorages/com.cloudflare.1dot1dot1dot1.macos", + "~/Library/HTTPStorages/com.cloudflare.1dot1dot1dot1.macos.binarycookies", + "~/Library/Preferences/com.cloudflare.1dot1dot1dot1.macos.plist" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/c/cloudflare-warp.rb", + "ruby_source_checksum": { + "sha256": "1b01184ffd16b49e97843b1cd3f7f7435199bac35487bea61d892b992b1f95f5" + }, + "variations": {}, + "analytics": { + "install": { + "30d": { + "cloudflare-warp": 675 + }, + "90d": { + "cloudflare-warp": 2045 + }, + "365d": { + "cloudflare-warp": 8333 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/docker.json b/server/mdm/maintainedapps/testdata/docker.json new file mode 100644 index 000000000000..15aec7b0b8be --- /dev/null +++ b/server/mdm/maintainedapps/testdata/docker.json @@ -0,0 +1,1004 @@ +{ + "token": "docker", + "full_token": "docker", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Docker Desktop", + "Docker Community Edition", + "Docker CE" + ], + "desc": "App to build and share containerised applications and microservices", + "homepage": "https://www.docker.com/products/docker-desktop", + "url": "https://desktop.docker.com/mac/main/arm64/165256/Docker.dmg", + "url_specs": {}, + "version": "4.34.0,165256", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "1d5fdbacd97373bcda95645f4d1ee32cff278afbec86f591788232c169a7b243", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.docker.helper", + "com.docker.socket", + "com.docker.vmnetd" + ], + "quit": "com.docker.docker", + "delete": [ + "/Library/PrivilegedHelperTools/com.docker.socket", + "/Library/PrivilegedHelperTools/com.docker.vmnetd" + ], + "rmdir": "~/.docker/bin" + } + ] + }, + { + "app": [ + "Docker.app" + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker-compose.fish" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker", + { + "target": "/usr/local/bin/docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-desktop", + { + "target": "/usr/local/bin/docker-credential-desktop" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-ecr-login", + { + "target": "/usr/local/bin/docker-credential-ecr-login" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain", + { + "target": "/usr/local/bin/docker-credential-osxkeychain" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-index", + { + "target": "/usr/local/bin/docker-index" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/kubectl", + { + "target": "/usr/local/bin/kubectl.docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/cli-plugins/docker-compose", + { + "target": "/usr/local/cli-plugins/docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker.fish" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/hub-tool", + { + "target": "/usr/local/bin/hub-tool" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker-compose" + } + ] + }, + { + "uninstall_postflight": null + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "/usr/local/bin/docker-compose.backup", + "/usr/local/bin/docker.backup", + "~/.docker", + "~/Library/Application Scripts/com.docker.helper", + "~/Library/Application Scripts/group.com.docker", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*", + "~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker", + "~/Library/Application Support/Docker Desktop", + "~/Library/Caches/com.docker.docker", + "~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker", + "~/Library/Caches/KSCrashReports/Docker", + "~/Library/Containers/com.docker.docker", + "~/Library/Containers/com.docker.helper", + "~/Library/Group Containers/group.com.docker", + "~/Library/HTTPStorages/com.docker.docker", + "~/Library/HTTPStorages/com.docker.docker.binarycookies", + "~/Library/Logs/Docker Desktop", + "~/Library/Preferences/com.docker.docker.plist", + "~/Library/Preferences/com.electron.docker-frontend.plist", + "~/Library/Preferences/com.electron.dockerdesktop.plist", + "~/Library/Saved Application State/com.electron.docker-frontend.savedState", + "~/Library/Saved Application State/com.electron.dockerdesktop.savedState" + ], + "rmdir": [ + "~/Library/Caches/com.plausiblelabs.crashreporter.data", + "~/Library/Caches/KSCrashReports" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "12" + ] + } + }, + "conflicts_with": { + "cask": [ + "rancher" + ], + "formula": [ + "docker", + "docker-completion", + "docker-compose", + "docker-credential-helper-ecr" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/d/docker.rb", + "ruby_source_checksum": { + "sha256": "5e6d89c8cd84c92dc1d331f47ad61cd32193036bd7a6c5e1d00ff208f57bad08" + }, + "variations": { + "sequoia": { + "url": "https://desktop.docker.com/mac/main/amd64/165256/Docker.dmg", + "sha256": "ea4e558d38fac4caafeb73134f012524f3b5a3b90894485f19ae99b0aa7cde19", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.docker.helper", + "com.docker.socket", + "com.docker.vmnetd" + ], + "quit": "com.docker.docker", + "delete": [ + "/Library/PrivilegedHelperTools/com.docker.socket", + "/Library/PrivilegedHelperTools/com.docker.vmnetd" + ], + "rmdir": "~/.docker/bin" + } + ] + }, + { + "app": [ + "Docker.app" + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker-compose.fish" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker", + { + "target": "/usr/local/bin/docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-desktop", + { + "target": "/usr/local/bin/docker-credential-desktop" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-ecr-login", + { + "target": "/usr/local/bin/docker-credential-ecr-login" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain", + { + "target": "/usr/local/bin/docker-credential-osxkeychain" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-index", + { + "target": "/usr/local/bin/docker-index" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/hub-tool", + { + "target": "/usr/local/bin/hub-tool" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/kubectl", + { + "target": "/usr/local/bin/kubectl.docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/cli-plugins/docker-compose", + { + "target": "/usr/local/cli-plugins/docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker.fish" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/bin/com.docker.hyperkit", + { + "target": "/usr/local/bin/hyperkit" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker-compose" + } + ] + }, + { + "uninstall_postflight": null + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "/usr/local/bin/docker-compose.backup", + "/usr/local/bin/docker.backup", + "~/.docker", + "~/Library/Application Scripts/com.docker.helper", + "~/Library/Application Scripts/group.com.docker", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*", + "~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker", + "~/Library/Application Support/Docker Desktop", + "~/Library/Caches/com.docker.docker", + "~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker", + "~/Library/Caches/KSCrashReports/Docker", + "~/Library/Containers/com.docker.docker", + "~/Library/Containers/com.docker.helper", + "~/Library/Group Containers/group.com.docker", + "~/Library/HTTPStorages/com.docker.docker", + "~/Library/HTTPStorages/com.docker.docker.binarycookies", + "~/Library/Logs/Docker Desktop", + "~/Library/Preferences/com.docker.docker.plist", + "~/Library/Preferences/com.electron.docker-frontend.plist", + "~/Library/Preferences/com.electron.dockerdesktop.plist", + "~/Library/Saved Application State/com.electron.docker-frontend.savedState", + "~/Library/Saved Application State/com.electron.dockerdesktop.savedState" + ], + "rmdir": [ + "~/Library/Caches/com.plausiblelabs.crashreporter.data", + "~/Library/Caches/KSCrashReports" + ] + } + ] + } + ] + }, + "sonoma": { + "url": "https://desktop.docker.com/mac/main/amd64/165256/Docker.dmg", + "sha256": "ea4e558d38fac4caafeb73134f012524f3b5a3b90894485f19ae99b0aa7cde19", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.docker.helper", + "com.docker.socket", + "com.docker.vmnetd" + ], + "quit": "com.docker.docker", + "delete": [ + "/Library/PrivilegedHelperTools/com.docker.socket", + "/Library/PrivilegedHelperTools/com.docker.vmnetd" + ], + "rmdir": "~/.docker/bin" + } + ] + }, + { + "app": [ + "Docker.app" + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker-compose.fish" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker", + { + "target": "/usr/local/bin/docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-desktop", + { + "target": "/usr/local/bin/docker-credential-desktop" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-ecr-login", + { + "target": "/usr/local/bin/docker-credential-ecr-login" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain", + { + "target": "/usr/local/bin/docker-credential-osxkeychain" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-index", + { + "target": "/usr/local/bin/docker-index" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/hub-tool", + { + "target": "/usr/local/bin/hub-tool" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/kubectl", + { + "target": "/usr/local/bin/kubectl.docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/cli-plugins/docker-compose", + { + "target": "/usr/local/cli-plugins/docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker.fish" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/bin/com.docker.hyperkit", + { + "target": "/usr/local/bin/hyperkit" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker-compose" + } + ] + }, + { + "uninstall_postflight": null + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "/usr/local/bin/docker-compose.backup", + "/usr/local/bin/docker.backup", + "~/.docker", + "~/Library/Application Scripts/com.docker.helper", + "~/Library/Application Scripts/group.com.docker", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*", + "~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker", + "~/Library/Application Support/Docker Desktop", + "~/Library/Caches/com.docker.docker", + "~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker", + "~/Library/Caches/KSCrashReports/Docker", + "~/Library/Containers/com.docker.docker", + "~/Library/Containers/com.docker.helper", + "~/Library/Group Containers/group.com.docker", + "~/Library/HTTPStorages/com.docker.docker", + "~/Library/HTTPStorages/com.docker.docker.binarycookies", + "~/Library/Logs/Docker Desktop", + "~/Library/Preferences/com.docker.docker.plist", + "~/Library/Preferences/com.electron.docker-frontend.plist", + "~/Library/Preferences/com.electron.dockerdesktop.plist", + "~/Library/Saved Application State/com.electron.docker-frontend.savedState", + "~/Library/Saved Application State/com.electron.dockerdesktop.savedState" + ], + "rmdir": [ + "~/Library/Caches/com.plausiblelabs.crashreporter.data", + "~/Library/Caches/KSCrashReports" + ] + } + ] + } + ] + }, + "ventura": { + "url": "https://desktop.docker.com/mac/main/amd64/165256/Docker.dmg", + "sha256": "ea4e558d38fac4caafeb73134f012524f3b5a3b90894485f19ae99b0aa7cde19", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.docker.helper", + "com.docker.socket", + "com.docker.vmnetd" + ], + "quit": "com.docker.docker", + "delete": [ + "/Library/PrivilegedHelperTools/com.docker.socket", + "/Library/PrivilegedHelperTools/com.docker.vmnetd" + ], + "rmdir": "~/.docker/bin" + } + ] + }, + { + "app": [ + "Docker.app" + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker-compose.fish" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker", + { + "target": "/usr/local/bin/docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-desktop", + { + "target": "/usr/local/bin/docker-credential-desktop" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-ecr-login", + { + "target": "/usr/local/bin/docker-credential-ecr-login" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain", + { + "target": "/usr/local/bin/docker-credential-osxkeychain" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-index", + { + "target": "/usr/local/bin/docker-index" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/hub-tool", + { + "target": "/usr/local/bin/hub-tool" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/kubectl", + { + "target": "/usr/local/bin/kubectl.docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/cli-plugins/docker-compose", + { + "target": "/usr/local/cli-plugins/docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker.fish" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/bin/com.docker.hyperkit", + { + "target": "/usr/local/bin/hyperkit" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker-compose" + } + ] + }, + { + "uninstall_postflight": null + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "/usr/local/bin/docker-compose.backup", + "/usr/local/bin/docker.backup", + "~/.docker", + "~/Library/Application Scripts/com.docker.helper", + "~/Library/Application Scripts/group.com.docker", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*", + "~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker", + "~/Library/Application Support/Docker Desktop", + "~/Library/Caches/com.docker.docker", + "~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker", + "~/Library/Caches/KSCrashReports/Docker", + "~/Library/Containers/com.docker.docker", + "~/Library/Containers/com.docker.helper", + "~/Library/Group Containers/group.com.docker", + "~/Library/HTTPStorages/com.docker.docker", + "~/Library/HTTPStorages/com.docker.docker.binarycookies", + "~/Library/Logs/Docker Desktop", + "~/Library/Preferences/com.docker.docker.plist", + "~/Library/Preferences/com.electron.docker-frontend.plist", + "~/Library/Preferences/com.electron.dockerdesktop.plist", + "~/Library/Saved Application State/com.electron.docker-frontend.savedState", + "~/Library/Saved Application State/com.electron.dockerdesktop.savedState" + ], + "rmdir": [ + "~/Library/Caches/com.plausiblelabs.crashreporter.data", + "~/Library/Caches/KSCrashReports" + ] + } + ] + } + ] + }, + "monterey": { + "url": "https://desktop.docker.com/mac/main/amd64/165256/Docker.dmg", + "sha256": "ea4e558d38fac4caafeb73134f012524f3b5a3b90894485f19ae99b0aa7cde19", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.docker.helper", + "com.docker.socket", + "com.docker.vmnetd" + ], + "quit": "com.docker.docker", + "delete": [ + "/Library/PrivilegedHelperTools/com.docker.socket", + "/Library/PrivilegedHelperTools/com.docker.vmnetd" + ], + "rmdir": "~/.docker/bin" + } + ] + }, + { + "app": [ + "Docker.app" + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker-compose.fish" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker", + { + "target": "/usr/local/bin/docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-desktop", + { + "target": "/usr/local/bin/docker-credential-desktop" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-ecr-login", + { + "target": "/usr/local/bin/docker-credential-ecr-login" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain", + { + "target": "/usr/local/bin/docker-credential-osxkeychain" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/docker-index", + { + "target": "/usr/local/bin/docker-index" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/hub-tool", + { + "target": "/usr/local/bin/hub-tool" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/bin/kubectl", + { + "target": "/usr/local/bin/kubectl.docker" + } + ] + }, + { + "binary": [ + "$APPDIR/Docker.app/Contents/Resources/cli-plugins/docker-compose", + { + "target": "/usr/local/cli-plugins/docker-compose" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.zsh-completion", + { + "target": "$HOMEBREW_PREFIX/share/zsh/site-functions/_docker" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker.fish-completion", + { + "target": "$HOMEBREW_PREFIX/share/fish/vendor_completions.d/docker.fish" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/bin/com.docker.hyperkit", + { + "target": "/usr/local/bin/hyperkit" + } + ] + }, + { + "binary": [ + "Docker.app/Contents/Resources/etc/docker-compose.bash-completion", + { + "target": "$HOMEBREW_PREFIX/etc/bash_completion.d/docker-compose" + } + ] + }, + { + "uninstall_postflight": null + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "/usr/local/bin/docker-compose.backup", + "/usr/local/bin/docker.backup", + "~/.docker", + "~/Library/Application Scripts/com.docker.helper", + "~/Library/Application Scripts/group.com.docker", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*", + "~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker", + "~/Library/Application Support/Docker Desktop", + "~/Library/Caches/com.docker.docker", + "~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker", + "~/Library/Caches/KSCrashReports/Docker", + "~/Library/Containers/com.docker.docker", + "~/Library/Containers/com.docker.helper", + "~/Library/Group Containers/group.com.docker", + "~/Library/HTTPStorages/com.docker.docker", + "~/Library/HTTPStorages/com.docker.docker.binarycookies", + "~/Library/Logs/Docker Desktop", + "~/Library/Preferences/com.docker.docker.plist", + "~/Library/Preferences/com.electron.docker-frontend.plist", + "~/Library/Preferences/com.electron.dockerdesktop.plist", + "~/Library/Saved Application State/com.electron.docker-frontend.savedState", + "~/Library/Saved Application State/com.electron.dockerdesktop.savedState" + ], + "rmdir": [ + "~/Library/Caches/com.plausiblelabs.crashreporter.data", + "~/Library/Caches/KSCrashReports" + ] + } + ] + } + ] + } + }, + "analytics": { + "install": { + "30d": { + "docker": 18303 + }, + "90d": { + "docker": 54826 + }, + "365d": { + "docker": 232250 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/expected_apps.json b/server/mdm/maintainedapps/testdata/expected_apps.json new file mode 100644 index 000000000000..1da9cc4584a0 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/expected_apps.json @@ -0,0 +1,97 @@ +[ + { + "name": "1Password", + "version": "8.10.44", + "platform": "darwin" + }, + { + "name": "Adobe Acrobat Reader", + "version": "24.002.21005", + "platform": "darwin" + }, + { + "name": "Box Drive", + "version": "2.40.345", + "platform": "darwin" + }, + { + "name": "Brave", + "version": "1.69.162.0", + "platform": "darwin" + }, + { + "name": "Cloudflare WARP", + "version": "2024.6.474.0", + "platform": "darwin" + }, + { + "name": "Docker Desktop", + "version": "4.34.0,165256", + "platform": "darwin" + }, + { + "name": "Figma", + "version": "124.3.2", + "platform": "darwin" + }, + { + "name": "Mozilla Firefox", + "version": "130.0", + "platform": "darwin" + }, + { + "name": "Google Chrome", + "version": "128.0.6613.120", + "platform": "darwin" + }, + { + "name": "Microsoft Edge", + "version": "128.0.2739.67,be6d4c8f-ec75-405e-a5f7-fec66b2898a2", + "platform": "darwin" + }, + { + "name": "Microsoft Excel", + "version": "16.88.24081116", + "platform": "darwin" + }, + { + "name": "Microsoft Teams", + "version": "24215.1002.3039.5089", + "platform": "darwin" + }, + { + "name": "Microsoft Word", + "version": "16.88.24081116", + "platform": "darwin" + }, + { + "name": "Notion", + "version": "3.14.0", + "platform": "darwin" + }, + { + "name": "Slack", + "version": "4.40.126", + "platform": "darwin" + }, + { + "name": "TeamViewer", + "version": "15.57.5", + "platform": "darwin" + }, + { + "name": "Microsoft Visual Studio Code", + "version": "1.93.0", + "platform": "darwin" + }, + { + "name": "WhatsApp", + "version": "2.24.16.80", + "platform": "darwin" + }, + { + "name": "Zoom", + "version": "6.1.11.39163", + "platform": "darwin" + } +] diff --git a/server/mdm/maintainedapps/testdata/figma.json b/server/mdm/maintainedapps/testdata/figma.json new file mode 100644 index 000000000000..d8af9b3e4a8f --- /dev/null +++ b/server/mdm/maintainedapps/testdata/figma.json @@ -0,0 +1,114 @@ +{ + "token": "figma", + "full_token": "figma", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Figma" + ], + "desc": "Collaborative team software", + "homepage": "https://www.figma.com/", + "url": "https://desktop.figma.com/mac-arm/Figma-124.3.2.zip", + "url_specs": {}, + "version": "124.3.2", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "65fa321f505faf7eb55cb639c5104a502e65cd015437c02551d3c492a62a444e", + "artifacts": [ + { + "app": [ + "Figma.app" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Support/Figma", + "~/Library/Application Support/figma-desktop", + "~/Library/Caches/com.figma.agent", + "~/Library/Caches/com.figma.Desktop", + "~/Library/Preferences/com.figma.Desktop.plist", + "~/Library/Saved Application State/com.figma.Desktop.savedState" + ] + } + ] + } + ], + "caveats": null, + "depends_on": {}, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/f/figma.rb", + "ruby_source_checksum": { + "sha256": "ee6620d8218afa5f7a5ba44f4a2a73232a90d2cf6b7d1be7f2dbed4afbc7571e" + }, + "variations": { + "sequoia": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "sonoma": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "ventura": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "monterey": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "big_sur": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "catalina": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "mojave": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "high_sierra": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "sierra": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + }, + "el_capitan": { + "url": "https://desktop.figma.com/mac/Figma-124.3.2.zip", + "sha256": "a847964fe508bcf9b193fc00eaafb54d2d21f0f2bcd047418e046b7ec3d5ce5f" + } + }, + "analytics": { + "install": { + "30d": { + "figma": 2271 + }, + "90d": { + "figma": 7022 + }, + "365d": { + "figma": 27805 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/firefox.json b/server/mdm/maintainedapps/testdata/firefox.json new file mode 100644 index 000000000000..ed766c177114 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/firefox.json @@ -0,0 +1,169 @@ +{ + "token": "firefox", + "full_token": "firefox", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Mozilla Firefox" + ], + "desc": "Web browser", + "homepage": "https://www.mozilla.org/firefox/", + "url": "https://download-installer.cdn.mozilla.net/pub/firefox/releases/130.0/mac/en-US/Firefox%20130.0.dmg", + "url_specs": { + "verified": "download-installer.cdn.mozilla.net/pub/firefox/releases/" + }, + "version": "130.0", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "c89ee9abcf7a3554959a7d2db0a5a748be3ae2c30d7c170b879de10e46127602", + "artifacts": [ + { + "preflight": null + }, + { + "uninstall": [ + { + "quit": "org.mozilla.firefox" + } + ] + }, + { + "app": [ + "Firefox.app" + ] + }, + { + "binary": [ + "$HOMEBREW_PREFIX/Caskroom/firefox/130.0/firefox.wrapper.sh", + { + "target": "firefox" + } + ] + }, + { + "zap": [ + { + "trash": [ + "/Library/Logs/DiagnosticReports/firefox_*", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/org.mozilla.firefox.sfl*", + "~/Library/Application Support/CrashReporter/firefox_*", + "~/Library/Application Support/Firefox", + "~/Library/Caches/Firefox", + "~/Library/Caches/Mozilla/updates/Applications/Firefox", + "~/Library/Caches/org.mozilla.crashreporter", + "~/Library/Caches/org.mozilla.firefox", + "~/Library/Preferences/org.mozilla.crashreporter.plist", + "~/Library/Preferences/org.mozilla.firefox.plist", + "~/Library/Saved Application State/org.mozilla.firefox.savedState", + "~/Library/WebKit/org.mozilla.firefox" + ], + "rmdir": [ + "~/Library/Application Support/Mozilla", + "~/Library/Caches/Mozilla", + "~/Library/Caches/Mozilla/updates", + "~/Library/Caches/Mozilla/updates/Applications" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": { + "cask": [ + "firefox@beta", + "firefox@cn", + "firefox@esr" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [ + "af", + "ar", + "be", + "bg", + "bn", + "ca", + "cs", + "de", + "en-CA", + "en-GB", + "en", + "eo", + "es-AR", + "es-CL", + "es-ES", + "fa", + "ff", + "fi", + "fr", + "gl", + "gn", + "gu", + "he", + "hi", + "in", + "it", + "ja", + "ka", + "ko", + "mr", + "my", + "ne", + "nl", + "pa-IN", + "pl", + "pt-BR", + "pt", + "ru", + "si", + "sq", + "sr", + "sv", + "ta", + "te", + "th", + "tl", + "tr", + "uk", + "ur", + "zh-TW", + "zh" + ], + "ruby_source_path": "Casks/f/firefox.rb", + "ruby_source_checksum": { + "sha256": "d50e081cb3abda7d7eecf60728b37a4d8e8f616473bd0b32d280f1327f23ac5e" + }, + "variations": {}, + "analytics": { + "install": { + "30d": { + "firefox": 14543 + }, + "90d": { + "firefox": 39158 + }, + "365d": { + "firefox": 148931 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/google-chrome.json b/server/mdm/maintainedapps/testdata/google-chrome.json new file mode 100644 index 000000000000..aaae6a12910b --- /dev/null +++ b/server/mdm/maintainedapps/testdata/google-chrome.json @@ -0,0 +1,105 @@ +{ + "token": "google-chrome", + "full_token": "google-chrome", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Google Chrome" + ], + "desc": "Web browser", + "homepage": "https://www.google.com/chrome/", + "url": "https://dl.google.com/chrome/mac/universal/stable/GGRO/googlechrome.dmg", + "url_specs": {}, + "version": "128.0.6613.120", + "installed": null, + "installed_time": null, + "bundle_version": "6613.120", + "bundle_short_version": "128.0.6613.120", + "outdated": false, + "sha256": "no_check", + "artifacts": [ + { + "app": [ + "Google Chrome.app" + ] + }, + { + "zap": [ + { + "launchctl": [ + "com.google.keystone.agent", + "com.google.keystone.daemon" + ], + "trash": [ + "/Library/Caches/com.google.SoftwareUpdate.*", + "/Library/Google/Google Chrome Brand.plist", + "/Library/Google/GoogleSoftwareUpdate", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.google.chrome.app.*.sfl*", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.google.chrome.sfl*", + "~/Library/Application Support/Google/Chrome", + "~/Library/Caches/com.google.Chrome", + "~/Library/Caches/com.google.Chrome.helper.*", + "~/Library/Caches/com.google.Keystone", + "~/Library/Caches/com.google.Keystone.Agent", + "~/Library/Caches/com.google.SoftwareUpdate", + "~/Library/Caches/Google/Chrome", + "~/Library/Google/Google Chrome Brand.plist", + "~/Library/Google/GoogleSoftwareUpdate", + "~/Library/LaunchAgents/com.google.keystone.agent.plist", + "~/Library/LaunchAgents/com.google.keystone.xpcservice.plist", + "~/Library/Logs/GoogleSoftwareUpdateAgent.log", + "~/Library/Preferences/com.google.Chrome.plist", + "~/Library/Preferences/com.google.Keystone.Agent.plist", + "~/Library/Saved Application State/com.google.Chrome.app.*.savedState", + "~/Library/Saved Application State/com.google.Chrome.savedState", + "~/Library/WebKit/com.google.Chrome" + ], + "rmdir": [ + "/Library/Google", + "~/Library/Application Support/Google", + "~/Library/Caches/Google", + "~/Library/Google" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/g/google-chrome.rb", + "ruby_source_checksum": { + "sha256": "b31aabe1674fdecda8d5178de43a5188cd1a58c24e844260ea1dccfa6f293340" + }, + "variations": {}, + "analytics": { + "install": { + "30d": { + "google-chrome": 19149 + }, + "90d": { + "google-chrome": 54038 + }, + "365d": { + "google-chrome": 216929 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/microsoft-edge.json b/server/mdm/maintainedapps/testdata/microsoft-edge.json new file mode 100644 index 000000000000..e7b1827cc59f --- /dev/null +++ b/server/mdm/maintainedapps/testdata/microsoft-edge.json @@ -0,0 +1,154 @@ +{ + "token": "microsoft-edge", + "full_token": "microsoft-edge", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Microsoft Edge" + ], + "desc": "Web browser", + "homepage": "https://www.microsoft.com/en-us/edge?form=", + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/be6d4c8f-ec75-405e-a5f7-fec66b2898a2/MicrosoftEdge-128.0.2739.67.pkg", + "url_specs": {}, + "version": "128.0.2739.67,be6d4c8f-ec75-405e-a5f7-fec66b2898a2", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "cb4ddcbe57be83d1ec82d4ac76062a49bcd92e5bb27e04e8ff01dbda9045f449", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.microsoft.EdgeUpdater.update-internal.109.0.1518.89.system", + "com.microsoft.EdgeUpdater.update.system", + "com.microsoft.EdgeUpdater.wake.system" + ], + "pkgutil": "com.microsoft.edgemac" + } + ] + }, + { + "pkg": [ + "MicrosoftEdge-128.0.2739.67.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.package.Microsoft_AutoUpdate.app", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "delete": "/Library/Application Support/Microsoft/EdgeUpdater", + "trash": [ + "~/Library/Application Scripts/com.microsoft.edgemac.wdgExtension", + "~/Library/Application Support/Microsoft Edge", + "~/Library/Application Support/Microsoft/EdgeUpdater", + "~/Library/Caches/com.microsoft.edgemac", + "~/Library/Caches/com.microsoft.EdgeUpdater", + "~/Library/Caches/Microsoft Edge", + "~/Library/Containers/com.microsoft.edgemac.wdgExtension", + "~/Library/HTTPStorages/com.microsoft.edge*", + "~/Library/LaunchAgents/com.microsoft.EdgeUpdater.*.plist", + "~/Library/Microsoft/EdgeUpdater", + "~/Library/Preferences/com.microsoft.edgemac.plist", + "~/Library/Saved Application State/com.microsoft.edgemac.*", + "~/Library/WebKit/com.microsoft.edgemac" + ], + "rmdir": "/Library/Application Support/Microsoft" + } + ] + } + ], + "caveats": null, + "depends_on": {}, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/m/microsoft-edge.rb", + "ruby_source_checksum": { + "sha256": "71d9afd8b4f0ef22a30f7b987fd94daed8fbe3fcd0c0fb9b55c1738c554cb887" + }, + "variations": { + "sequoia": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "sonoma": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "ventura": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "monterey": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "big_sur": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "catalina": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "mojave": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "high_sierra": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "sierra": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + }, + "el_capitan": { + "url": "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/3d8bc4f8-f1af-448e-b039-10a86db63085/MicrosoftEdge-128.0.2739.67.pkg", + "version": "128.0.2739.67,3d8bc4f8-f1af-448e-b039-10a86db63085", + "sha256": "4d79cc82038de72dd9efab38e69ceb6ed0f1fd90551f0d4764a593a428dfbfb1" + } + }, + "analytics": { + "install": { + "30d": { + "microsoft-edge": 3588 + }, + "90d": { + "microsoft-edge": 10949 + }, + "365d": { + "microsoft-edge": 51951 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/microsoft-excel.json b/server/mdm/maintainedapps/testdata/microsoft-excel.json new file mode 100644 index 000000000000..d62356f284a8 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/microsoft-excel.json @@ -0,0 +1,441 @@ +{ + "token": "microsoft-excel", + "full_token": "microsoft-excel", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Microsoft Excel" + ], + "desc": "Spreadsheet software", + "homepage": "https://www.microsoft.com/en-US/microsoft-365/excel", + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.88.24081116_Installer.pkg", + "url_specs": {}, + "version": "16.88.24081116", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "2af9d2d80d46942aa634223f54608ee75f26b973d89afbe79de2a56e6dcbc3b4", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.88.24081116_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "cask": [ + "microsoft-auto-update" + ] + }, + "conflicts_with": { + "cask": [ + "microsoft-office", + "microsoft-office-businesspro" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/m/microsoft-excel.rb", + "ruby_source_checksum": { + "sha256": "ba9a8018661312bf6e7f2bab84b37ccd4ab2e7f25185d626602b058498a13d0a" + }, + "variations": { + "big_sur": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.77.23091703_Installer.pkg", + "version": "16.77.23091703", + "sha256": "582fca32104e828e01c0928e674122f2d8044d84fd2dc1d7964e0a807e2f4695", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.77.23091703_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ] + }, + "arm64_big_sur": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.77.23091703_Installer.pkg", + "version": "16.77.23091703", + "sha256": "582fca32104e828e01c0928e674122f2d8044d84fd2dc1d7964e0a807e2f4695", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.77.23091703_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ] + }, + "catalina": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.66.22101101_Installer.pkg", + "version": "16.66.22101101", + "sha256": "94148628c6f143f07555b3d2a70cea61cef817d963539d281b092834496f8f16", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.66.22101101_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ] + }, + "mojave": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.54.21101001_Installer.pkg", + "version": "16.54.21101001", + "sha256": "e09fe9f49a36b37af3745673a385be4de9ae8ec774965fd1753f8479a775fc54", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.54.21101001_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ] + }, + "high_sierra": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.43.20110804_Installer.pkg", + "version": "16.43.20110804", + "sha256": "2711a1b8864f7474458086b4b0a56673fee0097d2049f276788c50e004c47d72", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.43.20110804_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ] + }, + "sierra": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.30.19101301_Installer.pkg", + "version": "16.30.19101301", + "sha256": "9886b661067f4a99de544d140980fb0f8ef2f4871baa519024781fb814a02fe5", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.30.19101301_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ] + }, + "el_capitan": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Excel_16.16.20101200_Installer.pkg", + "version": "16.16.20101200", + "sha256": "bdd23b696d54e5ffeb40f30a9bd7f968d2936380ab78a6eaf29d05f5fc8eb78e", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Excel.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Excel_16.16.20101200_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Excel", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.excel.sfl*", + "~/Library/Caches/com.microsoft.Excel", + "~/Library/Containers/com.microsoft.Excel", + "~/Library/Preferences/com.microsoft.Excel.plist", + "~/Library/Saved Application State/com.microsoft.Excel.savedState", + "~/Library/Webkit/com.microsoft.Excel" + ] + } + ] + } + ] + } + }, + "analytics": { + "install": { + "30d": { + "microsoft-excel": 873 + }, + "90d": { + "microsoft-excel": 2501 + }, + "365d": { + "microsoft-excel": 10581 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/microsoft-teams.json b/server/mdm/maintainedapps/testdata/microsoft-teams.json new file mode 100644 index 000000000000..07af90bdc742 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/microsoft-teams.json @@ -0,0 +1,132 @@ +{ + "token": "microsoft-teams", + "full_token": "microsoft-teams", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Microsoft Teams" + ], + "desc": "Meet, chat, call, and collaborate in just one place", + "homepage": "https://www.microsoft.com/en/microsoft-teams/group-chat-software/", + "url": "https://statics.teams.cdn.office.net/production-osx/24215.1002.3039.5089/MicrosoftTeams.pkg", + "url_specs": { + "verified": "statics.teams.cdn.office.net/production-osx/" + }, + "version": "24215.1002.3039.5089", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "df7ca5415b8ab0acd9f1002d9f04e0dab5782fa4cf1768331e22d14665a2b148", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.teams.TeamsUpdaterDaemon", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.MSTeamsAudioDevice", + "com.microsoft.package.Microsoft_AutoUpdate.app", + "com.microsoft.teams2" + ], + "delete": [ + "/Applications/Microsoft Teams.app", + "/Library/Application Support/Microsoft/TeamsUpdaterDaemon", + "/Library/Logs/Microsoft/MSTeams", + "/Library/Logs/Microsoft/Teams", + "/Library/Preferences/com.microsoft.teams.plist" + ] + } + ] + }, + { + "pkg": [ + "MicrosoftTeams.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.teams2", + "~/Library/Application Scripts/com.microsoft.teams2.launcher", + "~/Library/Application Scripts/com.microsoft.teams2.notificationcenter", + "~/Library/Application Support/com.microsoft.teams", + "~/Library/Application Support/Microsoft/Teams", + "~/Library/Application Support/Teams", + "~/Library/Caches/com.microsoft.teams", + "~/Library/Containers/com.microsoft.teams2", + "~/Library/Containers/com.microsoft.teams2.launcher", + "~/Library/Containers/com.microsoft.teams2.notificationcenter", + "~/Library/Cookies/com.microsoft.teams.binarycookies", + "~/Library/Group Containers/*.com.microsoft.teams", + "~/Library/HTTPStorages/com.microsoft.teams", + "~/Library/HTTPStorages/com.microsoft.teams.binarycookies", + "~/Library/Logs/Microsoft Teams Helper (Renderer)", + "~/Library/Logs/Microsoft Teams", + "~/Library/Preferences/com.microsoft.teams.plist", + "~/Library/Saved Application State/com.microsoft.teams.savedState", + "~/Library/Saved Application State/com.microsoft.teams2.savedState", + "~/Library/WebKit/com.microsoft.teams" + ], + "rmdir": "~/Library/Application Support/Microsoft" + } + ] + } + ], + "caveats": null, + "depends_on": { + "cask": [ + "microsoft-auto-update" + ], + "macos": { + ">=": [ + "11" + ] + } + }, + "conflicts_with": { + "cask": [ + "microsoft-office-businesspro" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/m/microsoft-teams.rb", + "ruby_source_checksum": { + "sha256": "6deae2be2e0862656eaedff01b767ebc8cb787dc2800ec38209255b2f7580e9a" + }, + "variations": {}, + "analytics": { + "install": { + "30d": { + "microsoft-teams": 3791 + }, + "90d": { + "microsoft-teams": 12487 + }, + "365d": { + "microsoft-teams": 53526 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/microsoft-word.json b/server/mdm/maintainedapps/testdata/microsoft-word.json new file mode 100644 index 000000000000..9b639ed38a73 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/microsoft-word.json @@ -0,0 +1,433 @@ +{ + "token": "microsoft-word", + "full_token": "microsoft-word", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Microsoft Word" + ], + "desc": "Word processor", + "homepage": "https://www.microsoft.com/en-US/microsoft-365/word", + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.88.24081116_Installer.pkg", + "url_specs": {}, + "version": "16.88.24081116", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "c6ff9937d3a872e87fbd9f83c838baadafbe32025a32a01f87e438a21258031d", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.88.24081116_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "cask": [ + "microsoft-auto-update" + ] + }, + "conflicts_with": { + "cask": [ + "microsoft-office", + "microsoft-office-businesspro" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/m/microsoft-word.rb", + "ruby_source_checksum": { + "sha256": "c1485bc53b17944212ed65da58450fe2d4512cbf524425e251a88900417ea752" + }, + "variations": { + "big_sur": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.77.23091703_Installer.pkg", + "version": "16.77.23091703", + "sha256": "10c8db978206275a557faf3650763a656b1f7170c9b2a65fa6fdce220bd23066", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.77.23091703_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ] + }, + "arm64_big_sur": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.77.23091703_Installer.pkg", + "version": "16.77.23091703", + "sha256": "10c8db978206275a557faf3650763a656b1f7170c9b2a65fa6fdce220bd23066", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.77.23091703_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ] + }, + "catalina": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.66.22101101_Installer.pkg", + "version": "16.66.22101101", + "sha256": "5a6a75d9a5b46cceeff5a1b7925c0eab6e4976cba529149b7b291a0355e7a7c9", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.66.22101101_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ] + }, + "mojave": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.54.21101001_Installer.pkg", + "version": "16.54.21101001", + "sha256": "7f3ed397b517aac3637d8b8f8b4233f9e7132941f0657eaca8ec423ac068616e", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.54.21101001_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ] + }, + "high_sierra": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.43.20110804_Installer.pkg", + "version": "16.43.20110804", + "sha256": "3d957d534fb2142f6e95a688552890a31f0d942796f0128ca837a3e98405d413", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.43.20110804_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ] + }, + "sierra": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.30.19101301_Installer.pkg", + "version": "16.30.19101301", + "sha256": "6abd7939b0d935023ebb8fabeb206c4cbbe8eb8f9a3ff7d318448d2ba5f332e4", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.30.19101301_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ] + }, + "el_capitan": { + "url": "https://officecdnmac.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Word_16.16.20101200_Installer.pkg", + "version": "16.16.20101200", + "sha256": "0c61b7db7a6a13653270795c085a909aa54668e8de2f2ca749257ce6aa5957d1", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.office.licensingV2.helper", + "quit": "com.microsoft.autoupdate2", + "pkgutil": [ + "com.microsoft.package.Microsoft_Word.app", + "com.microsoft.pkg.licensing" + ] + } + ] + }, + { + "pkg": [ + "Microsoft_Word_16.16.20101200_Installer.pkg", + { + "choices": [ + { + "choiceIdentifier": "com.microsoft.autoupdate", + "choiceAttribute": "selected", + "attributeSetting": 0 + } + ] + } + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.microsoft.Word", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.word.sfl*", + "~/Library/Application Support/CrashReporter/Microsoft Word_*.plist", + "~/Library/Containers/com.microsoft.Word", + "~/Library/Preferences/com.microsoft.Word.plist", + "~/Library/Saved Application State/com.microsoft.Word.savedState" + ] + } + ] + } + ] + } + }, + "analytics": { + "install": { + "30d": { + "microsoft-word": 793 + }, + "90d": { + "microsoft-word": 2262 + }, + "365d": { + "microsoft-word": 10083 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/notion.json b/server/mdm/maintainedapps/testdata/notion.json new file mode 100644 index 000000000000..3dcb88dff861 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/notion.json @@ -0,0 +1,109 @@ +{ + "token": "notion", + "full_token": "notion", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Notion" + ], + "desc": "App to write, plan, collaborate, and get organised", + "homepage": "https://www.notion.so/", + "url": "https://desktop-release.notion-static.com/Notion-3.14.0-arm64.dmg", + "url_specs": { + "verified": "desktop-release.notion-static.com/" + }, + "version": "3.14.0", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "281b681315f22fdb7919dabb7da40bec606cf0553e8d3dc3b95b1e280e22c048", + "artifacts": [ + { + "app": [ + "Notion.app" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Support/Caches/notion-updater", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/notion.id.sfl*", + "~/Library/Application Support/Notion", + "~/Library/Caches/notion.id*", + "~/Library/Logs/Notion", + "~/Library/Preferences/ByHost/notion.id.*", + "~/Library/Preferences/notion.id.*", + "~/Library/Saved Application State/notion.id.savedState", + "~/Library/WebKit/notion.id" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/n/notion.rb", + "ruby_source_checksum": { + "sha256": "d3819cf16d3d149e8c5da4d324ce3a61ba11cd5f31034c11f568fa9ec3b48bc1" + }, + "variations": { + "sequoia": { + "url": "https://desktop-release.notion-static.com/Notion-3.14.0.dmg", + "sha256": "5d7b762f522754b74c78bd0f0ebf292e6750224ee7bc4a3837156bdb5722ab11" + }, + "sonoma": { + "url": "https://desktop-release.notion-static.com/Notion-3.14.0.dmg", + "sha256": "5d7b762f522754b74c78bd0f0ebf292e6750224ee7bc4a3837156bdb5722ab11" + }, + "ventura": { + "url": "https://desktop-release.notion-static.com/Notion-3.14.0.dmg", + "sha256": "5d7b762f522754b74c78bd0f0ebf292e6750224ee7bc4a3837156bdb5722ab11" + }, + "monterey": { + "url": "https://desktop-release.notion-static.com/Notion-3.14.0.dmg", + "sha256": "5d7b762f522754b74c78bd0f0ebf292e6750224ee7bc4a3837156bdb5722ab11" + }, + "big_sur": { + "url": "https://desktop-release.notion-static.com/Notion-3.14.0.dmg", + "sha256": "5d7b762f522754b74c78bd0f0ebf292e6750224ee7bc4a3837156bdb5722ab11" + }, + "catalina": { + "url": "https://desktop-release.notion-static.com/Notion-3.14.0.dmg", + "sha256": "5d7b762f522754b74c78bd0f0ebf292e6750224ee7bc4a3837156bdb5722ab11" + } + }, + "analytics": { + "install": { + "30d": { + "notion": 4752 + }, + "90d": { + "notion": 13516 + }, + "365d": { + "notion": 52768 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/slack.json b/server/mdm/maintainedapps/testdata/slack.json new file mode 100644 index 000000000000..eaca79517a9c --- /dev/null +++ b/server/mdm/maintainedapps/testdata/slack.json @@ -0,0 +1,126 @@ +{ + "token": "slack", + "full_token": "slack", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Slack" + ], + "desc": "Team communication and collaboration software", + "homepage": "https://slack.com/", + "url": "https://downloads.slack-edge.com/desktop-releases/mac/arm64/4.40.126/Slack-4.40.126-macOS.dmg", + "url_specs": { + "verified": "downloads.slack-edge.com/" + }, + "version": "4.40.126", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "87dcde01a382e7d4a23f72f0fdd64315b52390dd2d5800df2a645d4316b3bc52", + "artifacts": [ + { + "uninstall": [ + { + "quit": "com.tinyspeck.slackmacgap" + } + ] + }, + { + "app": [ + "Slack.app" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/com.tinyspeck.slackmacgap", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.tinyspeck.slackmacgap.sfl*", + "~/Library/Application Support/Slack", + "~/Library/Caches/com.tinyspeck.slackmacgap*", + "~/Library/Containers/com.tinyspeck.slackmacgap*", + "~/Library/Cookies/com.tinyspeck.slackmacgap.binarycookies", + "~/Library/Group Containers/*.com.tinyspeck.slackmacgap", + "~/Library/Group Containers/*.slack", + "~/Library/HTTPStorages/com.tinyspeck.slackmacgap*", + "~/Library/Logs/Slack", + "~/Library/Preferences/ByHost/com.tinyspeck.slackmacgap.ShipIt.*.plist", + "~/Library/Preferences/com.tinyspeck.slackmacgap*", + "~/Library/Saved Application State/com.tinyspeck.slackmacgap.savedState", + "~/Library/WebKit/com.tinyspeck.slackmacgap" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": { + "cask": [ + "slack@beta" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/s/slack.rb", + "ruby_source_checksum": { + "sha256": "55b1b37ace62e6297b1861e2ab2b21b834c35112d8d422ccf0b9634843a9aa8d" + }, + "variations": { + "sequoia": { + "url": "https://downloads.slack-edge.com/desktop-releases/mac/x64/4.40.126/Slack-4.40.126-macOS.dmg", + "sha256": "f4246f416b84ce8a4a9abbfba6975f0fbdb90880c217544836b53c3fff5900ae" + }, + "sonoma": { + "url": "https://downloads.slack-edge.com/desktop-releases/mac/x64/4.40.126/Slack-4.40.126-macOS.dmg", + "sha256": "f4246f416b84ce8a4a9abbfba6975f0fbdb90880c217544836b53c3fff5900ae" + }, + "ventura": { + "url": "https://downloads.slack-edge.com/desktop-releases/mac/x64/4.40.126/Slack-4.40.126-macOS.dmg", + "sha256": "f4246f416b84ce8a4a9abbfba6975f0fbdb90880c217544836b53c3fff5900ae" + }, + "monterey": { + "url": "https://downloads.slack-edge.com/desktop-releases/mac/x64/4.40.126/Slack-4.40.126-macOS.dmg", + "sha256": "f4246f416b84ce8a4a9abbfba6975f0fbdb90880c217544836b53c3fff5900ae" + }, + "big_sur": { + "url": "https://downloads.slack-edge.com/desktop-releases/mac/x64/4.40.126/Slack-4.40.126-macOS.dmg", + "sha256": "f4246f416b84ce8a4a9abbfba6975f0fbdb90880c217544836b53c3fff5900ae" + }, + "catalina": { + "url": "https://downloads.slack-edge.com/releases/macos/4.33.90/prod/x64/Slack-4.33.90-macOS.dmg", + "version": "4.33.90", + "sha256": "7e0ba8a18a9cf95090ad80f58437d647eee5d1842ac4f15ea053c16c1629edde" + } + }, + "analytics": { + "install": { + "30d": { + "slack": 6334 + }, + "90d": { + "slack": 18458 + }, + "365d": { + "slack": 78914 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/teamviewer.json b/server/mdm/maintainedapps/testdata/teamviewer.json new file mode 100644 index 000000000000..a8e6a12dc99d --- /dev/null +++ b/server/mdm/maintainedapps/testdata/teamviewer.json @@ -0,0 +1,201 @@ +{ + "token": "teamviewer", + "full_token": "teamviewer", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "TeamViewer" + ], + "desc": "Remote access and connectivity software focused on security", + "homepage": "https://www.teamviewer.com/", + "url": "https://dl.teamviewer.com/download/version_15x/update/15.57.5/TeamViewer.pkg", + "url_specs": {}, + "version": "15.57.5", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "5f53e81921bf7b15e8605ad3cfa39c4769303bbb06d57dc50a683be0d5889e1f", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.teamviewer.desktop", + "com.teamviewer.Helper", + "com.teamviewer.service", + "com.teamviewer.teamviewer", + "com.teamviewer.teamviewer_desktop", + "com.teamviewer.teamviewer_service", + "com.teamviewer.UninstallerHelper", + "com.teamviewer.UninstallerWatcher" + ], + "quit": [ + "com.teamviewer.TeamViewer", + "com.teamviewer.TeamViewerUninstaller" + ], + "pkgutil": [ + "com.teamviewer.AuthorizationPlugin", + "com.teamviewer.remoteaudiodriver", + "com.teamviewer.teamviewer.*", + "TeamViewerUninstaller" + ], + "delete": [ + "/Applications/TeamViewer.app", + "/Library/Preferences/com.teamviewer*" + ] + } + ] + }, + { + "pkg": [ + "TeamViewer.pkg" + ] + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Support/TeamViewer", + "~/Library/Caches/com.teamviewer.TeamViewer", + "~/Library/Caches/TeamViewer", + "~/Library/Cookies/com.teamviewer.TeamViewer.binarycookies", + "~/Library/Logs/TeamViewer", + "~/Library/Preferences/com.teamviewer*", + "~/Library/Saved Application State/com.teamviewer.TeamViewer.savedState" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.11" + ] + } + }, + "conflicts_with": { + "cask": [ + "teamviewer-host" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/t/teamviewer.rb", + "ruby_source_checksum": { + "sha256": "86b4666b24b1645a599ce70f9a6841a4ec81ea5792655b08d362f9f474beebc8" + }, + "variations": { + "catalina": { + "url": "https://dl.teamviewer.com/download/version_15x/update/15.42.4/TeamViewer.pkg", + "version": "15.42.4", + "sha256": "3357bc366cd0295dd100b790d6af6216d349d34451ea18ba08692a51eadd6cf7", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": [ + "com.teamviewer.desktop", + "com.teamviewer.Helper", + "com.teamviewer.service", + "com.teamviewer.teamviewer", + "com.teamviewer.teamviewer_desktop", + "com.teamviewer.teamviewer_service", + "com.teamviewer.UninstallerHelper", + "com.teamviewer.UninstallerWatcher" + ], + "quit": [ + "com.teamviewer.TeamViewer", + "com.teamviewer.TeamViewerUninstaller" + ], + "pkgutil": [ + "com.teamviewer.AuthorizationPlugin", + "com.teamviewer.remoteaudiodriver", + "com.teamviewer.teamviewer.*", + "TeamViewerUninstaller" + ], + "delete": [ + "/Applications/TeamViewer.app", + "/Library/Preferences/com.teamviewer*" + ] + } + ] + }, + { + "installer": [ + { + "manual": "TeamViewer.pkg" + } + ] + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Support/TeamViewer", + "~/Library/Caches/com.teamviewer.TeamViewer", + "~/Library/Caches/TeamViewer", + "~/Library/Cookies/com.teamviewer.TeamViewer.binarycookies", + "~/Library/Logs/TeamViewer", + "~/Library/Preferences/com.teamviewer*", + "~/Library/Saved Application State/com.teamviewer.TeamViewer.savedState" + ] + } + ] + } + ], + "caveats": "WARNING: teamviewer has a bug in Catalina where it doesn't deal well with being uninstalled by other utilities.\nThe recommended way to remove it is by running their uninstaller under:\n\n Preferences → Advanced\n" + }, + "mojave": { + "url": "https://dl.teamviewer.com/download/version_15x/update/15.42.4/TeamViewer.pkg", + "version": "15.42.4", + "sha256": "3357bc366cd0295dd100b790d6af6216d349d34451ea18ba08692a51eadd6cf7" + }, + "high_sierra": { + "url": "https://dl.teamviewer.com/download/version_15x/update/15.2.2756/TeamViewer.pkg", + "version": "15.2.2756", + "sha256": "fe7daf80f9aee056f97d11183941470fa1c5823101a0951990340b6264a2651a" + }, + "sierra": { + "url": "https://dl.teamviewer.com/download/version_15x/update/15.2.2756/TeamViewer.pkg", + "version": "15.2.2756", + "sha256": "fe7daf80f9aee056f97d11183941470fa1c5823101a0951990340b6264a2651a" + }, + "el_capitan": { + "url": "https://dl.teamviewer.com/download/version_15x/update/15.2.2756/TeamViewer.pkg", + "version": "15.2.2756", + "sha256": "fe7daf80f9aee056f97d11183941470fa1c5823101a0951990340b6264a2651a" + } + }, + "analytics": { + "install": { + "30d": { + "teamviewer": 1271 + }, + "90d": { + "teamviewer": 3644 + }, + "365d": { + "teamviewer": 18205 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/visual-studio-code.json b/server/mdm/maintainedapps/testdata/visual-studio-code.json new file mode 100644 index 000000000000..398e6abb04d3 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/visual-studio-code.json @@ -0,0 +1,122 @@ +{ + "token": "visual-studio-code", + "full_token": "visual-studio-code", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Microsoft Visual Studio Code", + "VS Code" + ], + "desc": "Open-source code editor", + "homepage": "https://code.visualstudio.com/", + "url": "https://update.code.visualstudio.com/1.93.0/darwin-arm64/stable", + "url_specs": {}, + "version": "1.93.0", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "79a69b0e02f8dc79106276600b437ff3f831925d1f4d6665cf972ef45dc158f6", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "com.microsoft.VSCode.ShipIt", + "quit": "com.microsoft.VSCode" + } + ] + }, + { + "app": [ + "Visual Studio Code.app" + ] + }, + { + "binary": [ + "$APPDIR/Visual Studio Code.app/Contents/Resources/app/bin/code" + ] + }, + { + "zap": [ + { + "trash": [ + "~/.vscode", + "~/Library/Application Support/Code", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.microsoft.vscode.sfl*", + "~/Library/Caches/com.microsoft.VSCode", + "~/Library/Caches/com.microsoft.VSCode.ShipIt", + "~/Library/HTTPStorages/com.microsoft.VSCode", + "~/Library/Preferences/ByHost/com.microsoft.VSCode.ShipIt.*.plist", + "~/Library/Preferences/com.microsoft.VSCode.helper.plist", + "~/Library/Preferences/com.microsoft.VSCode.plist", + "~/Library/Saved Application State/com.microsoft.VSCode.savedState" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "10.15" + ] + } + }, + "conflicts_with": null, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/v/visual-studio-code.rb", + "ruby_source_checksum": { + "sha256": "fead740931be479fa70f4e3a8f707d096891a6c9c3c4bd1a2213b10b6fb7d684" + }, + "variations": { + "sequoia": { + "url": "https://update.code.visualstudio.com/1.93.0/darwin/stable", + "sha256": "321f2a51afe42498cd141124dda8f43be2d46821e035b0286a3d0605a519bea3" + }, + "sonoma": { + "url": "https://update.code.visualstudio.com/1.93.0/darwin/stable", + "sha256": "321f2a51afe42498cd141124dda8f43be2d46821e035b0286a3d0605a519bea3" + }, + "ventura": { + "url": "https://update.code.visualstudio.com/1.93.0/darwin/stable", + "sha256": "321f2a51afe42498cd141124dda8f43be2d46821e035b0286a3d0605a519bea3" + }, + "monterey": { + "url": "https://update.code.visualstudio.com/1.93.0/darwin/stable", + "sha256": "321f2a51afe42498cd141124dda8f43be2d46821e035b0286a3d0605a519bea3" + }, + "big_sur": { + "url": "https://update.code.visualstudio.com/1.93.0/darwin/stable", + "sha256": "321f2a51afe42498cd141124dda8f43be2d46821e035b0286a3d0605a519bea3" + }, + "catalina": { + "url": "https://update.code.visualstudio.com/1.93.0/darwin/stable", + "sha256": "321f2a51afe42498cd141124dda8f43be2d46821e035b0286a3d0605a519bea3" + } + }, + "analytics": { + "install": { + "30d": { + "visual-studio-code": 26798 + }, + "90d": { + "visual-studio-code": 79608 + }, + "365d": { + "visual-studio-code": 321611 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/whatsapp.json b/server/mdm/maintainedapps/testdata/whatsapp.json new file mode 100644 index 000000000000..97cbecbb810a --- /dev/null +++ b/server/mdm/maintainedapps/testdata/whatsapp.json @@ -0,0 +1,84 @@ +{ + "token": "whatsapp", + "full_token": "whatsapp", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "WhatsApp" + ], + "desc": "Native desktop client for WhatsApp", + "homepage": "https://www.whatsapp.com/", + "url": "https://web.whatsapp.com/desktop/mac_native/release/?version=2.24.16.80&extension=zip&configuration=Release&branch=relbranch", + "url_specs": {}, + "version": "2.24.16.80", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "33026f9cc9b1c63010df546c1ac5ff3b49ff6e742a57807a817264db82487ce9", + "artifacts": [ + { + "app": [ + "WhatsApp.app" + ] + }, + { + "zap": [ + { + "trash": [ + "~/Library/Application Scripts/net.whatsapp.WhatsApp*", + "~/Library/Caches/net.whatsapp.WhatsApp", + "~/Library/Containers/net.whatsapp.WhatsApp*", + "~/Library/Group Containers/group.com.facebook.family", + "~/Library/Group Containers/group.net.whatsapp*", + "~/Library/Saved Application State/net.whatsapp.WhatsApp.savedState" + ] + } + ] + } + ], + "caveats": null, + "depends_on": { + "macos": { + ">=": [ + "11" + ] + } + }, + "conflicts_with": { + "cask": [ + "whatsapp@beta", + "whatsapp@legacy" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/w/whatsapp.rb", + "ruby_source_checksum": { + "sha256": "05889e4ba8c0e0fe97e653d1e4122385a6f67a2ce2ec6a1f7b19c702142c617f" + }, + "variations": {}, + "analytics": { + "install": { + "30d": { + "whatsapp": 3652 + }, + "90d": { + "whatsapp": 13126 + }, + "365d": { + "whatsapp": 47436 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testdata/zoom.json b/server/mdm/maintainedapps/testdata/zoom.json new file mode 100644 index 000000000000..40e4640a7500 --- /dev/null +++ b/server/mdm/maintainedapps/testdata/zoom.json @@ -0,0 +1,161 @@ +{ + "token": "zoom", + "full_token": "zoom", + "old_tokens": [], + "tap": "homebrew/cask", + "name": [ + "Zoom" + ], + "desc": "Video communication and virtual meeting platform", + "homepage": "https://www.zoom.us/", + "url": "https://cdn.zoom.us/prod/6.1.11.39163/arm64/zoomusInstallerFull.pkg", + "url_specs": {}, + "version": "6.1.11.39163", + "installed": null, + "installed_time": null, + "bundle_version": null, + "bundle_short_version": null, + "outdated": false, + "sha256": "c567828838583df4c026db571b96c2c212eef9b98795c145fecdfe10009ea61e", + "artifacts": [ + { + "uninstall": [ + { + "launchctl": "us.zoom.ZoomDaemon", + "signal": [ + "KILL", + "us.zoom.xos" + ], + "pkgutil": "us.zoom.pkg.videomeeting", + "delete": [ + "/Applications/zoom.us.app", + "/Library/Internet Plug-Ins/ZoomUsPlugIn.plugin", + "/Library/Logs/DiagnosticReports/zoom.us*", + "/Library/PrivilegedHelperTools/us.zoom.ZoomDaemon" + ] + } + ] + }, + { + "pkg": [ + "zoomusInstallerFull.pkg" + ] + }, + { + "postflight": null + }, + { + "zap": [ + { + "trash": [ + "~/.zoomus", + "~/Desktop/Zoom", + "~/Documents/Zoom", + "~/Library/Application Scripts/*.ZoomClient3rd", + "~/Library/Application Support/CloudDocs/session/containers/iCloud.us.zoom.videomeetings", + "~/Library/Application Support/CloudDocs/session/containers/iCloud.us.zoom.videomeetings.plist", + "~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/us.zoom*.sfl*", + "~/Library/Application Support/CrashReporter/zoom.us*", + "~/Library/Application Support/zoom.us", + "~/Library/Caches/us.zoom.xos", + "~/Library/Cookies/us.zoom.xos.binarycookies", + "~/Library/Group Containers/*.ZoomClient3rd", + "~/Library/HTTPStorages/us.zoom.xos", + "~/Library/HTTPStorages/us.zoom.xos.binarycookies", + "~/Library/Internet Plug-Ins/ZoomUsPlugIn.plugin", + "~/Library/Logs/zoom.us", + "~/Library/Logs/zoominstall.log", + "~/Library/Logs/ZoomPhone", + "~/Library/Preferences/us.zoom.airhost.plist", + "~/Library/Preferences/us.zoom.caphost.plist", + "~/Library/Preferences/us.zoom.Transcode.plist", + "~/Library/Preferences/us.zoom.xos.Hotkey.plist", + "~/Library/Preferences/us.zoom.xos.plist", + "~/Library/Preferences/us.zoom.ZoomAutoUpdater.plist", + "~/Library/Preferences/us.zoom.ZoomClips.plist", + "~/Library/Preferences/ZoomChat.plist", + "~/Library/Saved Application State/us.zoom.xos.savedState", + "~/Library/WebKit/us.zoom.xos" + ] + } + ] + } + ], + "caveats": null, + "depends_on": {}, + "conflicts_with": { + "cask": [ + "zoom-for-it-admins" + ] + }, + "container": null, + "auto_updates": true, + "deprecated": false, + "deprecation_date": null, + "deprecation_reason": null, + "disabled": false, + "disable_date": null, + "disable_reason": null, + "tap_git_head": "5e76d542a4e6e78701fdfae86e263074eab2a3e7", + "languages": [], + "ruby_source_path": "Casks/z/zoom.rb", + "ruby_source_checksum": { + "sha256": "7a76c4fbb2eaf6f2ef87a5756a5b7147cdfd4cee1f8cef275e007e924003fbda" + }, + "variations": { + "sequoia": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "sonoma": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "ventura": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "monterey": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "big_sur": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "catalina": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "mojave": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "high_sierra": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "sierra": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + }, + "el_capitan": { + "url": "https://cdn.zoom.us/prod/6.1.11.39163/zoomusInstallerFull.pkg", + "sha256": "001f905f1eabdeb6b299553bac427d74ee02a8923db67445de5eb5bee1a7aa92" + } + }, + "analytics": { + "install": { + "30d": { + "zoom": 5878 + }, + "90d": { + "zoom": 17578 + }, + "365d": { + "zoom": 75807 + } + } + }, + "generated_date": "2024-09-09" +} diff --git a/server/mdm/maintainedapps/testing_utils.go b/server/mdm/maintainedapps/testing_utils.go new file mode 100644 index 000000000000..9c08af04b1a7 --- /dev/null +++ b/server/mdm/maintainedapps/testing_utils.go @@ -0,0 +1,74 @@ +package maintainedapps + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "os" + "path" + "path/filepath" + "runtime" + "testing" + + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/go-kit/log" + "github.com/stretchr/testify/require" +) + +// IngestMaintainedApps ingests the maintained apps from the testdata +// directory, to fill the library of maintained apps with valid data for tests. +// It returns the expected results of the ingestion as a slice of +// fleet.MaintainedApps with only a few fields filled - the result of +// unmarshaling the testdata/expected_apps.json file. +func IngestMaintainedApps(t *testing.T, ds fleet.Datastore) []*fleet.MaintainedApp { + _, filename, _, _ := runtime.Caller(0) + base := filepath.Dir(filename) + testdataDir := filepath.Join(base, "testdata") + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token := path.Base(r.URL.Path) + b, err := os.ReadFile(filepath.Join(testdataDir, token)) + if err != nil { + if os.IsNotExist(err) { + w.WriteHeader(http.StatusNotFound) + return + } + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(err.Error())) + return + } + _, _ = w.Write(b) + })) + defer srv.Close() + + // not using t.Setenv because we want the env var to be unset on return of + // this call + os.Setenv("FLEET_DEV_BREW_API_URL", srv.URL) + defer os.Unsetenv("FLEET_DEV_BREW_API_URL") + + err := Refresh(context.Background(), ds, log.NewNopLogger()) + require.NoError(t, err) + + var expected []*fleet.MaintainedApp + b, err := os.ReadFile(filepath.Join(testdataDir, "expected_apps.json")) + require.NoError(t, err) + err = json.Unmarshal(b, &expected) + require.NoError(t, err) + return expected +} + +// ExpectedAppTokens returns the list of app tokens (unique identifier) that are +// expected to be in the maintained apps library after ingestion. The tokens are +// taken from the apps.json list. +func ExpectedAppTokens(t *testing.T) []string { + var apps []maintainedApp + err := json.Unmarshal(appsJSON, &apps) + require.NoError(t, err) + + tokens := make([]string, len(apps)) + for i, app := range apps { + tokens[i] = app.Identifier + } + return tokens +} diff --git a/server/mock/datastore_mock.go b/server/mock/datastore_mock.go index 99d55d12158c..15e03deecf45 100644 --- a/server/mock/datastore_mock.go +++ b/server/mock/datastore_mock.go @@ -1068,6 +1068,8 @@ type GetPastActivityDataForVPPAppInstallFunc func(ctx context.Context, commandRe type GetVPPTokenByLocationFunc func(ctx context.Context, loc string) (*fleet.VPPTokenDB, error) +type UpsertMaintainedAppFunc func(ctx context.Context, app *fleet.MaintainedApp) error + type DataStore struct { HealthCheckFunc HealthCheckFunc HealthCheckFuncInvoked bool @@ -2641,6 +2643,9 @@ type DataStore struct { GetVPPTokenByLocationFunc GetVPPTokenByLocationFunc GetVPPTokenByLocationFuncInvoked bool + UpsertMaintainedAppFunc UpsertMaintainedAppFunc + UpsertMaintainedAppFuncInvoked bool + mu sync.Mutex } @@ -6311,3 +6316,10 @@ func (s *DataStore) GetVPPTokenByLocation(ctx context.Context, loc string) (*fle s.mu.Unlock() return s.GetVPPTokenByLocationFunc(ctx, loc) } + +func (s *DataStore) UpsertMaintainedApp(ctx context.Context, app *fleet.MaintainedApp) error { + s.mu.Lock() + s.UpsertMaintainedAppFuncInvoked = true + s.mu.Unlock() + return s.UpsertMaintainedAppFunc(ctx, app) +}