fleet/server/mdm/maintainedapps/sync.go

172 lines
5.1 KiB
Go
Raw Normal View History

package maintained_apps
import (
"context"
_ "embed"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
ma "github.com/fleetdm/fleet/v4/ee/maintained-apps"
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
Only allow FLEET_DEV_* env vars when `--dev` is passed, allow overriding configs one at a time in dev (#38652) Resolves #38484. This includes a CI job change to make sure we don't introduce any more env vars that don't get proxied (and thus turned off outside `--dev`). # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [x] Added/updated automated tests Manual QA touched hot paths, but did _not_ manually test every FLEET_DEV_* environment variable change. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Centralized dev-mode environment management for consistent FLEET_DEV_* handling and test-friendly overrides. * Dev-mode allows targeted overrides for certain dev-only configuration when running with --dev. * **Chores** * Migrated environment access to the centralized dev-mode helper across the codebase. * Added CI checks to enforce proper usage of FLEET_DEV_* variables. * **Documentation** * Added guidance on dev-mode environment variable rules and overrides. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Victor Lyuboslavsky <2685025+getvictor@users.noreply.github.com>
2026-01-27 20:32:56 +00:00
"github.com/fleetdm/fleet/v4/server/dev_mode"
"github.com/fleetdm/fleet/v4/server/fleet"
kitlog "github.com/go-kit/log"
)
type appListing struct {
Name string `json:"name"`
Slug string `json:"slug"`
Platform string `json:"platform"`
UniqueIdentifier string `json:"unique_identifier"`
}
type AppsList struct {
Version uint `json:"version"`
Apps []appListing `json:"apps"`
}
const fmaOutputsBase = "https://raw.githubusercontent.com/fleetdm/fleet/refs/heads/main/ee/maintained-apps/outputs"
// Refresh fetches the latest information about maintained apps from FMA's
// apps list on GitHub and updates the Fleet database with the new information.
func Refresh(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger) error {
appsList, err := FetchAppsList(ctx)
if err != nil {
return err
}
return upsertMaintainedApps(ctx, appsList, ds)
}
func FetchAppsList(ctx context.Context) (*AppsList, error) {
httpClient := fleethttp.NewClient(fleethttp.WithTimeout(10 * time.Second))
baseURL := fmaOutputsBase
Only allow FLEET_DEV_* env vars when `--dev` is passed, allow overriding configs one at a time in dev (#38652) Resolves #38484. This includes a CI job change to make sure we don't introduce any more env vars that don't get proxied (and thus turned off outside `--dev`). # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [x] Added/updated automated tests Manual QA touched hot paths, but did _not_ manually test every FLEET_DEV_* environment variable change. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Centralized dev-mode environment management for consistent FLEET_DEV_* handling and test-friendly overrides. * Dev-mode allows targeted overrides for certain dev-only configuration when running with --dev. * **Chores** * Migrated environment access to the centralized dev-mode helper across the codebase. * Added CI checks to enforce proper usage of FLEET_DEV_* variables. * **Documentation** * Added guidance on dev-mode environment variable rules and overrides. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Victor Lyuboslavsky <2685025+getvictor@users.noreply.github.com>
2026-01-27 20:32:56 +00:00
if baseFromEnvVar := dev_mode.Env("FLEET_DEV_MAINTAINED_APPS_BASE_URL"); baseFromEnvVar != "" {
baseURL = baseFromEnvVar
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/apps.json", baseURL), nil)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "create http request")
}
res, err := httpClient.Do(req)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "execute http request")
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "read http response body")
}
switch res.StatusCode {
case http.StatusOK:
// success, go on
case http.StatusNotFound:
return nil, ctxerr.New(ctx, "maintained apps list not found")
default:
if len(body) > 512 {
body = body[:512]
}
return nil, ctxerr.Errorf(ctx, "apps list returned HTTP status %d: %s", res.StatusCode, string(body))
}
var appsList AppsList
if err := json.Unmarshal(body, &appsList); err != nil {
return nil, ctxerr.Wrap(ctx, err, "unmarshal apps list")
}
if appsList.Version != 2 {
return nil, ctxerr.New(ctx, "apps list is an incompatible version")
}
return &appsList, nil
}
func upsertMaintainedApps(ctx context.Context, appsList *AppsList, ds fleet.Datastore) error {
var gotApps []string
for _, app := range appsList.Apps {
gotApps = append(gotApps, app.Slug)
if app.UniqueIdentifier == "" {
app.UniqueIdentifier = app.Name
}
if _, err := ds.UpsertMaintainedApp(ctx, &fleet.MaintainedApp{
Name: app.Name,
Slug: app.Slug,
Platform: app.Platform,
UniqueIdentifier: app.UniqueIdentifier,
}); err != nil {
return ctxerr.Wrap(ctx, err, "upsert maintained app")
}
}
// remove apps that were removed upstream
if err := ds.ClearRemovedFleetMaintainedApps(ctx, gotApps); err != nil {
return ctxerr.Wrap(ctx, err, "clear removed maintained apps during refresh")
}
return nil
}
// Hydrate pulls information from app-level FMA manifests info an FMA skeleton pulled from the database
func Hydrate(ctx context.Context, app *fleet.MaintainedApp) (*fleet.MaintainedApp, error) {
httpClient := fleethttp.NewClient(fleethttp.WithTimeout(10 * time.Second))
baseURL := fmaOutputsBase
Only allow FLEET_DEV_* env vars when `--dev` is passed, allow overriding configs one at a time in dev (#38652) Resolves #38484. This includes a CI job change to make sure we don't introduce any more env vars that don't get proxied (and thus turned off outside `--dev`). # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [x] Added/updated automated tests Manual QA touched hot paths, but did _not_ manually test every FLEET_DEV_* environment variable change. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Centralized dev-mode environment management for consistent FLEET_DEV_* handling and test-friendly overrides. * Dev-mode allows targeted overrides for certain dev-only configuration when running with --dev. * **Chores** * Migrated environment access to the centralized dev-mode helper across the codebase. * Added CI checks to enforce proper usage of FLEET_DEV_* variables. * **Documentation** * Added guidance on dev-mode environment variable rules and overrides. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Victor Lyuboslavsky <2685025+getvictor@users.noreply.github.com>
2026-01-27 20:32:56 +00:00
if baseFromEnvVar := dev_mode.Env("FLEET_DEV_MAINTAINED_APPS_BASE_URL"); baseFromEnvVar != "" {
baseURL = baseFromEnvVar
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/%s.json", baseURL, app.Slug), nil)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "create http request")
}
res, err := httpClient.Do(req)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "execute http request")
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "read http response body")
}
switch res.StatusCode {
case http.StatusOK:
// success, go on
case http.StatusNotFound:
return nil, ctxerr.New(ctx, "app not found in Fleet manifests")
default:
if len(body) > 512 {
body = body[:512]
}
return nil, ctxerr.Errorf(ctx, "manifest retrieval returned HTTP status %d: %s", res.StatusCode, string(body))
}
var manifest ma.FMAManifestFile
if err := json.Unmarshal(body, &manifest); err != nil {
return nil, ctxerr.Wrapf(ctx, err, "unmarshal FMA manifest for %s", app.Slug)
}
manifest.Versions[0].Slug = app.Slug
app.Version = manifest.Versions[0].Version
app.Platform = manifest.Versions[0].Platform()
app.InstallerURL = manifest.Versions[0].InstallerURL
app.SHA256 = manifest.Versions[0].SHA256
app.InstallScript = manifest.Refs[manifest.Versions[0].InstallScriptRef]
app.UninstallScript = manifest.Refs[manifest.Versions[0].UninstallScriptRef]
app.AutomaticInstallQuery = manifest.Versions[0].Queries.Exists
app.Categories = manifest.Versions[0].DefaultCategories
app.UpgradeCode = manifest.Versions[0].UpgradeCode
return app, nil
}