diff --git a/.yarnrc b/.yarnrc new file mode 100644 index 0000000000..fdd705c635 --- /dev/null +++ b/.yarnrc @@ -0,0 +1 @@ +save-prefix "" diff --git a/assets/images/os-prefill-preview.gif b/assets/images/os-prefill-preview.gif new file mode 100644 index 0000000000..21fcc0693a Binary files /dev/null and b/assets/images/os-prefill-preview.gif differ diff --git a/changes/17018-reset-query-report b/changes/17018-reset-query-report new file mode 100644 index 0000000000..444fac3f8b --- /dev/null +++ b/changes/17018-reset-query-report @@ -0,0 +1 @@ +- Query report is reset when there is a change to the selected platform or selected minimum osquery version diff --git a/changes/17264-batch-process-gitops b/changes/17264-batch-process-gitops new file mode 100644 index 0000000000..cfa7ce9776 --- /dev/null +++ b/changes/17264-batch-process-gitops @@ -0,0 +1 @@ +- `fleetctl gitops` now batch processes queries and policies \ No newline at end of file diff --git a/changes/17265-filter-alignment b/changes/17265-filter-alignment new file mode 100644 index 0000000000..a27c775810 --- /dev/null +++ b/changes/17265-filter-alignment @@ -0,0 +1 @@ +* Fix a small alignment bug diff --git a/changes/17559-batch-set-duplicate-mdm b/changes/17559-batch-set-duplicate-mdm new file mode 100644 index 0000000000..f037326fff --- /dev/null +++ b/changes/17559-batch-set-duplicate-mdm @@ -0,0 +1 @@ +- Added cross-platform check for duplicate MDM profiles names in batch set MDM profiles API. diff --git a/changes/17621-bulk-delete-hosts-all-teams b/changes/17621-bulk-delete-hosts-all-teams new file mode 100644 index 0000000000..ed210b1655 --- /dev/null +++ b/changes/17621-bulk-delete-hosts-all-teams @@ -0,0 +1 @@ +- Fix UI's ability to bulk delete hosts when "All teams" is selected diff --git a/changes/17927-fix-styling-for-live-query-disabled-warning b/changes/17927-fix-styling-for-live-query-disabled-warning new file mode 100644 index 0000000000..42323137fb --- /dev/null +++ b/changes/17927-fix-styling-for-live-query-disabled-warning @@ -0,0 +1 @@ +- UI fix: styling of live query disabled warning diff --git a/cmd/fleet/calendar_cron.go b/cmd/fleet/calendar_cron.go index 953747c602..54bd89f551 100644 --- a/cmd/fleet/calendar_cron.go +++ b/cmd/fleet/calendar_cron.go @@ -17,6 +17,8 @@ import ( "github.com/go-kit/log/level" ) +const calendarConsumers = 18 + func newCalendarSchedule( ctx context.Context, instanceID string, @@ -200,11 +202,10 @@ func processCalendarFailingHosts( ) { hosts = filterHostsWithSameEmail(hosts) - const consumers = 20 hostsCh := make(chan fleet.HostPolicyMembershipData) var wg sync.WaitGroup - for i := 0; i < consumers; i++ { + for i := 0; i < calendarConsumers; i++ { wg.Add(+1) go func() { defer wg.Done() @@ -500,11 +501,10 @@ func removeCalendarEventsFromPassingHosts( }) } - const consumers = 20 emailsCh := make(chan emailWithHosts) var wg sync.WaitGroup - for i := 0; i < consumers; i++ { + for i := 0; i < calendarConsumers; i++ { wg.Add(+1) go func() { defer wg.Done() @@ -601,15 +601,16 @@ func cronCalendarEventsCleanup(ctx context.Context, ds fleet.Datastore, logger k } var userCalendar fleet.UserCalendar + var calendarConfig *fleet.GoogleCalendarIntegration if len(appConfig.Integrations.GoogleCalendar) > 0 { - googleCalendarIntegrationConfig := appConfig.Integrations.GoogleCalendar[0] - userCalendar = createUserCalendarFromConfig(ctx, googleCalendarIntegrationConfig, logger) + calendarConfig = appConfig.Integrations.GoogleCalendar[0] + userCalendar = createUserCalendarFromConfig(ctx, calendarConfig, logger) } // If global setting is disabled, we remove all calendar events from the DB // (we cannot delete the events from the user calendar because there's no configuration anymore). if userCalendar == nil { - if err := deleteAllCalendarEvents(ctx, ds, nil, nil); err != nil { + if err := deleteAllCalendarEvents(ctx, ds, nil, nil, logger); err != nil { return fmt.Errorf("delete all calendar events: %w", err) } // We've deleted all calendar events, nothing else to do. @@ -630,7 +631,7 @@ func cronCalendarEventsCleanup(ctx context.Context, ds fleet.Datastore, logger k } for _, team := range teams { - if err := cleanupTeamCalendarEvents(ctx, ds, userCalendar, *team); err != nil { + if err := cleanupTeamCalendarEvents(ctx, ds, calendarConfig, *team, logger); err != nil { level.Info(logger).Log("msg", "delete team calendar events", "team_id", team.ID, "err", err) } } @@ -644,38 +645,59 @@ func cronCalendarEventsCleanup(ctx context.Context, ds fleet.Datastore, logger k if err != nil { return fmt.Errorf("list out of date calendar events: %w", err) } - for _, outOfDateCalendarEvent := range outOfDateCalendarEvents { - if err := deleteCalendarEvent(ctx, ds, userCalendar, outOfDateCalendarEvent); err != nil { - return fmt.Errorf("delete user calendar event: %w", err) - } - } - + deleteCalendarEventsInParallel(ctx, ds, calendarConfig, outOfDateCalendarEvents, logger) return nil } func deleteAllCalendarEvents( ctx context.Context, ds fleet.Datastore, - userCalendar fleet.UserCalendar, + calendarConfig *fleet.GoogleCalendarIntegration, teamID *uint, + logger kitlog.Logger, ) error { calendarEvents, err := ds.ListCalendarEvents(ctx, teamID) if err != nil { return fmt.Errorf("list calendar events: %w", err) } - for _, calendarEvent := range calendarEvents { - if err := deleteCalendarEvent(ctx, ds, userCalendar, calendarEvent); err != nil { - return fmt.Errorf("delete user calendar event: %w", err) - } - } + deleteCalendarEventsInParallel(ctx, ds, calendarConfig, calendarEvents, logger) return nil } +func deleteCalendarEventsInParallel( + ctx context.Context, ds fleet.Datastore, calendarConfig *fleet.GoogleCalendarIntegration, calendarEvents []*fleet.CalendarEvent, + logger kitlog.Logger, +) { + if len(calendarEvents) > 0 { + calendarEventCh := make(chan *fleet.CalendarEvent) + var wg sync.WaitGroup + for i := 0; i < calendarConsumers; i++ { + wg.Add(+1) + go func() { + defer wg.Done() + for calEvent := range calendarEventCh { + userCalendar := createUserCalendarFromConfig(ctx, calendarConfig, logger) + if err := deleteCalendarEvent(ctx, ds, userCalendar, calEvent); err != nil { + level.Error(logger).Log("msg", "delete user calendar event", "err", err) + continue + } + } + }() + } + for _, outOfDateCalendarEvent := range calendarEvents { + calendarEventCh <- outOfDateCalendarEvent + } + close(calendarEventCh) + wg.Wait() + } +} + func cleanupTeamCalendarEvents( ctx context.Context, ds fleet.Datastore, - userCalendar fleet.UserCalendar, + calendarConfig *fleet.GoogleCalendarIntegration, team fleet.Team, + logger kitlog.Logger, ) error { teamFeatureEnabled := team.Config.Integrations.GoogleCalendar != nil && team.Config.Integrations.GoogleCalendar.Enable @@ -692,7 +714,7 @@ func cleanupTeamCalendarEvents( // so we want to cleanup all calendar events for the team. } - return deleteAllCalendarEvents(ctx, ds, userCalendar, &team.ID) + return deleteAllCalendarEvents(ctx, ds, calendarConfig, &team.ID, logger) } func deleteCalendarEvent(ctx context.Context, ds fleet.Datastore, userCalendar fleet.UserCalendar, calendarEvent *fleet.CalendarEvent) error { diff --git a/cmd/fleetctl/mdm_test.go b/cmd/fleetctl/mdm_test.go index d275e15aab..0a7062de30 100644 --- a/cmd/fleetctl/mdm_test.go +++ b/cmd/fleetctl/mdm_test.go @@ -101,8 +101,10 @@ func TestMDMRunCommand(t *testing.T) { MDM: fleet.MDMHostData{Name: fleet.WellKnownMDMFleet, EnrollmentStatus: ptr.String("Pending")}, } hostByUUID := make(map[string]*fleet.Host) + hostByID := make(map[uint]*fleet.Host) for _, h := range []*fleet.Host{macEnrolled, winEnrolled, macUnenrolled, winUnenrolled, linuxUnenrolled, macEnrolled2, winEnrolled2, macNonFleetEnrolled, winNonFleetEnrolled, macPending, winPending} { hostByUUID[h.UUID] = h + hostByID[h.ID] = h } // define some files to use in the tests @@ -221,6 +223,15 @@ func TestMDMRunCommand(t *testing.T) { ds.GetMDMWindowsBitLockerStatusFunc = func(ctx context.Context, host *fleet.Host) (*fleet.HostMDMDiskEncryption, error) { return &fleet.HostMDMDiskEncryption{}, nil } + ds.GetHostMDMFunc = func(ctx context.Context, hostID uint) (*fleet.HostMDM, error) { + h, ok := hostByID[hostID] + require.True(t, ok) + if h.MDMInfo == nil { + return nil, ¬FoundError{} + } + return h.MDMInfo, nil + } + enqueuer.EnqueueCommandFunc = func(ctx context.Context, id []string, cmd *mdm.Command) (map[string]error, error) { return map[string]error{}, nil } @@ -467,6 +478,15 @@ func TestMDMLockCommand(t *testing.T) { return nil } + ds.GetHostMDMFunc = func(ctx context.Context, hostID uint) (*fleet.HostMDM, error) { + h, ok := hostsByID[hostID] + if !ok || h.MDMInfo == nil { + return nil, ¬FoundError{} + } + + return h.MDMInfo, nil + } + appCfgAllMDM, appCfgWinMDM, appCfgMacMDM, appCfgNoMDM := setupAppConigs() successfulOutput := func(ident string) string { @@ -701,6 +721,15 @@ func TestMDMUnlockCommand(t *testing.T) { return nil } + ds.GetHostMDMFunc = func(ctx context.Context, hostID uint) (*fleet.HostMDM, error) { + h, ok := hostsByID[hostID] + if !ok || h.MDMInfo == nil { + return nil, ¬FoundError{} + } + + return h.MDMInfo, nil + } + appCfgAllMDM, appCfgWinMDM, appCfgMacMDM, appCfgNoMDM := setupAppConigs() successfulOutput := func(ident string) string { @@ -1001,6 +1030,15 @@ func TestMDMWipeCommand(t *testing.T) { return nil } + ds.GetHostMDMFunc = func(ctx context.Context, hostID uint) (*fleet.HostMDM, error) { + h, ok := hostsByID[hostID] + if !ok || h.MDMInfo == nil { + return nil, ¬FoundError{} + } + + return h.MDMInfo, nil + } + appCfgAllMDM, appCfgWinMDM, appCfgMacMDM, appCfgNoMDM := setupAppConigs() appCfgScriptsDisabled := &fleet.AppConfig{ServerSettings: fleet.ServerSettings{ScriptsDisabled: true}} diff --git a/cmd/osquery-perf/agent.go b/cmd/osquery-perf/agent.go index 756f6f0cd5..611bcfe702 100644 --- a/cmd/osquery-perf/agent.go +++ b/cmd/osquery-perf/agent.go @@ -401,7 +401,7 @@ type agent struct { // single goroutine at a time can execute scripts. scriptExecRunning atomic.Bool - softwareVSCodeExtensionsProb float64 + softwareQueryFailureProb float64 softwareVSCodeExtensionsFailProb float64 // @@ -544,7 +544,7 @@ func newAgent( UUID: hostUUID, SerialNumber: serialNumber, - softwareVSCodeExtensionsProb: softwareQueryFailureProb, + softwareQueryFailureProb: softwareQueryFailureProb, softwareVSCodeExtensionsFailProb: softwareVSCodeExtensionsQueryFailureProb, macMDMClient: macMDMClient, @@ -1737,7 +1737,7 @@ func (a *agent) processQuery(name, query string) ( return true, results, &ss, nil, nil case name == hostDetailQueryPrefix+"software_macos": ss := fleet.StatusOK - if a.softwareVSCodeExtensionsProb > 0.0 && rand.Float64() <= a.softwareVSCodeExtensionsProb { + if a.softwareQueryFailureProb > 0.0 && rand.Float64() <= a.softwareQueryFailureProb { ss = fleet.OsqueryStatus(1) } if ss == fleet.StatusOK { @@ -1746,7 +1746,7 @@ func (a *agent) processQuery(name, query string) ( return true, results, &ss, nil, nil case name == hostDetailQueryPrefix+"software_windows": ss := fleet.StatusOK - if a.softwareVSCodeExtensionsProb > 0.0 && rand.Float64() <= a.softwareVSCodeExtensionsProb { + if a.softwareQueryFailureProb > 0.0 && rand.Float64() <= a.softwareQueryFailureProb { ss = fleet.OsqueryStatus(1) } if ss == fleet.StatusOK { @@ -1755,7 +1755,7 @@ func (a *agent) processQuery(name, query string) ( return true, results, &ss, nil, nil case name == hostDetailQueryPrefix+"software_linux": ss := fleet.StatusOK - if a.softwareVSCodeExtensionsProb > 0.0 && rand.Float64() <= a.softwareVSCodeExtensionsProb { + if a.softwareQueryFailureProb > 0.0 && rand.Float64() <= a.softwareQueryFailureProb { ss = fleet.OsqueryStatus(1) } if ss == fleet.StatusOK { @@ -2019,8 +2019,8 @@ func main() { onlyAlreadyEnrolled = flag.Bool("only_already_enrolled", false, "Only start agents that are already enrolled") nodeKeyFile = flag.String("node_key_file", "", "File with node keys to use") - softwareQueryFailureProb = flag.Float64("software_query_fail_prob", 0.5, "Probability of the software query failing") - softwareVSCodeExtensionsQueryFailureProb = flag.Float64("software_vscode_extensions_query_fail_prob", 0.5, "Probability of the software vscode_extensions query failing") + softwareQueryFailureProb = flag.Float64("software_query_fail_prob", 0.05, "Probability of the software query failing") + softwareVSCodeExtensionsQueryFailureProb = flag.Float64("software_vscode_extensions_query_fail_prob", 0.05, "Probability of the software vscode_extensions query failing") commonSoftwareCount = flag.Int("common_software_count", 10, "Number of common installed applications reported to fleet") commonVSCodeExtensionsSoftwareCount = flag.Int("common_vscode_extensions_software_count", 5, "Number of common vscode_extensions installed applications reported to fleet") diff --git a/docs/Get started/FAQ.md b/docs/Get started/FAQ.md index 9f7d76edd4..aaacfd3813 100644 --- a/docs/Get started/FAQ.md +++ b/docs/Get started/FAQ.md @@ -113,7 +113,7 @@ To uninstall the osquery agent, follow the below instructions for your operating Run the Orbit [cleanup script](https://github.com/fleetdm/fleet/blob/main/orbit/tools/cleanup/cleanup_macos.sh) #### Windows -Use the "Add or remove programs" dialog to remove Orbit. +Use the "Add or remove programs" dialog to remove Fleet osquery. #### Ubuntu Run `sudo apt remove fleet-osquery -y` diff --git a/docs/REST API/rest-api.md b/docs/REST API/rest-api.md index 2358f62050..39ea5b88c1 100644 --- a/docs/REST API/rest-api.md +++ b/docs/REST API/rest-api.md @@ -7373,10 +7373,10 @@ This allows you to easily configure scheduled queries that will impact a whole t - [Run script](#run-script) - [Get script result](#get-script-result) - [Run live script](#run-live-script) -- [Upload a script](#upload-a-script) -- [Delete a script](#delete-a-script) +- [Add script](#add-script) +- [Delete script](#delete-script) - [List scripts](#list-scripts) -- [Get or download a script](#get-or-download-a-script) +- [Get or download script](#get-or-download-script) - [Get script details by host](#get-script-details-by-host) ### Run script @@ -7488,7 +7488,7 @@ Run a live script and get results back (5 minute timeout). Live scripts only run } ``` -### Upload a script +### Add script Uploads a script, making it available to run on hosts assigned to the specified team (or no team). @@ -7538,7 +7538,7 @@ echo "hello" } ``` -### Delete a script +### Delete script Deletes an existing script. @@ -7566,6 +7566,7 @@ Deletes an existing script. | Name | Type | In | Description | | --------------- | ------- | ----- | ----------------------------------------------------------------------------------------------------------------------------- | +| team_id | integer | query | _Available in Fleet Premium_. The ID of the team to filter scripts by. If not specified, it will filter only scripts that are available to hosts with no team. | | page | integer | query | Page number of the results to fetch. | | per_page | integer | query | Results per page. | @@ -7603,7 +7604,7 @@ Deletes an existing script. ``` -### Get or download a script +### Get or download script `GET /api/v1/fleet/scripts/:id` @@ -7614,7 +7615,7 @@ Deletes an existing script. | id | integer | path | **Required.** The desired script's ID. | | alt | string | query | If specified and set to "media", downloads the script's contents. | -#### Example (get a script) +#### Example (get script) `GET /api/v1/fleet/scripts/123` @@ -7633,7 +7634,7 @@ Deletes an existing script. ``` -#### Example (download a script's contents) +#### Example (download script) `GET /api/v1/fleet/scripts/123?alt=media` diff --git a/docs/Using Fleet/CIS-Benchmarks.md b/docs/Using Fleet/CIS-Benchmarks.md index 1bcbb2e1fc..9942eb0e3c 100644 --- a/docs/Using Fleet/CIS-Benchmarks.md +++ b/docs/Using Fleet/CIS-Benchmarks.md @@ -2,8 +2,6 @@ _Available in Fleet Premium_. -## Overview - CIS Benchmarks represent the consensus-based effort of cybersecurity experts globally to help you protect your systems against threats more confidently. For more information about CIS Benchmarks check out [Center for Internet Security](https://www.cisecurity.org/cis-benchmarks)'s website. @@ -46,22 +44,6 @@ Two things are being evaluated in this policy: If either of these conditions fails, the host is considered to be failing the policy. -## Requirements - -Following are the requirements to use the CIS Benchmarks in Fleet: - -- To use these policies, Fleet must have an up-to-date paid license (β‰₯Fleet Premium). -- Devices must be running [`fleetd`](https://fleetdm.com/docs/using-fleet/orbit), the lightweight agent that bundles the latest osqueryd. -- Some CIS Benchmarks explicitly involve verifying MDM-based controls, so devices must be enrolled to an MDM solution. (Any MDM solution works, it doesn't have to be Fleet.) -- On macOS, the orbit executable in Fleetd must have "Full Disk Access", see [Grant Full Disk Access to Osquery on macOS](./Adding-hosts.md#grant-full-disk-access-to-osquery-on-macos). - -### MDM required -Some of the policies created by Fleet use the [managed_policies](https://www.fleetdm.com/tables/managed_policies) table. This checks whether an MDM solution has turned on the setting to enforce the policy. -Using MDM is the recommended way to manage and enforce CIS Benchmarks. To learn how to set up MDM in Fleet, visit [here](/docs/using-fleet/mdm-macos-setup). - -### Fleetd required -Fleet's CIS Benchmarks require our [osquery manager, Fleetd](https://fleetdm.com/docs/using-fleet/adding-hosts#osquery-installer). This is because Fleetd includes tables which are not part of vanilla osquery in order to accomplish auditing the benchmarks. - ## How to add CIS Benchmarks All CIS policies are stored under our restricted licensed folder `ee/cis/`. @@ -89,25 +71,6 @@ To apply the policies on a specific team use the `--policies-team` flag: fleetctl apply --policies-team "Workstations" -f cis-policy-queries.yml ``` -## Limitations - -Certain benchmarks require human action to audit, and cannot be automated by a policy in Fleet. For a list of specific benchmarks which are not covered, please visit the README for each benchmark: - -- [macOS 13.0 Ventura](https://github.com/fleetdm/fleet/blob/main/ee/cis/macos-13/README.md) -- [macOS 14.0 Sonoma](https://github.com/fleetdm/fleet/blob/main/ee/cis/macos-14/README.md) -- [Windows 10 Enterprise](https://github.com/fleetdm/fleet/blob/main/ee/cis/win-10/README.md) -- [Windows 11 Enterprise](https://github.com/fleetdm/fleet/blob/main/ee/cis/win-11/README.md) - -### Audit vs. remediation -Each benchmark has two elements: -1. Audit - how to find out whether the host is in compliance with the benchmark -2. Remediation - if the host is out of compliance with the benchmark, how to fix it - -Since Fleetd is currently read-only without the ability to execute actions on the host, Fleet does not implement the remediation portions of CIS benchmarks. - -To implement automated remediation, you can install a separate agent such as Munki, Chef, Puppet, etc. which has write functionality. - - ## Levels 1 and 2 CIS designates various benchmarks as Level 1 or Level 2 to describe the level of thoroughness and burden that each benchmark represents. @@ -126,6 +89,22 @@ This profile extends the "Level 1" profile. Items in this profile exhibit one or - are intended for environments or use cases where security is paramount or acts as defense in depth measure - may negatively inhibit the utility or performance of the technology. +## Requirements + +Following are the requirements to use the CIS Benchmarks in Fleet: + +- Devices must be running [`fleetd`](https://fleetdm.com/docs/using-fleet/orbit), Fleet's lightweight agent. +- Some CIS Benchmarks explicitly involve verifying MDM-based controls, so devices must be enrolled to an MDM solution. +- On macOS, the orbit component of fleetd must have "Full Disk Access", see [Grant Full Disk Access to Osquery on macOS](./Adding-hosts.md#grant-full-disk-access-to-osquery-on-macos). + +## Limitations + +Certain benchmarks cannot be automated by a policy in Fleet. For a list of specific benchmarks which are not covered, please visit the README for each benchmark: + +- [macOS 13.0 Ventura](https://github.com/fleetdm/fleet/blob/main/ee/cis/macos-13/README.md) +- [macOS 14.0 Sonoma](https://github.com/fleetdm/fleet/blob/main/ee/cis/macos-14/README.md) +- [Windows 10 Enterprise](https://github.com/fleetdm/fleet/blob/main/ee/cis/win-10/README.md) +- [Windows 11 Enterprise](https://github.com/fleetdm/fleet/blob/main/ee/cis/win-11/README.md) ## Performance testing In August 2023, we completed scale testing on 10k Windows hosts and 70k macOS hosts. Ultimately, we validated both server and host performance at that scale. diff --git a/docs/Using Fleet/enroll-hosts.md b/docs/Using Fleet/enroll-hosts.md index e0b2545f03..81e852cbb6 100644 --- a/docs/Using Fleet/enroll-hosts.md +++ b/docs/Using Fleet/enroll-hosts.md @@ -123,7 +123,7 @@ How to unenroll a host from Fleet: ## Advanced - +- [Fleet agent (fleetd) components](#fleetd-components) - [Signing fleetd installer](#signing-fleetd-installer) - [Grant full disk access to osquery on macOS](#grant-full-disk-access-to-osquery-on-macos) - [Using mTLS](#using-mtls) @@ -134,6 +134,25 @@ How to unenroll a host from Fleet: - [Generating Windows installers using local WiX toolset](#generating-windows-installers-using-local-wix-toolset) - [Experimental features](#experimental-features) +### fleetd components + +```mermaid +graph LR; + tuf["TUF file server
(default: tuf.fleetctl.com)"]; + fleet_server[Fleet
Server]; + subgraph fleetd + orbit[orbit]; + desktop[Fleet Desktop
Tray App]; + osqueryd[osqueryd]; + desktop_browser[Fleet Desktop
from Browser]; + end + orbit -- "Fleet Orbit API (TLS)" --> fleet_server; + desktop -- "Fleet Desktop API (TLS)" --> fleet_server; + osqueryd -- "osquery
remote API (TLS)" --> fleet_server; + desktop_browser -- "My Device API (TLS)" --> fleet_server; + orbit -- "Auto Update (TLS)" --> tuf; +``` + ### Signing fleetd installers >**Note:** Currently, the `fleetctl package` command does not support signing Windows fleetd installers. Windows installers can be signed after building. diff --git a/docs/Using Fleet/fleetctl-CLI.md b/docs/Using Fleet/fleetctl-CLI.md index 678dbd565e..d83702e46e 100644 --- a/docs/Using Fleet/fleetctl-CLI.md +++ b/docs/Using Fleet/fleetctl-CLI.md @@ -120,15 +120,14 @@ An API-only user does not have access to the Fleet UI. Instead, it's only purpos ### Create API-only user +Before creating the API-only user, log in to `fleetctl` as an admin. See [authentication](https://#authentication) above for details. + To create your new API-only user, use `fleetctl user create`: ```sh fleetctl user create --name "API User" --email api@example.com --password temp@pass123 --api-only ``` - -To use fleetctl with an API-only user, you will need to log in via `fleetctl`. See [authentication](https://#authentication) above for details. - #### Permissions An API-only user can be given the same permissions as a regular user. The default access level is **Observer**. You can specify what level of access the new user should have using the `--global-role` flag: diff --git a/frontend/components/LogDestinationIndicator/LogDestinationIndicator.tsx b/frontend/components/LogDestinationIndicator/LogDestinationIndicator.tsx index 3bc7998618..4d88395155 100644 --- a/frontend/components/LogDestinationIndicator/LogDestinationIndicator.tsx +++ b/frontend/components/LogDestinationIndicator/LogDestinationIndicator.tsx @@ -60,7 +60,7 @@ const LogDestinationIndicator = ({ return ( <> Each time a query runs, the data is sent to
- Amazon Kinesis Data Firehose.` + Amazon Kinesis Data Firehose. ); case "kinesis": @@ -81,7 +81,7 @@ const LogDestinationIndicator = ({ return ( <> Each time a query runs, the data is
sent to Google Cloud Pub - / Sub.` + / Sub. ); case "kafta": diff --git a/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx b/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx index a3941ac7af..9998278692 100644 --- a/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx +++ b/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx @@ -799,10 +799,8 @@ const TAGGED_TEMPLATES = { return ( <> {" "} - edited declaration (DDM) profile - {activity.details?.profile_name} - {" "} - for{" "} + edited declaration (DDM) profiles{" "} + {activity.details?.profile_name} for{" "} {getProfileMessageSuffix( isPremiumTier, "darwin", diff --git a/frontend/pages/ManageControlsPage/SetupExperience/cards/SetupAssistant/components/SetupAssistantPreview/SetupAssistantPreview.tsx b/frontend/pages/ManageControlsPage/SetupExperience/cards/SetupAssistant/components/SetupAssistantPreview/SetupAssistantPreview.tsx index 9e080644d6..d67255a6c2 100644 --- a/frontend/pages/ManageControlsPage/SetupExperience/cards/SetupAssistant/components/SetupAssistantPreview/SetupAssistantPreview.tsx +++ b/frontend/pages/ManageControlsPage/SetupExperience/cards/SetupAssistant/components/SetupAssistantPreview/SetupAssistantPreview.tsx @@ -2,7 +2,7 @@ import React from "react"; import Card from "components/Card"; -import OsSetupPreview from "../../../../../../../../assets/images/os-setup-preview.gif"; +import OsPrefillPreview from "../../../../../../../../assets/images/os-prefill-preview.gif"; const baseClass = "setup-assistant-preview"; @@ -25,7 +25,7 @@ const SetupAssistantPreview = () => {

OS setup preview diff --git a/frontend/pages/admin/IntegrationsPage/cards/Calendars/Calendars.tsx b/frontend/pages/admin/IntegrationsPage/cards/Calendars/Calendars.tsx index e9f6ed57c9..019d5f192e 100644 --- a/frontend/pages/admin/IntegrationsPage/cards/Calendars/Calendars.tsx +++ b/frontend/pages/admin/IntegrationsPage/cards/Calendars/Calendars.tsx @@ -27,7 +27,7 @@ const GOOGLE_WORKSPACE_DOMAINS = const DOMAIN_WIDE_DELEGATION = "https://www.fleetdm.com/learn-more-about/domain-wide-delegation"; const ENABLING_CALENDAR_API = - "fleetdm.com/learn-more-about/enabling-calendar-api"; + "https://www.fleetdm.com/learn-more-about/enabling-calendar-api"; const OAUTH_SCOPES = "https://www.googleapis.com/auth/calendar.events,https://www.googleapis.com/auth/calendar.settings.readonly"; @@ -112,10 +112,10 @@ const Calendars = (): JSX.Element => { // Must set all keys or no keys at all if (!curFormData.apiKeyJson && !!curFormData.domain) { - errors.apiKeyJson = "API key JSON must be present"; + errors.apiKeyJson = "API key JSON must be completed"; } if (!curFormData.domain && !!curFormData.apiKeyJson) { - errors.domain = "Domain must be present"; + errors.domain = "Domain must be completed"; } if (curFormData.apiKeyJson) { try { @@ -167,11 +167,11 @@ const Calendars = (): JSX.Element => { await configAPI.update({ integrations: destination }); renderFlash( "success", - "Successfully saved calendar integration settings" + "Successfully saved calendar integration settings." ); refetchConfig(); } catch (e) { - renderFlash("error", "Could not save calendar integration settings"); + renderFlash("error", "Could not save calendar integration settings."); } finally { setIsUpdatingSettings(false); } @@ -286,7 +286,7 @@ const Calendars = (): JSX.Element => {

5. Configure your service account integration in Fleet using the - form below: + form below.