diff --git a/.github/workflows/build-binaries.yaml b/.github/workflows/build-binaries.yaml index 278f958b2842..8499171c1583 100644 --- a/.github/workflows/build-binaries.yaml +++ b/.github/workflows/build-binaries.yaml @@ -37,11 +37,10 @@ jobs: with: go-version-file: 'go.mod' - # Set the Node.js version - - name: Set up Node.js ${{ vars.NODE_VERSION }} + - name: Set up Node.js uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: - node-version: ${{ vars.NODE_VERSION }} + node-version-file: package.json - name: JS Dependency Cache id: js-cache @@ -51,7 +50,7 @@ jobs: **/node_modules # Use a separate cache for this from other JS jobs since we run the # webpack steps and will have more to cache. - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}-node_version-${{ vars.NODE_VERSION }} + key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-node_modules- diff --git a/.github/workflows/fleet-and-orbit.yml b/.github/workflows/fleet-and-orbit.yml index f4dfb2780eb7..22be676c7868 100644 --- a/.github/workflows/fleet-and-orbit.yml +++ b/.github/workflows/fleet-and-orbit.yml @@ -79,11 +79,10 @@ jobs: with: go-version-file: 'go.mod' - # Set the Node.js version - - name: Set up Node.js ${{ vars.NODE_VERSION }} + - name: Set up Node.js uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: - node-version: ${{ vars.NODE_VERSION }} + node-version-file: package.json - name: Start tunnel env: diff --git a/.github/workflows/goreleaser-fleet.yaml b/.github/workflows/goreleaser-fleet.yaml index 6ba9aff8f08f..7a23296ef2fe 100644 --- a/.github/workflows/goreleaser-fleet.yaml +++ b/.github/workflows/goreleaser-fleet.yaml @@ -46,11 +46,10 @@ jobs: with: go-version-file: 'go.mod' - # Set the Node.js version - - name: Set up Node.js ${{ vars.NODE_VERSION }} + - name: Set up Node.js uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: - node-version: ${{ vars.NODE_VERSION }} + node-version-file: package.json - name: Install JS Dependencies run: make deps-js diff --git a/.github/workflows/goreleaser-snapshot-fleet.yaml b/.github/workflows/goreleaser-snapshot-fleet.yaml index 927cf31be1da..f3c6a9340c96 100644 --- a/.github/workflows/goreleaser-snapshot-fleet.yaml +++ b/.github/workflows/goreleaser-snapshot-fleet.yaml @@ -60,10 +60,10 @@ jobs: go-version-file: 'go.mod' # Set the Node.js version - - name: Set up Node.js ${{ vars.NODE_VERSION }} + - name: Set up Node.js uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: - node-version: ${{ vars.NODE_VERSION }} + node-version-file: package.json - name: Install Dependencies run: make deps diff --git a/.github/workflows/test-db-changes.yml b/.github/workflows/test-db-changes.yml index 2bd89ab82b1e..10d1ec4ddea2 100644 --- a/.github/workflows/test-db-changes.yml +++ b/.github/workflows/test-db-changes.yml @@ -40,33 +40,6 @@ jobs: with: fetch-depth: 0 - - name: Install Go - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 - with: - go-version-file: 'go.mod' - - - name: Start Infra Dependencies - # Use & to background this - run: docker compose up -d mysql_test & - - - name: Wait for mysql - run: | - echo "waiting for mysql..." - until docker compose exec -T mysql_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do - echo "." - sleep 1 - done - echo "mysql is ready" - - - name: Verify test schema changes - run: | - make dump-test-schema - if [[ $(git diff server/datastore/mysql/schema.sql) ]]; then - echo "❌ fail: uncommited changes in schema.sql" - echo "please run `make dump-test-schema` and commit the changes" - exit 1 - fi - # TODO: This doesn't cover all scenarios since other PRs might # be merged into `main` after this check has passed. # @@ -84,8 +57,8 @@ jobs: base_ref=$(git tag --list "fleet-v*" --sort=-creatordate | head -n 1) fi - all_migrations=($(ls server/datastore/mysql/migrations/tables/20*_*.go | sort -r)) - new_migrations=($(git diff --find-renames --name-only --diff-filter=A $base_ref -- server/datastore/mysql/migrations/tables/20\*_\*.go | sort -r)) + all_migrations=($(ls server/datastore/mysql/migrations/tables/20*_*.go | sort -r | grep -v '_test.go')) + new_migrations=($(git diff --find-renames --name-only --diff-filter=A $base_ref -- server/datastore/mysql/migrations/tables/20\*_\*.go ':(exclude,glob)server/datastore/mysql/migrations/tables/20*_*_test.go' | sort -r)) index=0 for migration in "${new_migrations[@]}"; do @@ -110,3 +83,31 @@ jobs: echo "Ref: https://github.com/fleetdm/fleet/blob/main/handbook/engineering/scaling-fleet.md#foreign-keys-and-locking" exit 1 fi + + + - name: Install Go + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + with: + go-version-file: 'go.mod' + + - name: Start Infra Dependencies + # Use & to background this + run: docker compose up -d mysql_test & + + - name: Wait for mysql + run: | + echo "waiting for mysql..." + until docker compose exec -T mysql_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do + echo "." + sleep 1 + done + echo "mysql is ready" + + - name: Verify test schema changes + run: | + make dump-test-schema + if [[ $(git diff server/datastore/mysql/schema.sql) ]]; then + echo "❌ fail: uncommited changes in schema.sql" + echo "please run `make dump-test-schema` and commit the changes" + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml index 15b4fd05cee5..ab60d81939a2 100644 --- a/.github/workflows/test-js.yml +++ b/.github/workflows/test-js.yml @@ -42,14 +42,14 @@ jobs: with: egress-policy: audit - - name: Set up Node.js ${{ vars.NODE_VERSION }} - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 - with: - node-version: ${{ vars.NODE_VERSION }} - - name: Checkout Code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Set up Node.js + uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + with: + node-version-file: package.json + - name: JS Dependency Cache id: js-cache uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v2 @@ -87,14 +87,14 @@ jobs: with: egress-policy: audit - - name: Set up Node.js ${{ vars.NODE_VERSION }} - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 - with: - node-version: ${{ vars.NODE_VERSION }} - - name: Checkout Code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Set up Node.js + uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + with: + node-version-file: package.json + - name: JS Dependency Cache id: js-cache uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index f1f4dd2cee3e..056966f521be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## Fleet 4.57.1 (Oct 01, 2024) + +### Bug fixes + +* Improved performance of SQL queries used to determine MDM profile status for Apple hosts. +* Ensured request timeouts for software installer edits were just as high as for initial software installer uploads. +* Fixed an issue with the migration that added support for multiple VPP tokens, which would happen if a token was removed prior to upgrading Fleet. +* Fixed a "no rows" error when adding a software installer that matched an existing title's name and source but not its bundle ID. + ## Fleet 4.57.0 (Sep 23, 2024) **Endpoint Operations** diff --git a/articles/config-less-fleetd-agent-deployment.md b/articles/config-less-fleetd-agent-deployment.md index eb37159fdcf5..2ca3b5cd7c93 100644 --- a/articles/config-less-fleetd-agent-deployment.md +++ b/articles/config-less-fleetd-agent-deployment.md @@ -4,7 +4,7 @@ Deploying Fleet's agent across a diverse range of devices often involves the crucial step of enrolling each device. Traditionally, this involves [packaging](https://fleetdm.com/docs/using-fleet/fleetd#packaging) `fleetd` with configuration including the enroll secret and server URL. While effective, an alternative offers more flexibility in your deployment process. This guide introduces a different approach for deploying Fleet's agent without embedding configuration settings directly into `fleetd`. Ideal for IT administrators who prefer to generate a single package and maintain greater control over the distribution of enrollment secrets and server URLs, this method simplifies the enrollment process across macOS and Windows hosts. -Emphasizing adaptability and convenience, this approach allows for a more efficient way to manage device enrollments. Let’s dive into how to deploy Fleet's agent using this alternative method, ensuring a more open and flexible deployment process. +This approach emphasizes adaptability and convenience and allows for a more efficient way to manage device enrollments. Let’s explore how to deploy Fleet's agent using this alternative method, ensuring a more open and flexible deployment process. ## For macOS: @@ -44,6 +44,18 @@ fleetctl package --type=pkg --use-system-configuration --fleet-desktop PayloadVersion 1 + + EndUserEmail + END_USER_EMAIL_HERE + PayloadIdentifier + com.fleetdm.fleet.mdm.apple.mdm + PayloadType + com.apple.mdm + PayloadUUID + 29713130-1602-4D27-90C9-B822A295E44E + PayloadVersion + 1 + PayloadDisplayName Fleetd configuration @@ -56,11 +68,38 @@ fleetctl package --type=pkg --use-system-configuration --fleet-desktop PayloadVersion 1 PayloadDescription - Default configuration for the fleetd agent. + Configuration for the fleetd agent. ``` +You can optionally specify the `END_USER_EMAIL` that will be added to the host's [human-device mapping](https://fleetdm.com/docs/rest-api/rest-api#get-human-device-mapping): + +```xml + + + + + PayloadContent + + ... + + EndUserEmail + END_USER_EMAIL + PayloadIdentifier + com.fleetdm.fleet.mdm.apple.mdm + PayloadType + com.apple.mdm + PayloadUUID + 29713130-1602-4D27-90C9-B822A295E44E + PayloadVersion + 1 + + + ... + + +``` ## For Windows: diff --git a/articles/enroll-hosts.md b/articles/enroll-hosts.md index 0635855596ab..f15f44236b29 100644 --- a/articles/enroll-hosts.md +++ b/articles/enroll-hosts.md @@ -320,7 +320,7 @@ Fleetd will send stdout/stderr logs to the following directories: - macOS: `/private/var/log/orbit/orbit.std{out|err}.log`. - Windows: `C:\Windows\system32\config\systemprofile\AppData\Local\FleetDM\Orbit\Logs\orbit-osquery.log` (the log file is rotated). - - Linux: Orbit and osqueryd stdout/stderr output is sent to syslog (`/var/log/syslog` on Debian systems and `/var/log/messages` on CentOS). + - Linux: Orbit and osqueryd stdout/stderr output is sent to syslog (`/var/log/syslog` on Debian systems, `/var/log/messages` on CentOS, and `journalctl -u orbit` on Fedora). If the `logger_path` agent configuration is set to `filesystem`, fleetd will send osquery's "result" and "status" logs to the following directories: - Windows: C:\Program Files\Orbit\osquery_log diff --git a/articles/macos-mdm-setup.md b/articles/macos-mdm-setup.md index 209deead8b00..0f32ccb09033 100644 --- a/articles/macos-mdm-setup.md +++ b/articles/macos-mdm-setup.md @@ -58,17 +58,17 @@ If no default team is set for a host platform (macOS, iOS, or iPadOS), then newl To connect Fleet to Apple's VPP, head to the guide [here](https://fleetdm.com/guides/install-vpp-apps-on-macos-using-fleet). -### Best practice +## Best practice -Most organizations need only one ABM token and one VPP token to manage their macOS, iOS, and iPadOS hosts. +Most organizations only need one ABM token and one VPP token to manage their macOS, iOS, and iPadOS hosts. -Some organizations need multiple ABM and VPP tokens: +These organizations may need multiple ABM and VPP tokens: - Managed Service Providers (MSPs) - Enterprises that acquire new businesses and as a result inherit new hosts - Umbrella organizations that preside over entities with separated purchasing authority (i.e. a hospital or university) -For MSPs, the best practice is to have one ABM and VPP connection per client. +For **MSPs**, the best practice is to have one ABM and VPP connection per client. The default teams in Fleet for each client's ABM token in Fleet will look like this: - macOS: 💻 Client A - Workstations @@ -77,7 +77,7 @@ The default teams in Fleet for each client's ABM token in Fleet will look like t Client A's VPP token will be assigned to the above teams. -For enterprises that acquire, the best practice is to add a new ABM and VPP connection for each acquisition. +For **enterprises that acquire**, the best practice is to add a new ABM and VPP connection for each acquisition. These will default teams in Fleet: diff --git a/changes/19619-win-battery b/changes/19619-win-battery new file mode 100644 index 000000000000..124e58114048 --- /dev/null +++ b/changes/19619-win-battery @@ -0,0 +1 @@ +- Windows host details now include battery status \ No newline at end of file diff --git a/changes/20537-add-rpm-support b/changes/20537-add-rpm-support new file mode 100644 index 000000000000..2238298b2413 --- /dev/null +++ b/changes/20537-add-rpm-support @@ -0,0 +1 @@ +* Added support for uploading RPM packages. diff --git a/changes/21409-fedora-label b/changes/21409-fedora-label new file mode 100644 index 000000000000..2f0ca7cfd61e --- /dev/null +++ b/changes/21409-fedora-label @@ -0,0 +1 @@ +- added builtin label for Fedora Linux. Warning: migrations will fail if a pre-existing 'Fedora Linux' label exists. To resolve, delete the existing 'Fedora Linux' label. \ No newline at end of file diff --git a/changes/21923-switch-exact-search-focus-bug b/changes/21923-switch-exact-search-focus-bug new file mode 100644 index 000000000000..0ae8b45da921 --- /dev/null +++ b/changes/21923-switch-exact-search-focus-bug @@ -0,0 +1 @@ +- UI fix: Switching vulnerability search types does not cause page re-render diff --git a/changes/22094-cleanup-queries b/changes/22094-cleanup-queries new file mode 100644 index 000000000000..af8e9ab77da8 --- /dev/null +++ b/changes/22094-cleanup-queries @@ -0,0 +1 @@ +- updated activity cleanup job to remove all expired live queries to improve API performance in environment using large volumes of live queries. To note, the cleanup cron may take longer on the first run after upgrade. \ No newline at end of file diff --git a/changes/22094-query-optimization b/changes/22094-query-optimization new file mode 100644 index 000000000000..bd779b451346 --- /dev/null +++ b/changes/22094-query-optimization @@ -0,0 +1 @@ +- Increased performance for Host details and Fleet Desktop, particularly in environments using high volumes of live queries \ No newline at end of file diff --git a/changes/22198-defaults b/changes/22198-defaults new file mode 100644 index 000000000000..ec243e9a48e4 --- /dev/null +++ b/changes/22198-defaults @@ -0,0 +1,2 @@ +- Fixes a bug where removing a VPP or ABM token from a GitOps YAML file would leave the team + assignments unchanged. \ No newline at end of file diff --git a/charts/fleet/Chart.yaml b/charts/fleet/Chart.yaml index c23438bf22aa..f9abb8e29901 100644 --- a/charts/fleet/Chart.yaml +++ b/charts/fleet/Chart.yaml @@ -8,7 +8,7 @@ version: v6.2.0 home: https://github.com/fleetdm/fleet sources: - https://github.com/fleetdm/fleet.git -appVersion: v4.57.0 +appVersion: v4.57.1 dependencies: - name: mysql condition: mysql.enabled diff --git a/charts/fleet/values.yaml b/charts/fleet/values.yaml index 03539df9da98..15eda9b9e8ce 100644 --- a/charts/fleet/values.yaml +++ b/charts/fleet/values.yaml @@ -3,7 +3,7 @@ hostName: fleet.localhost replicas: 3 # The number of Fleet instances to deploy imageRepository: fleetdm/fleet -imageTag: v4.57.0 # Version of Fleet to deploy +imageTag: v4.57.1 # Version of Fleet to deploy podAnnotations: {} # Additional annotations to add to the Fleet pod serviceAccountAnnotations: {} # Additional annotations to add to the Fleet service account resources: diff --git a/cmd/fleetctl/apply_test.go b/cmd/fleetctl/apply_test.go index f35b39dc84f1..bd80bb84347c 100644 --- a/cmd/fleetctl/apply_test.go +++ b/cmd/fleetctl/apply_test.go @@ -657,6 +657,18 @@ func TestApplyAppConfig(t *testing.T) { return []*fleet.TeamSummary{{Name: "team1", ID: 1}}, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{{OrganizationName: t.Name()}}, nil + } + name := writeTmpYml(t, `--- apiVersion: v1 kind: config @@ -782,6 +794,18 @@ func TestApplyAppConfigDryRunIssue(t *testing.T) { return nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + // first, set the default app config's agent options as set after fleetctl setup name := writeTmpYml(t, `--- apiVersion: v1 @@ -914,6 +938,18 @@ func TestApplyAppConfigDeprecatedFields(t *testing.T) { return nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + name := writeTmpYml(t, `--- apiVersion: v1 kind: config @@ -1316,6 +1352,14 @@ func TestApplyAsGitOps(t *testing.T) { return []*fleet.ABMToken{{ID: 1}}, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + // Apply global config. name := writeTmpYml(t, `--- apiVersion: v1 @@ -1873,6 +1917,18 @@ func TestCanApplyIntervalsInNanoseconds(t *testing.T) { return nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + name := writeTmpYml(t, `--- apiVersion: v1 kind: config @@ -1908,6 +1964,18 @@ func TestCanApplyIntervalsUsingDurations(t *testing.T) { return nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + name := writeTmpYml(t, `--- apiVersion: v1 kind: config @@ -2091,6 +2159,18 @@ func TestApplyMacosSetup(t *testing.T) { return []*fleet.ABMToken{{ID: 1}}, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + return ds } @@ -2764,6 +2844,17 @@ func TestApplySpecs(t *testing.T) { ds.DeleteMDMWindowsConfigProfileByTeamAndNameFunc = func(ctx context.Context, teamID *uint, profileName string) error { return nil } + + // VPP/AMB + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } } cases := []struct { diff --git a/cmd/fleetctl/gitops_test.go b/cmd/fleetctl/gitops_test.go index 1a054482f618..295172612d74 100644 --- a/cmd/fleetctl/gitops_test.go +++ b/cmd/fleetctl/gitops_test.go @@ -83,6 +83,18 @@ func TestGitOpsBasicGlobalFree(t *testing.T) { return nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml") require.NoError(t, err) @@ -238,6 +250,18 @@ func TestGitOpsBasicGlobalPremium(t *testing.T) { return nil, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml") require.NoError(t, err) @@ -591,6 +615,17 @@ func TestGitOpsFullGlobal(t *testing.T) { return nil } + // Needed for checking tokens + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + const ( fleetServerURL = "https://fleet.example.com" orgName = "GitOps Test" @@ -1079,6 +1114,18 @@ func TestGitOpsBasicGlobalAndTeam(t *testing.T) { return nil, 0, nil, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + globalFile, err := os.CreateTemp(t.TempDir(), "*.yml") require.NoError(t, err) @@ -1345,6 +1392,18 @@ func TestGitOpsBasicGlobalAndNoTeam(t *testing.T) { return nil, 0, nil, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + globalFileBasic, err := os.CreateTemp(t.TempDir(), "*.yml") require.NoError(t, err) @@ -1604,6 +1663,18 @@ func TestGitOpsFullGlobalAndTeam(t *testing.T) { return team, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } + apnsCert, apnsKey, err := mysql.GenerateTestCertBytes() require.NoError(t, err) crt, key, err := apple_mdm.NewSCEPCACertKey() @@ -1656,7 +1727,7 @@ func TestGitOpsTeamSofwareInstallers(t *testing.T) { wantErr string }{ {"testdata/gitops/team_software_installer_not_found.yml", "Please make sure that URLs are reachable from your Fleet server."}, - {"testdata/gitops/team_software_installer_unsupported.yml", "The file should be .pkg, .msi, .exe or .deb."}, + {"testdata/gitops/team_software_installer_unsupported.yml", "The file should be .pkg, .msi, .exe, .deb or .rpm."}, {"testdata/gitops/team_software_installer_too_large.yml", "The maximum file size is 500 MiB"}, {"testdata/gitops/team_software_installer_valid.yml", ""}, {"testdata/gitops/team_software_installer_valid_apply.yml", ""}, @@ -1711,7 +1782,7 @@ func TestGitOpsNoTeamSoftwareInstallers(t *testing.T) { wantErr string }{ {"testdata/gitops/no_team_software_installer_not_found.yml", "Please make sure that URLs are reachable from your Fleet server."}, - {"testdata/gitops/no_team_software_installer_unsupported.yml", "The file should be .pkg, .msi, .exe or .deb."}, + {"testdata/gitops/no_team_software_installer_unsupported.yml", "The file should be .pkg, .msi, .exe, .deb or .rpm."}, {"testdata/gitops/no_team_software_installer_too_large.yml", "The maximum file size is 500 MiB"}, {"testdata/gitops/no_team_software_installer_valid.yml", ""}, {"testdata/gitops/no_team_software_installer_pre_condition_multiple_queries.yml", "should have only one query."}, @@ -2234,6 +2305,15 @@ func setupFullGitOpsPremiumServer(t *testing.T) (*mock.Store, **fleet.AppConfig, ds.ListSoftwareTitlesFunc = func(ctx context.Context, opt fleet.SoftwareTitleListOptions, tmFilter fleet.TeamFilter) ([]fleet.SoftwareTitleListResult, int, *fleet.PaginationMetadata, error) { return nil, 0, nil, nil } + ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error { + return nil + } + ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) { + return []*fleet.VPPTokenDB{}, nil + } + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{}, nil + } t.Setenv("FLEET_SERVER_URL", fleetServerURL) t.Setenv("ORG_NAME", orgName) diff --git a/docs/Configuration/yaml-files.md b/docs/Configuration/yaml-files.md index 7599fd259f9a..fae1c212c192 100644 --- a/docs/Configuration/yaml-files.md +++ b/docs/Configuration/yaml-files.md @@ -354,7 +354,9 @@ software: - `app_store_id` is the ID of the Apple App Store app. You can find this at the end of the app's App Store URL. For example, "Bear - Markdown Notes" URL is "https://apps.apple.com/us/app/bear-markdown-notes/id1016366447" and the `app_store_id` is `1016366447`. -> Make sure to include only the ID itself, and not the `id` prefix shown in the URL. The ID must be wrapped in quotes as shown in the example so that it is processed as a string. +> Make sure to include only the ID itself, and not the `id` prefix shown in the URL. The ID must be wrapped in quotes as shown in the example so that it is processed as a string. + +`self_service` only applies to macOS, and is ignored for other platforms. For example, if the app is supported on macOS, iOS, and iPadOS, and `self_service` is set to `true`, it will be self-service on macOS workstations but not iPhones or iPads. ##### Separate file diff --git a/docs/Contributing/API-for-contributors.md b/docs/Contributing/API-for-contributors.md index 074c3338b4c2..27f819f72467 100644 --- a/docs/Contributing/API-for-contributors.md +++ b/docs/Contributing/API-for-contributors.md @@ -541,6 +541,10 @@ The MDM endpoints exist to support the related command-line interface sub-comman - [Renew VPP token](#renew-vpp-token) - [Delete VPP token](#delete-vpp-token) - [Batch-apply MDM custom settings](#batch-apply-mdm-custom-settings) +- [Batch-apply packages](#batch-apply-packages) +- [Batch-apply App Store apps](#batch-apply-app-store-apps) +- [Get token to download package](#get-token-to-download-package) +- [Download package using a token](#download-package-using-a-token) - [Initiate SSO during DEP enrollment](#initiate-sso-during-dep-enrollment) - [Complete SSO during DEP enrollment](#complete-sso-during-dep-enrollment) - [Over the air enrollment](#over-the-air-enrollment) @@ -549,7 +553,6 @@ The MDM endpoints exist to support the related command-line interface sub-comman - [Get FileVault statistics](#get-filevault-statistics) - [Upload VPP content token](#upload-vpp-content-token) - [Disable VPP](#disable-vpp) -- [Get an over the air (OTA) enrollment profile](#get-an-over-the-air-ota-enrollment-profile) ### Generate Apple Business Manager public key (ADE) @@ -1744,7 +1747,7 @@ If the `name` is not already associated with an existing team, this API route cr | scripts | list | body | A list of script files to add to this team so they can be executed at a later time. | | software | object | body | The team's software that will be available for install. | | software.packages | list | body | An array of objects. Each object consists of:`url`- URL to the software package (PKG, MSI, EXE or DEB),`install_script` - command that Fleet runs to install software, `pre_install_query` - condition query that determines if the install will proceed, `post_install_script` - script that runs after software install, and `self_service` boolean. | -| software.app_store_apps | list | body | An array objects. Each object consists of `app_store_id` - ID of the App Store app formatted as a string (in quotes) rather than a number. | +| software.app_store_apps | list | body | An array of objects. Each object consists of `app_store_id` - ID of the App Store app and `self_service` boolean. | | mdm.macos_settings.enable_disk_encryption | bool | body | Whether disk encryption should be enabled for hosts that belong to this team. | | force | bool | query | Force apply the spec even if there are (ignorable) validation errors. Those are unknown keys and agent options-related validations. | | dry_run | bool | query | Validate the provided JSON for unknown keys and invalid value types and return any validation errors, but do not apply the changes. | @@ -1837,6 +1840,7 @@ If the `name` is not already associated with an existing team, this API route cr "app_store_apps": [ { "app_store_id": "12464567", + "self_service": true } ] } @@ -3377,3 +3381,187 @@ Run a live script and get results back (5 minute timeout). Live scripts only run "exit_code": 0 } ``` +## Software + +### Batch-apply software + +_Available in Fleet Premium._ + +`POST /api/v1/fleet/software/batch` + +This endpoint is asynchronous, meaning it will start a background process to download and apply the software and return a `request_uuid` in the JSON response that can be used to query the status of the batch-apply (using the `GET /api/v1/fleet/software/batch/:request_uuid` endpoint defined below). + +#### Parameters + +| Name | Type | In | Description | +| --------- | ------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| team_name | string | query | The name of the team to add the software package to. Ommitting these parameters will add software to 'No Team'. | +| dry_run | bool | query | If `true`, will validate the provided software packages and return any validation errors, but will not apply the changes. | +| software | object | body | The team's software that will be available for install. | +| software.packages | list | body | An array of objects. Each object consists of:`url`- URL to the software package (PKG, MSI, EXE or DEB),`install_script` - command that Fleet runs to install software, `pre_install_query` - condition query that determines if the install will proceed, `post_install_script` - script that runs after software install, and `uninstall_script` - command that Fleet runs to uninstall software. | + +#### Example + +`POST /api/v1/fleet/software/batch` + +##### Default response + +`Status: 200` +```json +{ + "request_uuid": "ec23c7b6-c336-4109-b89d-6afd859659b4", +} +``` + +### Get status of software batch-apply request + +_Available in Fleet Premium._ + +`GET /api/v1/fleet/software/batch/:request_uuid` + +This endpoint allows querying the status of a batch-apply software request (`POST /api/v1/fleet/software/batch`). +Returns `"status"` field that can be one of `"processing"`, `"complete"` or `"failed"`. +If `"status"` is `"completed"` then the `"packages"` field contains the applied packages. +If `"status"` is `"processing"` then the operation is ongoing and the request should be retried. +If `"status"` is `"failed"` then the `"message"` field contains the error message. + +#### Parameters + +| Name | Type | In | Description | +| ------------ | ------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| request_uuid | string | query | The request_uuid returned by the `POST /api/v1/fleet/software/batch` endpoint. | +| team_name | string | query | The name of the team to add the software package to. Ommitting these parameters will add software to 'No Team'. | +| dry_run | bool | query | If `true`, will validate the provided software packages and return any validation errors, but will not apply the changes. | + +##### Default responses + +`Status: 200` +```json +{ + "status": "processing", + "message": "", + "packages": null +} +``` + +`Status: 200` +```json +{ + "status": "completed", + "message": "", + "packages": [ + { + "team_id": 1, + "title_id": 2751, + "url": "https://ftp.mozilla.org/pub/firefox/releases/129.0.2/win64/en-US/Firefox%20Setup%20129.0.2.msi" + } + ] +} +``` + +`Status: 200` +```json +{ + "status": "failed", + "message": "validation failed: software.url Couldn't edit software. URL (\"https://foobar.does.not.exist.com\") returned \"Not Found\". Please make sure that URLs are reachable from your Fleet server.", + "packages": null +} +``` + +### Batch-apply App Store apps + +_Available in Fleet Premium._ + +`POST /api/latest/fleet/software/app_store_apps/batch` + +#### Parameters + +| Name | Type | In | Description | +| --------- | ------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| team_name | string | query | The name of the team to add the software package to. Ommitting this parameter will add software to "No team". | +| dry_run | bool | query | If `true`, will validate the provided VPP apps and return any validation errors, but will not apply the changes. | +| app_store_apps | list | body | An array of objects. Each object contains `app_store_id` and `self_service`. | +| app_store_apps.app_store_id | string | body | ID of the App Store app. | +| app_store_apps.self_service | boolean | body | Whether the VPP app is "Self-service" or not. | + +#### Example + +`POST /api/latest/fleet/software/app_store_apps/batch` +```json +{ + "team_name": "Foobar", + "app_store_apps": { + { + "app_store_id": "597799333", + "self_service": false, + }, + { + "app_store_id": "497799835", + "self_service": true, + } + } +} +``` + +##### Default response + +`Status: 204` + +### Get token to download package + +_Available in Fleet Premium._ + +`POST /api/v1/fleet/software/titles/:software_title_id/package/token?alt=media` + +The returned token is a one-time use token that expires after 10 minutes. + +#### Parameters + +| Name | Type | In | Description | +|-------------------|---------|-------|------------------------------------------------------------------| +| software_title_id | integer | path | **Required**. The ID of the software title for software package. | +| team_id | integer | query | **Required**. The team ID containing the software package. | +| alt | integer | query | **Required**. Must be specified and set to "media". | + +#### Example + +`POST /api/v1/fleet/software/titles/123/package/token?alt=media&team_id=2` + +##### Default response + +`Status: 200` + +```json +{ + "token": "e905e33e-07fe-4f82-889c-4848ed7eecb7" +} +``` + +### Download package using a token + +_Available in Fleet Premium._ + +`GET /api/v1/fleet/software/titles/:software_title_id/package/token/:token?alt=media` + +#### Parameters + +| Name | Type | In | Description | +|-------------------|---------|------|--------------------------------------------------------------------------| +| software_title_id | integer | path | **Required**. The ID of the software title to download software package. | +| token | string | path | **Required**. The token to download the software package. | + +#### Example + +`GET /api/v1/fleet/software/titles/123/package/token/e905e33e-07fe-4f82-889c-4848ed7eecb7` + +##### Default response + +`Status: 200` + +```http +Status: 200 +Content-Type: application/octet-stream +Content-Disposition: attachment +Content-Length: +Body: +``` diff --git a/docs/Contributing/Understanding-host-vitals.md b/docs/Contributing/Understanding-host-vitals.md index 3cdabf2fde06..3aa2078574f1 100644 --- a/docs/Contributing/Understanding-host-vitals.md +++ b/docs/Contributing/Understanding-host-vitals.md @@ -3,7 +3,7 @@ Following is a summary of the detail queries hardcoded in Fleet used to populate the device details: -## battery +## battery_macos - Platforms: darwin @@ -12,6 +12,20 @@ Following is a summary of the detail queries hardcoded in Fleet used to populate SELECT serial_number, cycle_count, health FROM battery; ``` +## battery_windows + +- Platforms: windows + +- Discovery query: +```sql +SELECT 1 FROM osquery_registry WHERE active = true AND registry = 'table' AND name = 'battery' +``` + +- Query: +```sql +SELECT serial_number, cycle_count, designed_capacity, max_capacity FROM battery +``` + ## chromeos_profile_user_info - Platforms: chrome diff --git a/docs/Get started/why-fleet.md b/docs/Get started/why-fleet.md index e0db75d68759..6ee517a43da3 100644 --- a/docs/Get started/why-fleet.md +++ b/docs/Get started/why-fleet.md @@ -4,9 +4,9 @@ Fleet is an open-source device management platform for Linux, macOS, Windows, Ch ## What's it for? -Managing computers today is getting harder. You have to juggle a mix of operating systems and devices, with a whole bunch of middleman vendors in between. +Managing computers today is getting harder. You have to juggle a mix of operating systems and devices, with a bunch of middleman vendors in between. -Fleet makes things easier by giving you a single system to manage and secure all your computing devices. You can do MDM, patch stuff, and verify anything—all from one dashboard. It's like having a universal remote control for all your organization's computers. +Fleet makes things easier by giving you a single system to secure and maintain all your computing devices over the air. You can do MDM, patch stuff, and verify anything—all from one system. It's like having a universal remote control for all your organization's computers. Fleet is open source, and free features will always be free. @@ -15,7 +15,7 @@ Fleet is open source, and free features will always be free. Fleet is used in production by IT and security teams with thousands of laptops and servers. Many deployments support tens of thousands of hosts, and a few large organizations manage deployments as large as 400,000+ hosts. - **Get what you need:** Fleet lets you work directly with [data](https://fleetdm.com/integrations) and events from the native operating system. It lets you go all the way down to the bare metal. It’s also modular. (You can turn off features you are not using.) -- **Out of the box:** Ready-to-use integrations exist for the [most common tools](https://fleetdm.com/integrations). You can also build custom workflows with the REST API, webhook events, and the fleetctl command line tool. Or go all in and manage computers [with GitOps](https://fleetdm.com/handbook/company#history). +- **Out of the box:** Ready-to-use integrations exist for the [most common tools](https://fleetdm.com/integrations). You can also build custom workflows with the REST API, webhook events, and the fleetctl command line tool. Or go all in and govern computers [with GitOps](https://github.com/fleetdm/fleet-gitops). - **Good neighbors:** We think tools should be as easy as possible for everyone to understand. We helped [create osquery](https://fleetdm.com/handbook/company#history), and we are committed to improving it. - **Free as in free:** The free version of Fleet will [always be free](https://fleetdm.com/pricing). Fleet is independently backed and actively maintained with the help of many amazing contributors. diff --git a/docs/REST API/rest-api.md b/docs/REST API/rest-api.md index 0a760c32d5fc..cb23ae838055 100644 --- a/docs/REST API/rest-api.md +++ b/docs/REST API/rest-api.md @@ -4295,8 +4295,10 @@ Resends a configuration profile for the specified host. "name": "Logic Pro", "software_package": null "app_store_app": { - "app_store_id": "1091189122" + "app_store_id": "1091189122", + "icon_url": "https://is1-ssl.mzstatic.com/image/thumb/Purple221/v4/f4/25/1f/f4251f60-e27a-6f05-daa7-9f3a63aac929/AppIcon-0-0-85-220-0-0-4-0-0-2x-0-0-0-0-0.png/512x512bb.png" "version": "2.04", + "self_service": false, "last_install": { "command_uuid": "0aa14ae5-58fe-491a-ac9a-e4ee2b3aac40", "installed_at": "2024-05-15T15:23:57Z" @@ -5573,6 +5575,7 @@ solely on the response status code returned by this endpoint. ``` ###### Example response body + ```xml @@ -5720,6 +5723,7 @@ Get aggregate status counts of profiles for to macOS and Windows hosts that are - [Set custom MDM setup enrollment profile](#set-custom-mdm-setup-enrollment-profile) - [Get custom MDM setup enrollment profile](#get-custom-mdm-setup-enrollment-profile) - [Delete custom MDM setup enrollment profile](#delete-custom-mdm-setup-enrollment-profile) +- [Get Over-the-Air (OTA) enrollment profile](#get-over-the-air-ota-enrollment-profile) - [Get manual enrollment profile](#get-manual-enrollment-profile) - [Upload a bootstrap package](#upload-a-bootstrap-package) - [Get metadata about a bootstrap package](#get-metadata-about-a-bootstrap-package) @@ -5827,10 +5831,83 @@ Deletes the custom MDM setup enrollment profile assigned to a team or no team. `Status: 204` +### Get Over-the-Air (OTA) enrollment profile + +`GET /api/v1/fleet/enrollment_profiles/ota` + +The returned value is a signed `.mobileconfig` OTA enrollment profile. Install this profile on macOS, iOS, or iPadOS hosts to enroll them to a specific team in Fleet and turn on MDM features. + +To enroll macOS hosts, turn on MDM features, and add [human-device mapping](#get-human-device-mapping), install the [manual enrollment profile](#get-manual-enrollment-profile) instead. + +Learn more about OTA profiles [here](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/OTASecurity/OTASecurity.html). + +#### Parameters + +| Name | Type | In | Description | +|-------------------|---------|-------|----------------------------------------------------------------------------------| +| enroll_secret | string | query | **Required**. The enroll secret of the team this host will be assigned to. | + +#### Example + +`GET /api/v1/fleet/enrollment_profiles/ota?enroll_secret=foobar` + +##### Default response + +`Status: 200` + +> **Note:** To confirm success, it is important for clients to match content length with the response header (this is done automatically by most clients, including the browser) rather than relying solely on the response status code returned by this endpoint. + +##### Example response headers + +```http + Content-Length: 542 + Content-Type: application/x-apple-aspen-config; charset=urf-8 + Content-Disposition: attachment;filename="fleet-mdm-enrollment-profile.mobileconfig" + X-Content-Type-Options: nosniff +``` + +###### Example response body + +```xml + + + + + PayloadContent + + URL + https://foo.example.com/api/fleet/ota_enrollment?enroll_secret=foobar + DeviceAttributes + + UDID + VERSION + PRODUCT + SERIAL + + + PayloadOrganization + Acme Inc. + PayloadDisplayName + Acme Inc. enrollment + PayloadVersion + 1 + PayloadUUID + fdb376e5-b5bb-4d8c-829e-e90865f990c9 + PayloadIdentifier + com.fleetdm.fleet.mdm.apple.ota + PayloadType + Profile Service + + +``` + + ### Get manual enrollment profile Retrieves an unsigned manual enrollment profile for macOS hosts. Install this profile on macOS hosts to turn on MDM features manually. +To add [human-device mapping](#get-human-device-mapping), add the end user's email to the enrollment profle. Learn how [here](https://fleetdm.com/guides/config-less-fleetd-agent-deployment#basic-article). + `GET /api/v1/fleet/enrollment_profiles/manual` ##### Example @@ -6442,7 +6519,8 @@ None. ] ``` -Get Volume Purchasing Program (VPP) +### Get Volume Purchasing Program (VPP) + > **Experimental feature**. This feature is undergoing rapid improvement, which may result in breaking changes to the API or configuration surface. It is not recommended for use in automated workflows. @@ -8652,10 +8730,6 @@ Deletes the session specified by ID. When the user associated with the session n - [Get package install result](#get-package-install-result) - [Download package](#download-package) - [Delete package or App Store app](#delete-package-or-app-store-app) -- [Batch-apply software](#batch-apply-software) -- [Batch-apply app store apps](#batch-apply-app-store-apps) -- [Get token to download package](#get-token-to-download-package) -- [Download package using a token](#download-package-using-a-token) ### List software @@ -9026,9 +9100,10 @@ Returns information about the specified software. By default, `versions` are sor "software_package": null, "app_store_app": { "name": "Logic Pro", - "app_store_id": "1091189122", + "app_store_id": 1091189122, "latest_version": "2.04", "icon_url": "https://is1-ssl.mzstatic.com/image/thumb/Purple211/v4/f1/65/1e/a4844ccd-486d-455f-bb31-67336fe46b14/AppIcon-1x_U007emarketing-0-7-0-85-220-0.png/512x512bb.jpg", + "self_service": true, "status": { "installed": 3, "pending": 1, @@ -9107,6 +9182,7 @@ Returns information about the specified software version. } ``` + ### Get operating system version Retrieves information about the specified operating system (OS) version. @@ -9379,6 +9455,7 @@ Add App Store (VPP) app purchased in Apple Business Manager. | app_store_id | string | body | **Required.** The ID of App Store app. | | team_id | integer | body | **Required**. The team ID. Adds VPP software to the specified team. | | platform | string | body | The platform of the app (`darwin`, `ios`, or `ipados`). Default is `darwin`. | +| self_service | boolean | body | Self-service software is optional and can be installed by the end user. | #### Example @@ -9391,6 +9468,7 @@ Add App Store (VPP) app purchased in Apple Business Manager. "app_store_id": "497799835", "team_id": 2, "platform": "ipados" + "self_service": true } ``` @@ -9398,38 +9476,6 @@ Add App Store (VPP) app purchased in Apple Business Manager. `Status: 200` -### Download package - -> **Experimental feature**. This feature is undergoing rapid improvement, which may result in breaking changes to the API or configuration surface. It is not recommended for use in automated workflows. - -_Available in Fleet Premium._ - -`GET /api/v1/fleet/software/titles/:software_title_id/package?alt=media` - -#### Parameters - -| Name | Type | In | Description | -| ---- | ------- | ---- | -------------------------------------------- | -| software_title_id | integer | path | **Required**. The ID of the software title to download software package.| -| team_id | integer | query | **Required**. The team ID. Downloads a software package added to the specified team. | -| alt | integer | query | **Required**. If specified and set to "media", downloads the specified software package. | - -#### Example - -`GET /api/v1/fleet/software/titles/123/package?alt=media?team_id=2` - -##### Default response - -`Status: 200` - -```http -Status: 200 -Content-Type: application/octet-stream -Content-Disposition: attachment -Content-Length: -Body: -``` - ### Install package or App Store app > **Experimental feature**. This feature is undergoing rapid improvement, which may result in breaking changes to the API or configuration surface. It is not recommended for use in automated workflows. @@ -9487,7 +9533,7 @@ _Available in Fleet Premium._ `GET /api/v1/fleet/software/install/:install_uuid/results` -Get the results of a software package install. +Get the results of a software package install. To get the results of an App Store app install, use the [List MDM commands](#list-mdm-commands) and [Get MDM command results](#get-mdm-command-results) API enpoints. Fleet uses an MDM command to install App Store apps. @@ -9518,141 +9564,62 @@ To get the results of an App Store app install, use the [List MDM commands](#lis } ``` -### Delete package or App Store app +### Download package > **Experimental feature**. This feature is undergoing rapid improvement, which may result in breaking changes to the API or configuration surface. It is not recommended for use in automated workflows. _Available in Fleet Premium._ -Deletes software that's available for install (package or App Store app). - -`DELETE /api/v1/fleet/software/titles/:software_title_id/available_for_install` +`GET /api/v1/fleet/software/titles/:software_title_id/package?alt=media` #### Parameters | Name | Type | In | Description | | ---- | ------- | ---- | -------------------------------------------- | -| software_title_id | integer | path | **Required**. The ID of the software title to delete software available for install. | -| team_id | integer | query | **Required**. The team ID. Deletes a software package added to the specified team. | - -#### Example - -`DELETE /api/v1/fleet/software/titles/24/available_for_install?team_id=2` - -##### Default response - -`Status: 204` - -### Batch-apply software - -_Available in Fleet Premium._ - -`POST /api/v1/fleet/software/batch` - -#### Parameters - -| Name | Type | In | Description | -| --------- | ------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| team_id | number | query | The ID of the team to add the software package to. Only one team identifier (`team_id` or `team_name`) can be included in the request; omit this parameter if using `team_name`. Omitting these parameters will add software to "No Team". | -| team_name | string | query | The name of the team to add the software package to. Only one team identifier (`team_id` or `team_name`) can be included in the request; omit this parameter if using `team_id`. Omitting these parameters will add software to "No Team". | -| dry_run | bool | query | If `true`, will validate the provided software packages and return any validation errors, but will not apply the changes. | -| software | object | body | The team's software that will be available for install. | -| software.packages | list | body | An array of objects. Each object consists of:`url`- URL to the software package (PKG, MSI, EXE or DEB),`install_script` - command that Fleet runs to install software, `pre_install_query` - condition query that determines if the install will proceed, `post_install_script` - script that runs after software install, and `uninstall_script` - command that Fleet runs to uninstall software. | -| software.app_store_apps | list | body | An array objects. Each object consists of `app_store_id` - ID of the App Store app. | - -If both `team_id` and `team_name` parameters are included, this endpoint will respond with an error. If no `team_name` or `team_id` is provided, the scripts will be applied for **all hosts**. - -#### Example - -`POST /api/v1/fleet/software/batch` - -##### Default response - -`Status: 204` - -### Batch-apply app store apps - -_Available in Fleet Premium._ - -`POST /api/v1/fleet/software/app_store_apps/batch` - -#### Parameters - -| Name | Type | In | Description | -|-----------------|---------|-------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| team_name | integer | query | **Required**. The name of the team to add the app to. | -| dry_run | bool | query | If `true`, will validate the provided apps and return any validation errors, but will not apply the changes. | -| apps_store_apps | list | body | The list of objects containing `app_store_id`: a string representation of the app's App ID, `self_service`: a bool indicating if the app's installation can be initiated by end users. | - -> Note that this endpoint replaces all apps associated with a team. - -#### Example - -`POST /api/v1/fleet/software/app_store_apps/batch` - -#### Default response - -`Status: 204` - -### Get token to download package - -_Available in Fleet Premium._ - -`POST /api/v1/fleet/software/titles/:software_title_id/package/token?alt=media` - -The returned token is a one-time use token that expires after 10 minutes. - -#### Parameters - -| Name | Type | In | Description | -|-------------------|---------|-------|------------------------------------------------------------------| -| software_title_id | integer | path | **Required**. The ID of the software title for software package. | -| team_id | integer | query | **Required**. The team ID containing the software package. | -| alt | integer | query | **Required**. Must be specified and set to "media". | +| software_title_id | integer | path | **Required**. The ID of the software title to download software package.| +| team_id | integer | query | **Required**. The team ID. Downloads a software package added to the specified team. | +| alt | integer | query | **Required**. If specified and set to "media", downloads the specified software package. | #### Example -`POST /api/v1/fleet/software/titles/123/package/token?alt=media&team_id=2` +`GET /api/v1/fleet/software/titles/123/package?alt=media?team_id=2` ##### Default response `Status: 200` -```json -{ - "token": "e905e33e-07fe-4f82-889c-4848ed7eecb7" -} +```http +Status: 200 +Content-Type: application/octet-stream +Content-Disposition: attachment +Content-Length: +Body: ``` -### Download package using a token +### Delete package or App Store app + +> **Experimental feature**. This feature is undergoing rapid improvement, which may result in breaking changes to the API or configuration surface. It is not recommended for use in automated workflows. _Available in Fleet Premium._ -`GET /api/v1/fleet/software/titles/:software_title_id/package/token/:token?alt=media` +Deletes software that's available for install (package or App Store app). + +`DELETE /api/v1/fleet/software/titles/:software_title_id/available_for_install` #### Parameters -| Name | Type | In | Description | -|-------------------|---------|------|--------------------------------------------------------------------------| -| software_title_id | integer | path | **Required**. The ID of the software title to download software package. | -| token | string | path | **Required**. The token to download the software package. | +| Name | Type | In | Description | +| ---- | ------- | ---- | -------------------------------------------- | +| software_title_id | integer | path | **Required**. The ID of the software title to delete software available for install. | +| team_id | integer | query | **Required**. The team ID. Deletes a software package added to the specified team. | #### Example -`GET /api/v1/fleet/software/titles/123/package/token/e905e33e-07fe-4f82-889c-4848ed7eecb7` +`DELETE /api/v1/fleet/software/titles/24/available_for_install?team_id=2` ##### Default response -`Status: 200` - -```http -Status: 200 -Content-Type: application/octet-stream -Content-Disposition: attachment -Content-Length: -Body: -``` - +`Status: 204` ## Vulnerabilities diff --git a/ee/server/service/software_installers.go b/ee/server/service/software_installers.go index ac4461a592b2..a2dea22138bb 100644 --- a/ee/server/service/software_installers.go +++ b/ee/server/service/software_installers.go @@ -1054,7 +1054,7 @@ func (svc *Service) addMetadataToSoftwarePayload(ctx context.Context, payload *f if err != nil { if errors.Is(err, file.ErrUnsupportedType) { return "", &fleet.BadRequestError{ - Message: "Couldn't edit software. File type not supported. The file should be .pkg, .msi, .exe or .deb.", + Message: "Couldn't edit software. File type not supported. The file should be .pkg, .msi, .exe, .deb or .rpm.", InternalErr: ctxerr.Wrap(ctx, err, "extracting metadata from installer"), } } @@ -1517,7 +1517,7 @@ func packageExtensionToPlatform(ext string) string { requiredPlatform = "windows" case ".pkg": requiredPlatform = "darwin" - case ".deb": + case ".deb", ".rpm": requiredPlatform = "linux" default: return "" diff --git a/frontend/interfaces/package_type.ts b/frontend/interfaces/package_type.ts index 8afb43cef382..b8b83b93fe9d 100644 --- a/frontend/interfaces/package_type.ts +++ b/frontend/interfaces/package_type.ts @@ -1,4 +1,4 @@ -const unixPackageTypes = ["pkg", "deb"] as const; +const unixPackageTypes = ["pkg", "deb", "rpm"] as const; const windowsPackageTypes = ["msi", "exe"] as const; export const packageTypes = [ ...unixPackageTypes, diff --git a/frontend/interfaces/software.ts b/frontend/interfaces/software.ts index 77b4c91767cb..5db289051a3a 100644 --- a/frontend/interfaces/software.ts +++ b/frontend/interfaces/software.ts @@ -270,7 +270,7 @@ export interface ISoftwareInstallResults { // ISoftwareInstallerType defines the supported installer types for // software uploaded by the IT admin. -export type ISoftwareInstallerType = "pkg" | "msi" | "deb" | "exe"; +export type ISoftwareInstallerType = "pkg" | "msi" | "deb" | "rpm" | "exe"; export interface ISoftwareLastInstall { install_uuid: string; diff --git a/frontend/pages/ManageControlsPage/Scripts/components/DeleteScriptModal/DeleteScriptModal.tsx b/frontend/pages/ManageControlsPage/Scripts/components/DeleteScriptModal/DeleteScriptModal.tsx index eef37919dc87..8b5fec069426 100644 --- a/frontend/pages/ManageControlsPage/Scripts/components/DeleteScriptModal/DeleteScriptModal.tsx +++ b/frontend/pages/ManageControlsPage/Scripts/components/DeleteScriptModal/DeleteScriptModal.tsx @@ -44,8 +44,8 @@ const DeleteScriptModal = ({

The script{" "} {scriptName} will - run on pending hosts. After the script runs, its output and - exit code will appear in the activity feed. + run on pending hosts. After the script runs, its output and exit code + will appear in the activity feed.