mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 00:45:19 +00:00
Merge branch 'main' into feat-mdm-wipe-host
This commit is contained in:
commit
4ee65ce184
55
.github/workflows/dogfood-gitops.yml
vendored
Normal file
55
.github/workflows/dogfood-gitops.yml
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
name: 'Apply latest configuration to dogfood with gitops'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'it-and-security/**'
|
||||
- 'mdm_profiles/**'
|
||||
- '.github/workflows/dogfood-gitops.yml'
|
||||
workflow_dispatch: # allows manual triggering
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Limit permissions of GITHUB_TOKEN.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
fleet-gitops:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout our repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout GitOps repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: fleetdm/fleet-gitops
|
||||
ref: main
|
||||
path: fleet-gitops
|
||||
|
||||
- name: Apply latest configuration to Fleet
|
||||
uses: ./fleet-gitops/.github/gitops-action
|
||||
with:
|
||||
working-directory: ${{ github.workspace }}/fleet-gitops
|
||||
env:
|
||||
FLEET_GITOPS_DIR: ${{ github.workspace }}/it-and-security
|
||||
FLEET_URL: https://dogfood.fleetdm.com
|
||||
FLEET_API_TOKEN: ${{ secrets.DOGFOOD_API_TOKEN }}
|
||||
DOGFOOD_APPLE_BM_DEFAULT_TEAM: Workstations
|
||||
DOGFOOD_MACOS_MIGRATION_WEBHOOK_URL: ${{ secrets.DOGFOOD_MACOS_MIGRATION_WEBHOOK_URL }}
|
||||
DOGFOOD_GLOBAL_ENROLL_SECRET: ${{ secrets.DOGFOOD_GLOBAL_ENROLL_SECRET }}
|
||||
DOGFOOD_SSO_ISSUER_URI: ${{ secrets.DOGFOOD_SSO_ISSUER_URI }}
|
||||
DOGFOOD_SSO_METADATA: ${{ secrets.DOGFOOD_SSO_METADATA }}
|
||||
DOGFOOD_FAILING_POLICIES_WEBHOOK_URL: ${{ secrets.DOGFOOD_FAILING_POLICIES_WEBHOOK_URL }}
|
||||
DOGFOOD_VULNERABILITIES_WEBHOOK_URL: ${{ secrets.DOGFOOD_VULNERABILITIES_WEBHOOK_URL }}
|
||||
DOGFOOD_WORKSTATIONS_ENROLL_SECRET: ${{ secrets.DOGFOOD_WORKSTATIONS_ENROLL_SECRET }}
|
||||
DOGFOOD_WORKSTATIONS_CANARY_ENROLL_SECRET: ${{ secrets.DOGFOOD_WORKSTATIONS_CANARY_ENROLL_SECRET }}
|
||||
DOGFOOD_SERVERS_ENROLL_SECRET: ${{ secrets.DOGFOOD_SERVERS_ENROLL_SECRET }}
|
||||
DOGFOOD_SERVERS_CANARY_ENROLL_SECRET: ${{ secrets.DOGFOOD_SERVERS_CANARY_ENROLL_SECRET }}
|
||||
DOGFOOD_EXPLORE_DATA_ENROLL_SECRET: ${{ secrets.DOGFOOD_EXPLORE_DATA_ENROLL_SECRET }}
|
44
.github/workflows/example-workflow.yaml
vendored
44
.github/workflows/example-workflow.yaml
vendored
@ -1,44 +0,0 @@
|
||||
# This workflow applies the latest configuration profiles (macOS settings) and macOS updates minimum version and deadline to the provided team.
|
||||
name: Apply latest configuration profiles (example)
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "path/to/**.mobileconfig"
|
||||
workflow_dispatch: # Manual
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id}}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# fail-fast using bash -eo pipefail. See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FLEET_API_TOKEN: ${{ secrets.DOGFOOD_API_TOKEN }}
|
||||
FLEET_URL: ${{ secrets.DOGFOOD_URL }}
|
||||
TOKEN_USED_BY_PROFILE: ${{ secrets.TOKEN_USED_BY_PROFILE }}
|
||||
|
||||
jobs:
|
||||
apply-profiles:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply configuration profiles and updates
|
||||
uses: fleetdm/fleet-mdm-gitops@15072f2739ef92c6357414ddd86e89b6bf302a2b
|
||||
with:
|
||||
FLEET_API_TOKEN: $FLEET_API_TOKEN
|
||||
FLEET_URL: $FLEET_URL
|
||||
FLEET_TEAM_NAME: 💻🐣 Workstations (canary)
|
||||
MDM_CONFIG_REPO: fleetdm/fleet
|
||||
MDM_CONFIG_DIRECTORY: mdm_profiles
|
||||
MAC_OS_MIN_VERSION: 13.3.2
|
||||
MAC_OS_VERSION_DEADLINE: 2023-06-15
|
||||
MAC_OS_ENABLE_DISK_ENCRYPTION: true
|
@ -1,49 +0,0 @@
|
||||
# This workflow applies the latest configuration profiles (macOS settings) and macOS updates minimum version and deadline to the workstations (canary) team.
|
||||
# It uses a fleet instance also built and executed from source.
|
||||
#
|
||||
# It runs automatically when a file is changed in /mdm_profiles.
|
||||
name: Apply latest configuration profiles and macOS updates (Canary)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "mdm_profiles/**.mobileconfig"
|
||||
- ".github/workflows/fleetctl-workstations-canary.yml"
|
||||
workflow_dispatch: # Manual
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id}}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# fail-fast using bash -eo pipefail. See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
DOGFOOD_API_TOKEN: ${{ secrets.DOGFOOD_API_TOKEN }}
|
||||
DOGFOOD_URL: ${{ secrets.DOGFOOD_URL }}
|
||||
CLOUD_MANAGEMENT_ENROLLMENT_TOKEN: ${{ secrets.CLOUD_MANAGEMENT_ENROLLMENT_TOKEN }}
|
||||
|
||||
jobs:
|
||||
apply-profiles:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply configuration profiles and updates
|
||||
uses: fleetdm/fleet-mdm-gitops@15072f2739ef92c6357414ddd86e89b6bf302a2b # v1.1.0
|
||||
with:
|
||||
FLEET_API_TOKEN: $DOGFOOD_API_TOKEN
|
||||
FLEET_URL: $DOGFOOD_URL
|
||||
FLEET_TEAM_NAME: 💻🐣 Workstations (canary)
|
||||
MDM_CONFIG_REPO: fleetdm/fleet
|
||||
MDM_CONFIG_DIRECTORY: mdm_profiles
|
||||
MAC_OS_MIN_VERSION: "14.2"
|
||||
MAC_OS_VERSION_DEADLINE: 2023-12-15
|
||||
MAC_OS_ENABLE_DISK_ENCRYPTION: true
|
49
.github/workflows/fleetctl-workstations.yml
vendored
49
.github/workflows/fleetctl-workstations.yml
vendored
@ -1,49 +0,0 @@
|
||||
# This workflow applies the latest configuration profiles (macOS settings) and macOS updates minimum version and deadline to the workstations team.
|
||||
# It uses a Fleet instance also built and executed from source.
|
||||
#
|
||||
# It runs when the GitHub action is triggered manually
|
||||
name: Apply latest configuration profiles and macOS updates
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "mdm_profiles/**.mobileconfig"
|
||||
- ".github/workflows/fleetctl-workstations.yml"
|
||||
workflow_dispatch: # Manual
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id}}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# fail-fast using bash -eo pipefail. See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
DOGFOOD_API_TOKEN: ${{ secrets.DOGFOOD_API_TOKEN }}
|
||||
DOGFOOD_URL: ${{ secrets.DOGFOOD_URL }}
|
||||
CLOUD_MANAGEMENT_ENROLLMENT_TOKEN: ${{ secrets.CLOUD_MANAGEMENT_ENROLLMENT_TOKEN }}
|
||||
|
||||
jobs:
|
||||
apply-profiles:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply configuration profiles and updates
|
||||
uses: fleetdm/fleet-mdm-gitops@15072f2739ef92c6357414ddd86e89b6bf302a2b # v1.1.0
|
||||
with:
|
||||
FLEET_API_TOKEN: $DOGFOOD_API_TOKEN
|
||||
FLEET_URL: $DOGFOOD_URL
|
||||
FLEET_TEAM_NAME: 💻 Workstations
|
||||
MDM_CONFIG_REPO: fleetdm/fleet
|
||||
MDM_CONFIG_DIRECTORY: mdm_profiles
|
||||
MAC_OS_MIN_VERSION: "14.2"
|
||||
MAC_OS_VERSION_DEADLINE: 2023-12-19
|
||||
MAC_OS_ENABLE_DISK_ENCRYPTION: true
|
2
.github/workflows/test-puppet.yml
vendored
2
.github/workflows/test-puppet.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
- patch-*
|
||||
pull_request:
|
||||
paths:
|
||||
- 'ee/tools/puppet/fleetdm/*.*'
|
||||
- 'ee/tools/puppet/fleetdm/**'
|
||||
- '.github/workflows/test-puppet.yml'
|
||||
workflow_dispatch: # Manual
|
||||
|
||||
|
1
changes/17197-frequent-cleanups-enabled
Normal file
1
changes/17197-frequent-cleanups-enabled
Normal file
@ -0,0 +1 @@
|
||||
Added --server_frequent_cleanups_enabled (FLEET_SERVER_FREQUENT_CLEANUPS_ENABLED) flag to enable cron job to clean up stale data running every 15 minutes. Currently disabled by default.
|
1
changes/jve-16335
Normal file
1
changes/jve-16335
Normal file
@ -0,0 +1 @@
|
||||
- Enables usage of `<Add>` nodes in Windows MDM profiles.
|
@ -705,7 +705,6 @@ func newCleanupsAndAggregationSchedule(
|
||||
ctx context.Context,
|
||||
instanceID string,
|
||||
ds fleet.Datastore,
|
||||
lq fleet.LiveQueryStore,
|
||||
logger kitlog.Logger,
|
||||
enrollHostLimiter fleet.EnrollHostLimiter,
|
||||
config *config.FleetConfig,
|
||||
@ -721,6 +720,13 @@ func newCleanupsAndAggregationSchedule(
|
||||
schedule.WithAltLockID("leader"),
|
||||
schedule.WithLogger(kitlog.With(logger, "cron", name)),
|
||||
// Run cleanup jobs first.
|
||||
schedule.WithJob(
|
||||
"distributed_query_campaigns",
|
||||
func(ctx context.Context) error {
|
||||
_, err := ds.CleanupDistributedQueryCampaigns(ctx, time.Now().UTC())
|
||||
return err
|
||||
},
|
||||
),
|
||||
schedule.WithJob(
|
||||
"incoming_hosts",
|
||||
func(ctx context.Context) error {
|
||||
@ -846,16 +852,16 @@ func newFrequentCleanupsSchedule(
|
||||
s := schedule.New(
|
||||
ctx, name, instanceID, defaultInterval, ds, ds,
|
||||
// Using leader for the lock to be backwards compatilibity with old deployments.
|
||||
schedule.WithAltLockID("leader"),
|
||||
schedule.WithAltLockID("leader_frequent_cleanups"),
|
||||
schedule.WithLogger(kitlog.With(logger, "cron", name)),
|
||||
// Run cleanup jobs first.
|
||||
schedule.WithJob(
|
||||
"distributed_query_campaigns",
|
||||
"redis_live_queries",
|
||||
func(ctx context.Context) error {
|
||||
_, err := ds.CleanupDistributedQueryCampaigns(ctx, time.Now().UTC())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// It's necessary to avoid lingering live queries in case of:
|
||||
// - (Unknown) bug in the implementation, or,
|
||||
// - Redis is so overloaded already that the lq.StopQuery in svc.CompleteCampaign fails to execute, or,
|
||||
// - MySQL is so overloaded that ds.SaveDistributedQueryCampaign in svc.CompleteCampaign fails to execute.
|
||||
names, err := lq.LoadActiveQueryNames()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -865,10 +871,8 @@ func newFrequentCleanupsSchedule(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := lq.CleanupInactiveQueries(ctx, completed); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
err = lq.CleanupInactiveQueries(ctx, completed)
|
||||
return err
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@ -680,10 +680,14 @@ the way that the Fleet server works.
|
||||
}
|
||||
}()
|
||||
|
||||
if err := cronSchedules.StartCronSchedule(func() (fleet.CronSchedule, error) {
|
||||
return newFrequentCleanupsSchedule(ctx, instanceID, ds, liveQueryStore, logger)
|
||||
}); err != nil {
|
||||
initFatal(err, "failed to register frequent_cleanups schedule")
|
||||
if config.Server.FrequentCleanupsEnabled {
|
||||
if err := cronSchedules.StartCronSchedule(
|
||||
func() (fleet.CronSchedule, error) {
|
||||
return newFrequentCleanupsSchedule(ctx, instanceID, ds, liveQueryStore, logger)
|
||||
},
|
||||
); err != nil {
|
||||
initFatal(err, "failed to register frequent_cleanups schedule")
|
||||
}
|
||||
}
|
||||
|
||||
if err := cronSchedules.StartCronSchedule(
|
||||
@ -693,7 +697,7 @@ the way that the Fleet server works.
|
||||
commander = apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService)
|
||||
}
|
||||
return newCleanupsAndAggregationSchedule(
|
||||
ctx, instanceID, ds, liveQueryStore, logger, redisWrapperDS, &config, commander,
|
||||
ctx, instanceID, ds, logger, redisWrapperDS, &config, commander,
|
||||
)
|
||||
},
|
||||
); err != nil {
|
||||
|
@ -2155,9 +2155,9 @@ Returns the count of all hosts organized by status. `online_count` includes all
|
||||
|
||||
| Name | Type | In | Description |
|
||||
| --------------- | ------- | ---- | ------------------------------------------------------------------------------- |
|
||||
| team_id | integer | query | The ID of the team whose host counts should be included. Defaults to all teams. |
|
||||
| team_id | integer | query | _Available in Fleet Premium_. The ID of the team whose host counts should be included. Defaults to all teams. |
|
||||
| platform | string | query | Platform to filter by when counting. Defaults to all platforms. |
|
||||
| low_disk_space | integer | query | _Available in Fleet Premium_ Returns the count of hosts with less GB of disk space available than this value. Must be a number between 1-100. |
|
||||
| low_disk_space | integer | query | _Available in Fleet Premium_. Returns the count of hosts with less GB of disk space available than this value. Must be a number between 1-100. |
|
||||
|
||||
#### Example
|
||||
|
||||
@ -3464,11 +3464,10 @@ Retrieves the aggregated host OS versions information.
|
||||
|
||||
| Name | Type | In | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. If not provided, all hosts are included. |
|
||||
| team_id | integer | query | _Available in Fleet Premium_. Filters to only include OS versions for hosts on the specified team. If not provided, OS versions for all hosts are included. |
|
||||
| platform | string | query | Filters the hosts to the specified platform |
|
||||
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
|
||||
| os_version | string | query | The version of the operating system to filter hosts by. `os_name` must also be specified with `os_version` |
|
||||
| team_id | integer | query | _Available in Fleet Premium_. Filters to only include OS versions for the specified team. |
|
||||
| page | integer | query | Page number of the results to fetch. |
|
||||
| per_page | integer | query | Results per page. |
|
||||
| order_key | string | query | What to order results by. Allowed fields are: `hosts_count`. Default is `hosts_count` (descending). |
|
||||
@ -6268,7 +6267,7 @@ Returns a list of global queries or team queries.
|
||||
| --------------- | ------- | ----- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| order_key | string | query | What to order results by. Can be any column in the queries table. |
|
||||
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
|
||||
| team_id | integer | query | The ID of the parent team for the queries to be listed. When omitted, returns global queries. |
|
||||
| team_id | integer | query | _Available in Fleet Premium_. The ID of the parent team for the queries to be listed. When omitted, returns global queries. |
|
||||
| query | string | query | Search query keywords. Searchable fields include `name`. |
|
||||
|
||||
|
||||
@ -6589,7 +6588,7 @@ Creates a global query or team query.
|
||||
| query | string | body | **Required**. The query in SQL syntax. |
|
||||
| description | string | body | The query's description. |
|
||||
| observer_can_run | bool | body | Whether or not users with the `observer` role can run the query. In Fleet 4.0.0, 3 user roles were introduced (`admin`, `maintainer`, and `observer`). This field is only relevant for the `observer` role. The `observer_plus` role can run any query and is not limited by this flag (`observer_plus` role was added in Fleet 4.30.0). |
|
||||
| team_id | integer | body | The parent team to which the new query should be added. If omitted, the query will be global. |
|
||||
| team_id | integer | body | _Available in Fleet Premium_. The parent team to which the new query should be added. If omitted, the query will be global. |
|
||||
| interval | integer | body | The amount of time, in seconds, the query waits before running. Can be set to `0` to never run. Default: 0. |
|
||||
| platform | string | body | The OS platforms where this query will run (other platforms ignored). Comma-separated string. If omitted, runs on all compatible platforms. |
|
||||
| min_osquery_version | string | body | The minimum required osqueryd version installed on a host. If omitted, all osqueryd versions are acceptable. |
|
||||
@ -6732,7 +6731,7 @@ Deletes the query specified by name.
|
||||
| Name | Type | In | Description |
|
||||
| ---- | ---------- | ---- | ------------------------------------ |
|
||||
| name | string | path | **Required.** The name of the query. |
|
||||
| team_id | integer | body | The ID of the parent team of the query to be deleted. If omitted, Fleet will search among queries in the global context. |
|
||||
| team_id | integer | body | _Available in Fleet Premium_. The ID of the parent team of the query to be deleted. If omitted, Fleet will search among queries in the global context. |
|
||||
|
||||
#### Example
|
||||
|
||||
@ -7456,7 +7455,7 @@ Uploads a script, making it available to run on hosts assigned to the specified
|
||||
| Name | Type | In | Description |
|
||||
| ---- | ------- | ---- | -------------------------------------------- |
|
||||
| script | file | form | **Required**. The file containing the script. |
|
||||
| team_id | integer | form | The team ID. If specified, the script will only be available to hosts assigned to this team. If not specified, the script will only be available to hosts on **no team**. |
|
||||
| team_id | integer | form | _Available in Fleet Premium_. The team ID. If specified, the script will only be available to hosts assigned to this team. If not specified, the script will only be available to hosts on **no team**. |
|
||||
|
||||
#### Example
|
||||
|
||||
|
@ -8,15 +8,21 @@ Puppet::Reports.register_report(:fleetdm) do
|
||||
|
||||
def process
|
||||
return if noop
|
||||
client = Puppet::Util::FleetClient.instance
|
||||
|
||||
node_name = Puppet[:node_name_value]
|
||||
if resource_statuses.any? { |r| r.include?('error pre-setting fleetdm::profile') }
|
||||
Puppet.err("Some resources failed to be assigned, not matching profiles for #{node_name}")
|
||||
return
|
||||
end
|
||||
|
||||
client = Puppet::Util::FleetClient.instance
|
||||
run_identifier = "#{catalog_uuid}-#{node_name}"
|
||||
response = client.match_profiles(run_identifier, environment)
|
||||
|
||||
if response['error'].empty?
|
||||
Puppet.info("Successfully matched #{node_name} with a team containing configuration profiles")
|
||||
else
|
||||
Puppet.err("Error matching node #{node_name} with a team containing configuration profiles: #{response['error']}")
|
||||
return
|
||||
end
|
||||
|
||||
Puppet.err("Error matching node #{node_name} with a team containing configuration profiles: #{response['error']}")
|
||||
end
|
||||
end
|
||||
|
@ -47,13 +47,13 @@ define fleetdm::profile (
|
||||
$changed = $response['resource_changed']
|
||||
|
||||
if $err != '' {
|
||||
notify { "error pre-setting profile ${name} as ${ensure}: ${err}":
|
||||
notify { "error pre-setting fleetdm::profile ${name} as ${ensure}: ${err}":
|
||||
loglevel => 'err',
|
||||
}
|
||||
} elsif $changed {
|
||||
# NOTE: sending a notification also marks the
|
||||
# 'fleetdm::profile' as changed in the reports.
|
||||
notify { "successfully pre-set profile ${name} as ${ensure}": }
|
||||
notify { "successfully pre-set fleetdm::profile ${name} as ${ensure}": }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
64
ee/tools/puppet/fleetdm/spec/unit/reports/fleetdm_spec.rb
Normal file
64
ee/tools/puppet/fleetdm/spec/unit/reports/fleetdm_spec.rb
Normal file
@ -0,0 +1,64 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'puppet/reports'
|
||||
require_relative '../../../lib/puppet/reports/fleetdm.rb'
|
||||
|
||||
describe 'Puppet::Reports::Fleetdm' do
|
||||
let(:fleet_client_mock) { instance_double('Puppet::Util::FleetClient') }
|
||||
let(:catalog_uuid) { '827a74c8-cf98-44da-9ff7-18c5e4bee41e' }
|
||||
let(:node_name) { Puppet[:node_name_value] }
|
||||
let(:report) do
|
||||
report = Puppet::Transaction::Report.new('apply')
|
||||
report.extend(Puppet::Reports.report(:fleetdm))
|
||||
report
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
Puppet[:reports] = 'fleetdm'
|
||||
Puppet::Util::Log.level = :warning
|
||||
Puppet::Util::Log.newdestination(:console)
|
||||
|
||||
fleet_client_class = class_spy('Puppet::Util::FleetClient')
|
||||
stub_const('Puppet::Util::FleetClient', fleet_client_class)
|
||||
allow(fleet_client_class).to receive(:instance) { fleet_client_mock }
|
||||
allow(SecureRandom).to receive(:uuid).and_return(catalog_uuid)
|
||||
end
|
||||
|
||||
it 'does not process in noop mode' do
|
||||
allow(report).to receive(:noop).and_return(true)
|
||||
expect(fleet_client_mock).not_to receive(:match_profiles)
|
||||
report.process
|
||||
end
|
||||
|
||||
it 'logs an error if resources failed to be assigned' do
|
||||
allow(report).to receive(:resource_statuses).and_return({ 'myresource' => 'error pre-setting fleetdm::profile' })
|
||||
expect(Puppet).to receive(:err).with(%r{Some resources failed to be assigned})
|
||||
expect(fleet_client_mock).not_to receive(:match_profiles)
|
||||
report.process
|
||||
end
|
||||
|
||||
it 'successfully matches profiles when there are no errors' do
|
||||
allow(report).to receive(:noop).and_return(false)
|
||||
allow(report).to receive(:resource_statuses).and_return({})
|
||||
allow(fleet_client_mock).to receive(:match_profiles).and_return({ 'error' => '' })
|
||||
allow(report).to receive(:catalog_uuid).and_return(catalog_uuid)
|
||||
|
||||
expect(fleet_client_mock).to receive(:match_profiles).with("#{catalog_uuid}-#{node_name}", anything)
|
||||
expect(Puppet).to receive(:info).with("Successfully matched #{node_name} with a team containing configuration profiles")
|
||||
|
||||
report.process
|
||||
end
|
||||
|
||||
it 'logs an error when matching profiles fails' do
|
||||
allow(report).to receive(:noop).and_return(false)
|
||||
allow(report).to receive(:resource_statuses).and_return({})
|
||||
allow(fleet_client_mock).to receive(:match_profiles).and_return({ 'error' => 'Some error' })
|
||||
allow(report).to receive(:catalog_uuid).and_return(catalog_uuid)
|
||||
|
||||
expect(fleet_client_mock).to receive(:match_profiles).with("#{catalog_uuid}-#{node_name}", anything)
|
||||
expect(Puppet).to receive(:err).with("Error matching node #{node_name} with a team containing configuration profiles: Some error")
|
||||
|
||||
report.process
|
||||
end
|
||||
end
|
@ -147,6 +147,37 @@ When a Fleetie, consultant or advisor requests an update to their personnel deta
|
||||
- If required, BizOps also makes changes to other core systems (e.g: creating a new email alias in google workspace; updating details in Carta; etc).
|
||||
- The change is now actioned, notify the team member and close the issue.
|
||||
|
||||
|
||||
### Change a Fleetie's job title
|
||||
When BizOps receives notification of a Fleetie's job title changing, follow these steps to ensure accurate recording of the change across our systems.
|
||||
- Update the ["🧑🚀 Fleeties"](https://docs.google.com/spreadsheets/d/1OSLn-ZCbGSjPusHPiR5dwQhheH1K8-xqyZdsOe9y7qc/edit#gid=0) spreadsheet:
|
||||
- Search the spreadsheet for the Fleetie in need of a job title change.
|
||||
- Input the new job title in the Fleetie's row in the "Job title" cell.
|
||||
- Navigate to the "Org chart" tab of the spreadsheet, and verify that the Fleetie's title appears correctly in the org chart.
|
||||
- Update the relevant HRIS system.
|
||||
- For updating Gusto (US-based Fleeties):
|
||||
- Login to Gusto and navigate to "People > Team members".
|
||||
- Find the Fleetie and select them to see their profile page.
|
||||
- Under the "Compensation" heading, select edit and update the "Job title" and input the specific date the change happened. Save the changes.
|
||||
- For updating Plane (non-US Fleeties):
|
||||
- Login to Plane and navigate to "People > Team".
|
||||
- Find the Fleetie and select them to see their profile page.
|
||||
- Use the "Help" function, or email support@plane.com to notify Plane of the need to change the job title for the Fleetie. Include the Fleetie's name, current title, new title, and effective date.
|
||||
- Take any relevant steps as directed by Plane in order to make the required changes to the Fleetie's profile.
|
||||
|
||||
|
||||
### Change a Fleetie's manager
|
||||
When BizOps receives notification of a Fleetie's manager changing, follow these steps to ensure correct recording in our systems.
|
||||
- Update the [Fleeties](https://docs.google.com/spreadsheets/d/1OSLn-ZCbGSjPusHPiR5dwQhheH1K8-xqyZdsOe9y7qc/edit#gid=0).
|
||||
- Search for the Fleetie's new manager, and copy the new manager's unique ID from the far left "Unique ID" column.
|
||||
- Search for the Fleetie who's manager is changing, and paste (without formatting) their new manager's unique ID in the "Reports to: (manager unique ID)" cell in the Fleetie's row.
|
||||
- Verify that the "Reports to (auto: manager name and job title)" cell in the Fleetie's row reflects the new manager's details.
|
||||
- Verify that in the new manager's row, the "# direct reports" cell reflect the correct number.
|
||||
- Navigate to the "Org chart" tab in the spreadsheet, and verify that the Fleetie now appears in the correct place in the org chart.
|
||||
> **Note:** The Fleeties spreadsheet is the source of truth for this information, and any other systems reflecting reporting lines should be disregarded.
|
||||
|
||||
|
||||
|
||||
### Prepare salary benchmarking information
|
||||
- Use the relevant template text in the README section of the [¶¶ 💌 Compensation decisions document](https://docs.google.com/document/d/1NQ-IjcOTbyFluCWqsFLMfP4SvnopoXDcX0civ-STS5c/edit?usp=sharing) for a current Fleetie, a new role, a prospective hire, or other benchmarking use case.
|
||||
- Copy the template text and paste at the end of the document.
|
||||
|
@ -253,6 +253,7 @@ Labels with a `#g-` prefix refer to a kanban board. Since it is best practice to
|
||||
> - `bug-` Defect category. For example, `bug-enrollment`, `bug-profiles-sync`, `bug-policies`. This allows us to track the areas of the product producing the most bugs.
|
||||
> - `story` A user story.
|
||||
> - `prospect-` A customer prospect.
|
||||
> - `P-` A [priority level](https://fleetdm.com/handbook/company/product-groups#high-priority-user-stories-and-bugs).
|
||||
> - `Epic` Do not use. _(TODO: ZenHub automatically recreates this label when we group sub-tasks inside of a user story. Find a way to remove this. It is an artifact from Zenhub and not something we actually want to exist or use, as it is confusing.)_
|
||||
|
||||
### Process new requests
|
||||
|
@ -141,17 +141,6 @@ User stories are small and independently valuable.
|
||||
- Is it small enough? Will this task be likely to fit in 1 sprint when estimated?
|
||||
- Is it valuable enough? Will this task drive business value when released, independent of other tasks?
|
||||
|
||||
|
||||
#### Engineering-initiated stories
|
||||
<!-- TODO: Move steps to "Create an Engineering-initiated story" to handbook/engineering#responsibilities -->
|
||||
Engineering-initiated stories are types of user stories created by engineers to make technical changes to Fleet. Technical changes should improve the user experience or contributor experience. For example, optimizing SQL that improves the response time of an API endpoint improves user experience by reducing latency. A script that generates common boilerplate, or automated tests to cover important business logic, improves the quality of life for contributors, making them happier and more productive, resulting in faster delivery of features to our customers.
|
||||
|
||||
It is important to frame engineering-initiated user stories the same way we frame all user stories. Stay focused on how this technical change will drive value for our users.
|
||||
|
||||
To [create an engineering-initiated user story](https://fleetdm.com/handbook/engineering#creating-an-engineering-initiated-story), follow the [user story drafting process](https://fleetdm.com/handbook/company/development-groups#drafting). Once your user story is created using the [new story template](https://github.com/fleetdm/fleet/issues/new?assignees=&labels=story,~engineering-initiated&projects=&template=story.md&title=), add the `~engineering-initiated` label, assign it to yourself, and bring to your EM to be considered for future prioritization into a sprint. The engineering output and architecture DRI is responsible for prioritizing engineering-initiated stories.
|
||||
|
||||
> We prefer the term engineering-initiated stories over technical debt because the user story format helps keep us focused on our users.
|
||||
|
||||
#### Defining "done"
|
||||
To successfully deliver a user story, the people working on it need to know what "done" means.
|
||||
|
||||
@ -428,6 +417,28 @@ Fleet [always prioritizes bugs](https://fleetdm.com/handbook/product#prioritizin
|
||||
#### Awaiting QA
|
||||
Bugs will be verified as fixed by QA when they are placed in the "Awaiting QA" column of the relevant product group's sprint board. If the bug is verified as fixed, it is moved to the "Ready for release" column of the sprint board. Otherwise, the remaining issues are noted in a comment, and it is moved back to the "In progress" column of the sprint board.
|
||||
|
||||
## High priority user stories and bugs
|
||||
All issues are treated as standard priority by default. Some issues are assigned a priority label to indicate urgency for the business.
|
||||
|
||||
1. Emergency: `P0`
|
||||
- Examples: Customer outage, confirmed security vulnerability ([critical bug](https://fleetdm.com/handbook/company/product-groups#release-testing)), a new feature is needed to address an immediate business emergency.
|
||||
- Response: Immediately stop other work to swarm the issue. Work 24/7 in shifts until resolved.
|
||||
- Impact: Significant impact. May void current sprint.
|
||||
|
||||
2. Critical: `P1`
|
||||
- Examples: A supported workflow is broken ([critical bug](https://fleetdm.com/handbook/company/product-groups#release-testing)), a potential security vulnerability, a new feature is required to address an immediate critical business need.
|
||||
- Response: Issue brought to next standup for estimation and immediately brought into the sprint. Necessary team members are assigned as their top priority.
|
||||
- Impact: High impact. Does not void sprint, but reduces overall velocity and requires deprioritizing other work.
|
||||
|
||||
3. Urgent: `P2`
|
||||
- Examples: A supported workflow is not functioning as intended, a newly drafted feature has an associated urgent business need.
|
||||
- Response: Issue is prioritized at the top of the next sprint. If opporunity cost of waiting for the next sprint is too high, it may be considered for current sprint.
|
||||
- Impact: Low to medium impact. If prioritized into current sprint, may reduce overall velocity and require deprioritizing other work.
|
||||
|
||||
Add as much context as possible to the issue description and assign labels to help the team understand the problem and what is driving the urgency. All issues with a `P0`, `P1`, or `P2` label should be assigned to the [DRI for what goes in a release](https://fleetdm.com/handbook/company/communications#directly-responsible-individuals-dris). For immediate action, follow up on Slack or by phone.
|
||||
|
||||
Once the release DRI is aware of the issue, they will adjust the labels as needed and assign to the PM and EM of the appropriate product group. If they disagree with the priority label applied to the issue, they will contact the requestor to discuss further.
|
||||
|
||||
## How to reach the developer on-call
|
||||
Oncall engineers do not need to actively monitor Slack channels, except when called in by the Community or Customer teams. Members of those teams are instructed to `@oncall` in `#help-engineering` to get the attention of the on-call engineer to continue discussing any issues that come up. In some cases, the Community or Customer representative will continue to communicate with the requestor. In others, the on-call engineer will communicate directly (team members should use their judgment and discuss on a case-by-case basis how to best communicate with community members and customers).
|
||||
|
||||
@ -464,13 +475,11 @@ The on-call developer is encouraged to attend some of the customer success meeti
|
||||
|
||||
This has a dual purpose of providing more context for how our customers use Fleet. The developer should actively participate and provide input where appropriate (if not sure, please ask your manager or organizer of the call).
|
||||
|
||||
|
||||
- **Documentation for contributors**
|
||||
Fleet's documentation for contributors can be found in the [Fleet GitHub repo](https://github.com/fleetdm/fleet/tree/main/docs/Contributing).
|
||||
|
||||
The on-call developer is asked to read, understand, test, correct, and improve at least one doc page per week. Our goal is to 1, ensure accuracy and verify that our deployment guides and tutorials are up to date and work as expected. And 2, improve the readability, consistency, and simplicity of our documentation – with empathy towards first-time users. See [Writing documentation](https://fleetdm.com/handbook/marketing#writing-documentation) for writing guidelines, and don't hesitate to reach out to [#g-digital-experience](https://fleetdm.slack.com/archives/C01GQUZ91TN) on Slack for writing support. A backlog of documentation improvement needs is kept [here](https://github.com/fleetdm/fleet/issues?q=is%3Aopen+is%3Aissue+label%3A%22%3Aimprove+documentation%22).
|
||||
|
||||
|
||||
### Escalations
|
||||
When the on-call developer is unsure of the answer, they should follow this process for escalation.
|
||||
|
||||
@ -482,7 +491,6 @@ How to escalate:
|
||||
|
||||
2. Create a new thread in the [#help-engineering channel](https://fleetdm.slack.com/archives/C019WG4GH0A), tagging `@zwass` and provide the information turned up in your research. Please include possibly relevant links (even if you didn't find what you were looking for there). Zach will work with you to craft an appropriate answer or find another team member who can help.
|
||||
|
||||
|
||||
### Changing of the guard
|
||||
The on-call developer changes each week on Wednesday.
|
||||
|
||||
@ -509,8 +517,7 @@ In the Slack reminder thread, the on-call developer includes their retrospective
|
||||
|
||||
## Wireframes
|
||||
- Showing these principles and ideas, to help remember the pros and cons and conceptualize the above visually.
|
||||
|
||||
- Figma: [⚗️ Fleet product project](https://www.figma.com/files/project/17318630/%E2%9A%97%EF%B8%8F-Fleet-product?fuid=1234929285759903870)
|
||||
- Figma: [⚗️ Fleet product project](https://www.figma.com/files/project/17318630/%E2%9A%97%EF%B8%8F-Fleet-product?fuid=1234929285759903870)
|
||||
|
||||
We have certain design conventions that we include in Fleet. We will document more of these over time.
|
||||
|
||||
@ -581,22 +588,6 @@ OPTIONS
|
||||
|
||||
## Meetings
|
||||
|
||||
<!-- TODO: Find out what to do with this stuff. Delete?
|
||||
### Eng Together
|
||||
This meeting is to disseminate engineering-wide announcements, promote cohesion across groups within the engineering team, and connect with engineers (and the "engineering-curious") in other departments. Held monthly for one hour.
|
||||
|
||||
**Participants:** Everyone at the company is welcome to attend. All engineers are asked to attend. The subject matter is focused on engineering.
|
||||
|
||||
**Agenda:**
|
||||
- Announcements
|
||||
- Engineering KPIs review
|
||||
- “Tech talks”
|
||||
- At least one engineer from each product group demos or discusses a technical aspect of their recent work.
|
||||
- Everyone is welcome to present on a technical topic. Add your name and tech talk subject in the agenda doc included in the Eng Together calendar event.
|
||||
- Social
|
||||
- Structured and/or unstructured social activities
|
||||
|
||||
|
||||
### User story discovery
|
||||
User story discovery meetings are scheduled as needed to align on large or complicated user stories. Before a discovery meeting is scheduled, the user story must be prioritized for product drafting and go through the design and specification process. When the user story is ready to be estimated, a user story discovery meeting may be scheduled to provide more dedicated, synchronous time for the team to discuss the user story than is available during weekly estimation sessions.
|
||||
|
||||
@ -617,18 +608,6 @@ All participants are expected to review the user story and associated designs an
|
||||
- Software Engineers: Clarifying questions and implementation details
|
||||
- Product Quality Specialist: Testing plan
|
||||
|
||||
|
||||
### Group weeklies
|
||||
A chance for deeper, synchronous discussion on topics relevant across product groups like “Frontend weekly”, “Backend weekly”, etc.
|
||||
|
||||
**Participants:** Anyone who wishes to participate.
|
||||
|
||||
**Sample agenda (Frontend weekly)**
|
||||
- Discuss common patterns and conventions in the codebase
|
||||
- Review difficult frontend bugs
|
||||
- Write engineering-initiated stories
|
||||
-->
|
||||
|
||||
### Design consultation
|
||||
Design consultations are scheduled as needed with the relevant participants, typically product designers and frontend engineers. It is an opportunity to collaborate and discuss design, implementation, and story requirements. The meeting is scheduled as needed by the product designer or frontend engineer when a user story is in the "Prioritized" column on the [drafting board](https://app.zenhub.com/workspaces/-drafting-ships-in-6-weeks-6192dd66ea2562000faea25c/board).
|
||||
|
||||
@ -662,6 +641,30 @@ QA has weekly check-in with product to go over the inbox items. QA is responsibl
|
||||
|
||||
QA may also propose that a reported bug is not actually a bug. A bug is defined as “behavior that is not according to spec or implied by spec.” If agreed that it is not a bug, then it's assigned to the relevant product manager to determine its priority.
|
||||
|
||||
### Group weeklies
|
||||
A chance for deeper, synchronous discussion on topics relevant across product groups like “Frontend weekly”, “Backend weekly”, etc.
|
||||
|
||||
**Participants:** Anyone who wishes to participate.
|
||||
|
||||
**Sample agenda from frontend weekly**
|
||||
- Discuss common patterns and conventions in the codebase
|
||||
- Review difficult frontend bugs
|
||||
- Write engineering-initiated stories
|
||||
|
||||
### Eng Together
|
||||
This meeting is to disseminate engineering-wide announcements, promote cohesion across groups within the engineering team, and connect with engineers (and the "engineering-curious") in other departments. Held monthly for one hour.
|
||||
|
||||
**Participants:** Everyone at the company is welcome to attend. All engineers are asked to attend. The subject matter is focused on engineering.
|
||||
|
||||
**Agenda:**
|
||||
- Announcements
|
||||
- Engineering KPIs review
|
||||
- “Tech talks”
|
||||
- At least one member from each product group demos or discusses a technical subject relevant to engineering at Fleet.
|
||||
- Everyone is welcome to present on a technical topic. Add your name and tech talk subject in the agenda doc included in the Eng Together calendar event.
|
||||
- Social
|
||||
- Structured and/or unstructured social activities
|
||||
|
||||
## Development best practices
|
||||
- Remember the user. What would you do if you saw that error message? [🔴](https://fleetdm.com/handbook/company#empathy)
|
||||
- Communicate any blockers ASAP in your group Slack channel or standup. [🟠](https://fleetdm.com/handbook/company#ownership)
|
||||
|
@ -27,6 +27,15 @@ The metrics are:
|
||||
|
||||
Each week these are tracked and shared in the weekly KPI sheet by Luke Heath.
|
||||
|
||||
#### Create an engineering-initiated story
|
||||
Engineering-initiated stories are types of user stories created by engineers to make technical changes to Fleet. Technical changes should improve the user experience or contributor experience. For example, optimizing SQL that improves the response time of an API endpoint improves user experience by reducing latency. A script that generates common boilerplate, or automated tests to cover important business logic, improves the quality of life for contributors, making them happier and more productive, resulting in faster delivery of features to our customers.
|
||||
|
||||
It is important to frame engineering-initiated user stories the same way we frame all user stories. Stay focused on how this technical change will drive value for our users.
|
||||
|
||||
To [create an engineering-initiated user story](https://fleetdm.com/handbook/engineering#creating-an-engineering-initiated-story), follow the [user story drafting process](https://fleetdm.com/handbook/company/development-groups#drafting). Once your user story is created using the [new story template](https://github.com/fleetdm/fleet/issues/new?assignees=&labels=story,~engineering-initiated&projects=&template=story.md&title=), add the `~engineering-initiated` label, assign it to yourself, and bring to your EM to be considered for future prioritization into a sprint. The engineering output and architecture DRI is responsible for prioritizing engineering-initiated stories.
|
||||
|
||||
> We prefer the term engineering-initiated stories over technical debt because the user story format helps keep us focused on our users and contributors.
|
||||
|
||||
### Begin a merge freeze
|
||||
To ensure release quality, Fleet has a freeze period for testing beginning the Tuesday before the release at 9:00 AM Pacific. Effective at the start of the freeze period, new feature work will not be merged into `main`.
|
||||
|
||||
@ -180,7 +189,6 @@ When merging a pull request from a community contributor:
|
||||
- Thank and congratulate the contributor.
|
||||
- Share the merged PR with the team in the #help-promote channel of Fleet Slack to be publicized on social media. Those who contribute to Fleet and are recognized for their contributions often become great champions for the project.
|
||||
|
||||
|
||||
### Schedule developer on-call workload
|
||||
Engineering managers are asked to be aware of the [on-call rotation](https://docs.google.com/document/d/1FNQdu23wc1S9Yo6x5k04uxT2RwT77CIMzLLeEI2U7JA/edit#) and schedule a light workload for engineers while they are on-call. While it varies week to week considerably, the on-call responsibilities can sometimes take up a substantial portion of the engineer's time.
|
||||
|
||||
@ -334,40 +342,40 @@ Please see [handbook/engineering#notify-community-members-about-a-critical-bug](
|
||||
Please see [handbook/engineering#run-fleet-locally-for-qa-purposes](https://fleetdm.com/handbook/engineering#run-fleet-localy-for-qa-purposes)
|
||||
|
||||
##### Scrum at Fleet
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#scrum-at-fleet)
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#scrum-at-fleet)
|
||||
|
||||
##### Scrum items
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#scrum-items)
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#scrum-items)
|
||||
|
||||
##### Sprint ceremonies
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#sprint-ceremonies)
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#sprint-ceremonies)
|
||||
|
||||
##### Meetings
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#meetings)
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#meetings)
|
||||
|
||||
##### Principles
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#principles)
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#principles)
|
||||
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#eng-together) for **below**
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#eng-together) for **below**
|
||||
##### Eng Together
|
||||
##### Participants
|
||||
##### Agenda
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#eng-together) for **above**
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#eng-together) for **above**
|
||||
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **below**
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **below**
|
||||
##### User story discovery
|
||||
##### Participants
|
||||
##### Agenda
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **above**
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **above**
|
||||
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **below**
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **below**
|
||||
##### Group weeklies
|
||||
##### Participants
|
||||
##### Sample agenda (Frontend weekly)
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **above**
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/product-groups#group-weeklies) for **above**
|
||||
|
||||
##### Engineering-initiated stories
|
||||
Please see [handbook/company/product-groups#engineering-initiated-stories](https://fleetdm.com/handbook/company/product-groups#engineering-initiated-stories)
|
||||
Please see [handbook/company/engineering#create-an-engineering-initiated-story](https://fleetdm.com/handbook/company/engineering#create-an-engineering-initiated-story)
|
||||
|
||||
##### Creating an engineering-initiated story
|
||||
Please see [handbook/engineering#create-an-engineering-initiated-user-story](https://fleetdm.com/handbook/engineering#create-an-engineering-initiated-user-story)
|
||||
|
86
it-and-security/default.yml
Normal file
86
it-and-security/default.yml
Normal file
@ -0,0 +1,86 @@
|
||||
agent_options:
|
||||
path: ./lib/agent-options.yml
|
||||
controls:
|
||||
enable_disk_encryption: true
|
||||
macos_migration:
|
||||
enable: true
|
||||
mode: voluntary
|
||||
webhook_url: $DOGFOOD_MACOS_MIGRATION_WEBHOOK_URL
|
||||
macos_settings:
|
||||
custom_settings: null
|
||||
macos_setup:
|
||||
bootstrap_package: ""
|
||||
enable_end_user_authentication: false
|
||||
macos_setup_assistant: null
|
||||
macos_updates:
|
||||
deadline: "2023-06-13"
|
||||
minimum_version: 13.4.1
|
||||
windows_enabled_and_configured: true
|
||||
windows_settings:
|
||||
custom_settings: []
|
||||
windows_updates:
|
||||
deadline_days: 3
|
||||
grace_period_days: 2
|
||||
scripts: []
|
||||
org_settings:
|
||||
features:
|
||||
enable_host_users: true
|
||||
enable_software_inventory: true
|
||||
fleet_desktop:
|
||||
transparency_url: https://fleetdm.com/transparency
|
||||
host_expiry_settings:
|
||||
host_expiry_enabled: false
|
||||
host_expiry_window: 7
|
||||
integrations:
|
||||
jira: [ ]
|
||||
zendesk: [ ]
|
||||
mdm:
|
||||
apple_bm_default_team: $DOGFOOD_APPLE_BM_DEFAULT_TEAM
|
||||
org_info:
|
||||
contact_url: https://fleetdm.com/company/contact
|
||||
org_logo_url: ""
|
||||
org_logo_url_light_background: ""
|
||||
org_name: Fleet Device Management
|
||||
secrets:
|
||||
- secret: $DOGFOOD_GLOBAL_ENROLL_SECRET
|
||||
server_settings:
|
||||
debug_host_ids:
|
||||
- 1
|
||||
- 3
|
||||
deferred_save_host: false
|
||||
enable_analytics: true
|
||||
live_query_disabled: false
|
||||
query_reports_disabled: false
|
||||
scripts_disabled: false
|
||||
server_url: https://dogfood.fleetdm.com
|
||||
sso_settings:
|
||||
enable_jit_provisioning: true
|
||||
enable_jit_role_sync: false
|
||||
enable_sso: true
|
||||
enable_sso_idp_login: false
|
||||
entity_id: dogfood.fleetdm.com
|
||||
idp_image_url: ""
|
||||
idp_name: Google
|
||||
issuer_uri: $DOGFOOD_SSO_ISSUER_URI
|
||||
metadata: |-
|
||||
$DOGFOOD_SSO_METADATA
|
||||
metadata_url: ""
|
||||
webhook_settings:
|
||||
failing_policies_webhook:
|
||||
destination_url: $DOGFOOD_FAILING_POLICIES_WEBHOOK_URL
|
||||
enable_failing_policies_webhook: true
|
||||
host_batch_size: 0
|
||||
policy_ids: []
|
||||
host_status_webhook:
|
||||
days_count: 1
|
||||
destination_url: ""
|
||||
enable_host_status_webhook: false
|
||||
host_percentage: 25
|
||||
interval: 1m0s
|
||||
vulnerabilities_webhook:
|
||||
destination_url: $DOGFOOD_VULNERABILITIES_WEBHOOK_URL
|
||||
enable_vulnerabilities_webhook: true
|
||||
host_batch_size: 0
|
||||
policies:
|
||||
queries:
|
||||
- path: ./lib/collect-fleetd-update-channels.queries.yml
|
13
it-and-security/lib/agent-options.yml
Normal file
13
it-and-security/lib/agent-options.yml
Normal file
@ -0,0 +1,13 @@
|
||||
config:
|
||||
decorators:
|
||||
load:
|
||||
- SELECT uuid AS host_uuid FROM system_info;
|
||||
- SELECT hostname AS hostname FROM system_info;
|
||||
options:
|
||||
disable_distributed: false
|
||||
distributed_interval: 10
|
||||
distributed_plugin: tls
|
||||
distributed_tls_max_attempts: 3
|
||||
logger_tls_endpoint: /api/osquery/log
|
||||
logger_tls_period: 10
|
||||
pack_delimiter: /
|
@ -0,0 +1,14 @@
|
||||
- name: Collect failed login attempts
|
||||
automations_enabled: true
|
||||
description: Lists the users at least one failed login attempt and timestamp of
|
||||
failed login. Number of failed login attempts reset to zero after a user successfully
|
||||
logs in.
|
||||
discard_data: false
|
||||
interval: 300
|
||||
logging: snapshot
|
||||
min_osquery_version: ""
|
||||
observer_can_run: false
|
||||
platform: ""
|
||||
query: SELECT users.username, account_policy_data.failed_login_count, account_policy_data.failed_login_timestamp
|
||||
FROM users INNER JOIN account_policy_data using (uid) WHERE account_policy_data.failed_login_count
|
||||
> 0;
|
7
it-and-security/lib/collect-fleetd-logs.sh
Normal file
7
it-and-security/lib/collect-fleetd-logs.sh
Normal file
@ -0,0 +1,7 @@
|
||||
cp /var/log/orbit/orbit.stderr.log ~/Library/Logs/Fleet/fleet-desktop.log /Users/Shared
|
||||
|
||||
echo "Successfully copied fleetd logs to the /Users/Shared folder."
|
||||
|
||||
echo "To retrieve logs, ask the end user to open Finder and in the menu bar select Go > Go to Folder."
|
||||
|
||||
echo "Then, ask the end user to type in /Users/Shared, press Return, and locate orbit.stderr.log (Orbit logs) and fleet-desktop.log (Fleet Desktop logs) files."
|
@ -0,0 +1,7 @@
|
||||
- name: Collect fleetd update channels
|
||||
description: "Collects the update channels for all fleetd components: osquery, Orbit, and Fleet Desktop. To see which version number each channel is on, ask in #help-engineering."
|
||||
query: SELECT desktop_channel, orbit_channel, osqueryd_channel FROM orbit_info;
|
||||
interval: 300 # 5 minutes
|
||||
observer_can_run: true
|
||||
automations_enabled: false
|
||||
platform: darwin,linux,windows
|
10
it-and-security/lib/collect-usb-devices.queries.yml
Normal file
10
it-and-security/lib/collect-usb-devices.queries.yml
Normal file
@ -0,0 +1,10 @@
|
||||
- name: Collect USB devices
|
||||
automations_enabled: false
|
||||
description: Collects the USB devices that are currently connected to macOS and Linux hosts.
|
||||
discard_data: false
|
||||
interval: 300
|
||||
logging: snapshot
|
||||
min_osquery_version: ""
|
||||
observer_can_run: true
|
||||
platform: ""
|
||||
query: SELECT model, vendor FROM usb_devices;
|
12
it-and-security/lib/collect-vs-code-extensions.queries.yml
Normal file
12
it-and-security/lib/collect-vs-code-extensions.queries.yml
Normal file
@ -0,0 +1,12 @@
|
||||
- name: Collect Visual Studio (VS) Code extensions
|
||||
automations_enabled: false
|
||||
description: Collects the name, publisher, and version of the VS Code extensions
|
||||
installed on hosts.
|
||||
discard_data: false
|
||||
interval: 3600
|
||||
logging: snapshot
|
||||
min_osquery_version: ""
|
||||
observer_can_run: false
|
||||
platform: ""
|
||||
query: SELECT extension.name, extension.publisher, extension.version FROM users
|
||||
JOIN vscode_extensions extension USING (uid);
|
3210
it-and-security/lib/explore-data.queries.yml
Normal file
3210
it-and-security/lib/explore-data.queries.yml
Normal file
File diff suppressed because it is too large
Load Diff
6
it-and-security/lib/linux-device-health.policies.yml
Normal file
6
it-and-security/lib/linux-device-health.policies.yml
Normal file
@ -0,0 +1,6 @@
|
||||
- name: Linux - Enable disk encryption
|
||||
query: SELECT 1 FROM disk_encryption WHERE encrypted=1 AND name LIKE '/dev/dm-1';
|
||||
critical: false
|
||||
description: This policy checks if disk encryption is enabled.
|
||||
resolution: As an IT admin, deploy an image that includes disk encryption.
|
||||
platform: linux
|
55
it-and-security/lib/macos-device-health.policies.yml
Normal file
55
it-and-security/lib/macos-device-health.policies.yml
Normal file
@ -0,0 +1,55 @@
|
||||
- name: macOS - Enable FileVault
|
||||
query: SELECT 1 FROM filevault_status WHERE status = 'FileVault is On.';
|
||||
critical: false
|
||||
description: This policy checks if FileVault (disk encryption) is enabled.
|
||||
resolution: As an IT admin, turn on disk encryption in Fleet.
|
||||
platform: darwin
|
||||
- name: macOS - Enable Firewall
|
||||
query: SELECT 1 FROM managed_policies WHERE domain='com.apple.security.firewall' AND username = '' AND name='EnableFirewall' AND CAST(value AS INT) = 1;
|
||||
critical: false
|
||||
description: This policy checks if Firewall is enabled.
|
||||
resolution: An an IT admin, deploy a macOS, Firewall profile with the EnableFirewall option set to true.
|
||||
platform: darwin
|
||||
- name: macOS - Disable guest account
|
||||
query: SELECT 1 FROM managed_policies WHERE domain='com.apple.loginwindow' AND username = '' AND name='DisableGuestAccount' AND CAST(value AS INT) = 1;
|
||||
critical: false
|
||||
description: This policy checks if the guest account is disabled.
|
||||
resolution: An an IT admin, deploy a macOS, login window profile with the DisableGuestAccount option set to true.
|
||||
platform: darwin
|
||||
- name: macOS - Require 10 character password
|
||||
query: SELECT 1 WHERE
|
||||
EXISTS (
|
||||
SELECT 1 FROM managed_policies WHERE
|
||||
domain='com.apple.screensaver' AND
|
||||
name='askForPassword' AND
|
||||
CAST(value AS INT)
|
||||
)
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM managed_policies WHERE
|
||||
domain='com.apple.screensaver' AND
|
||||
name='minLength' AND
|
||||
CAST(value AS INT) <= 10
|
||||
);
|
||||
critical: false
|
||||
description: This policy checks if the end user is required to enter a password, with at least 10 characters, to unlock the host.
|
||||
resolution: An an IT admin, deploy a macOS, screensaver profile with the askForPassword option set to true and minLength option set to 10.
|
||||
platform: darwin
|
||||
- name: macOS - Enable screen saver after 20 minutes
|
||||
query: SELECT 1 WHERE
|
||||
EXISTS (
|
||||
SELECT 1 FROM managed_policies WHERE
|
||||
domain='com.apple.screensaver' AND
|
||||
name='idleTime' AND
|
||||
CAST(value AS INT) <= 1200 AND
|
||||
username = ''
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM managed_policies WHERE
|
||||
domain='com.apple.screensaver' AND
|
||||
name='idleTime' AND
|
||||
CAST(value AS INT) > 1200
|
||||
);
|
||||
critical: false
|
||||
description: This policy checks if maximum amount of time (in minutes) the device is allowed to sit idle before the screen is locked. End users can select any value less than the specified maximum.
|
||||
resolution: An an IT admin, deploy a macOS, screen saver profile with the maxInactivity option set to 20 minutes.
|
||||
platform: darwin
|
@ -0,0 +1 @@
|
||||
profiles show -type enrollment
|
13
it-and-security/lib/servers.agent-options.yml
Normal file
13
it-and-security/lib/servers.agent-options.yml
Normal file
@ -0,0 +1,13 @@
|
||||
config:
|
||||
decorators:
|
||||
load:
|
||||
- SELECT uuid AS host_uuid FROM system_info;
|
||||
- SELECT hostname AS hostname FROM system_info;
|
||||
options:
|
||||
disable_distributed: false
|
||||
distributed_interval: 10
|
||||
distributed_plugin: tls
|
||||
distributed_tls_max_attempts: 3
|
||||
logger_tls_endpoint: /api/osquery/log
|
||||
logger_tls_period: 10
|
||||
pack_delimiter: /
|
24
it-and-security/lib/windows-device-health.policies.yml
Normal file
24
it-and-security/lib/windows-device-health.policies.yml
Normal file
@ -0,0 +1,24 @@
|
||||
- name: Windows - Enable screen saver after 20 minutes
|
||||
query: SELECT 1 FROM mdm_bridge where mdm_command_input = "<SyncBody><Get><CmdID>1</CmdID><Item><Target><LocURI>./Device/Vendor/MSFT/Policy/Result/DeviceLock/MaxInactivityTimeDeviceLock</LocURI></Target></Item></Get></SyncBody>" and CAST(mdm_command_output AS INT) <= 20;
|
||||
critical: false
|
||||
description: This policy checks if maximum amount of time (in minutes) the device is allowed to sit idle before the screen is locked. End users can select any value less than the specified maximum.
|
||||
resolution: "As an IT admin, to deploy a Windows profile with the MaxInactivityTimeDeviceLock option documented here: https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-devicelock#maxinactivitytimedevicelock"
|
||||
platform: windows
|
||||
- name: Windows - Enable BitLocker
|
||||
query: SELECT * FROM bitlocker_info WHERE drive_letter='C:' AND protection_status = 1;
|
||||
critical: false
|
||||
description: As an IT admin, turn on disk encryption in Fleet.
|
||||
resolution: Ask your system administrator to turn on disk encryption in Fleet
|
||||
platform: windows
|
||||
- name: Windows - Disable guest account
|
||||
query: SELECT 1 FROM mdm_bridge where mdm_command_input = "<SyncBody><Get><CmdID>1</CmdID><Item><Target><LocURI>./Device/Vendor/MSFT/Policy/Result/LocalPoliciesSecurityOptions/Accounts_EnableGuestAccountStatus</LocURI></Target></Item></Get></SyncBody>" and CAST(mdm_command_output AS INT) = 0;
|
||||
critical: false
|
||||
description: This policy checks if the guest account is disabled. The Guest account allows unauthenticated network users to gain access to the system.
|
||||
resolution: "As an IT admin, deploy a Windows profile with the Accounts_EnableGuestAccountStatus option documented here: https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-localpoliciessecurityoptions#accounts_enableguestaccountstatus"
|
||||
platform: windows
|
||||
- name: Windows - Require 10 character password
|
||||
query: SELECT 1 FROM mdm_bridge where mdm_command_input = "<SyncBody><Get><CmdID>1</CmdID><Item><Target><LocURI>./Device/Vendor/MSFT/Policy/Result/DeviceLock/DevicePasswordEnabled</LocURI></Target></Item></Get></SyncBody>" and CAST(mdm_command_output AS INT) = 0;
|
||||
critical: false
|
||||
description: This policy checks if the end user is required to enter a password, with at least 10 characters, to unlock the host.
|
||||
resolution: "As an IT admin, deploy a Windows profile with the DevicePasswordEnabled and MinDevicePasswordLength option documented here: https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-devicelock"
|
||||
platform: windows
|
110
it-and-security/lib/windows-remove-fleetd.ps1
Normal file
110
it-and-security/lib/windows-remove-fleetd.ps1
Normal file
@ -0,0 +1,110 @@
|
||||
function Test-Administrator
|
||||
{
|
||||
[OutputType([bool])]
|
||||
param()
|
||||
process {
|
||||
[Security.Principal.WindowsPrincipal]$user = [Security.Principal.WindowsIdentity]::GetCurrent();
|
||||
return $user.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator);
|
||||
}
|
||||
}
|
||||
|
||||
# borrowed from Jeffrey Snover http://blogs.msdn.com/powershell/archive/2006/12/07/resolve-error.aspx
|
||||
function Resolve-Error-Detailed($ErrorRecord = $Error[0]) {
|
||||
$error_message = "========== ErrorRecord:{0}ErrorRecord.InvocationInfo:{1}Exception:{2}"
|
||||
$formatted_errorRecord = $ErrorRecord | format-list * -force | out-string
|
||||
$formatted_invocationInfo = $ErrorRecord.InvocationInfo | format-list * -force | out-string
|
||||
$formatted_exception = ""
|
||||
$Exception = $ErrorRecord.Exception
|
||||
for ($i = 0; $Exception; $i++, ($Exception = $Exception.InnerException)) {
|
||||
$formatted_exception += ("$i" * 70) + "-----"
|
||||
$formatted_exception += $Exception | format-list * -force | out-string
|
||||
$formatted_exception += "-----"
|
||||
}
|
||||
|
||||
return $error_message -f $formatted_errorRecord, $formatted_invocationInfo, $formatted_exception
|
||||
}
|
||||
|
||||
#Stops Orbit service and related processes
|
||||
function Stop-Orbit {
|
||||
|
||||
# Stop Service
|
||||
Stop-Service -Name "Fleet osquery" -ErrorAction "Continue"
|
||||
Start-Sleep -Milliseconds 1000
|
||||
|
||||
# Ensure that no process left running
|
||||
Get-Process -Name "orbit" -ErrorAction "SilentlyContinue" | Stop-Process -Force
|
||||
Get-Process -Name "osqueryd" -ErrorAction "SilentlyContinue" | Stop-Process -Force
|
||||
Get-Process -Name "fleet-desktop" -ErrorAction "SilentlyContinue" | Stop-Process -Force
|
||||
Start-Sleep -Milliseconds 1000
|
||||
}
|
||||
|
||||
#Remove Orbit footprint from registry and disk
|
||||
function Force-Remove-Orbit {
|
||||
|
||||
try {
|
||||
|
||||
#Stoping Orbit
|
||||
Stop-Orbit
|
||||
|
||||
#Remove Service
|
||||
$service = Get-WmiObject -Class Win32_Service -Filter "Name='Fleet osquery'"
|
||||
if ($service) {
|
||||
$service.delete() | Out-Null
|
||||
}
|
||||
|
||||
#Removing Program files entries
|
||||
$targetPath = $Env:Programfiles + "\\Orbit"
|
||||
Remove-Item -LiteralPath $targetPath -Force -Recurse -ErrorAction "Continue"
|
||||
|
||||
#Remove HKLM registry entries
|
||||
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" -Recurse -ErrorAction "SilentlyContinue" | Where-Object {($_.ValueCount -gt 0)} | ForEach-Object {
|
||||
|
||||
# Filter for osquery entries
|
||||
$properties = Get-ItemProperty $_.PSPath -ErrorAction "SilentlyContinue" | Where-Object {($_.DisplayName -eq "Fleet osquery")}
|
||||
if ($properties) {
|
||||
|
||||
#Remove Registry Entries
|
||||
$regKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" + $_.PSChildName
|
||||
|
||||
Get-Item $regKey -ErrorAction "SilentlyContinue" | Remove-Item -Force -ErrorAction "SilentlyContinue"
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host "There was a problem running Force-Remove-Orbit"
|
||||
Write-Host "$(Resolve-Error-Detailed)"
|
||||
return $false
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function Main {
|
||||
|
||||
try {
|
||||
# Is Administrator check
|
||||
if (-not (Test-Administrator)) {
|
||||
Write-Host "Please run this script with adming privileges."
|
||||
Exit -1
|
||||
}
|
||||
|
||||
Write-Host "About to uninstall fleetd..."
|
||||
|
||||
if (Force-Remove-Orbit) {
|
||||
Write-Host "fleetd was uninstalled."
|
||||
Exit 0
|
||||
} else {
|
||||
Write-Host "There was a problem uninstalling fleetd."
|
||||
Exit -1
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Host "Errorr: Entry point"
|
||||
Write-Host "$(Resolve-Error-Detailed)"
|
||||
Exit -1
|
||||
}
|
||||
}
|
||||
|
||||
$null = Main
|
27
it-and-security/lib/windows-turn-off-mdm.ps1
Normal file
27
it-and-security/lib/windows-turn-off-mdm.ps1
Normal file
@ -0,0 +1,27 @@
|
||||
Add-Type -TypeDefinition @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class MdmRegistration
|
||||
{
|
||||
[DllImport("mdmregistration.dll", SetLastError = true)]
|
||||
public static extern int UnregisterDeviceWithManagement(IntPtr pDeviceID);
|
||||
|
||||
public static int UnregisterDevice()
|
||||
{
|
||||
return UnregisterDeviceWithManagement(IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
"@ -Language CSharp
|
||||
|
||||
try {
|
||||
$result = [MdmRegistration]::UnregisterDevice()
|
||||
|
||||
if ($result -ne 0) {
|
||||
throw "UnregisterDeviceWithManagement failed with error code: $result"
|
||||
}
|
||||
|
||||
Write-Host "Device unregistration called successfully."
|
||||
} catch {
|
||||
Write-Error "Error calling UnregisterDeviceWithManagement: $_"
|
||||
}
|
43
it-and-security/teams/explore-data.yml
Normal file
43
it-and-security/teams/explore-data.yml
Normal file
@ -0,0 +1,43 @@
|
||||
name: "Explore data (fleetdm.com) [DO NOT DELETE]"
|
||||
team_settings:
|
||||
features:
|
||||
enable_host_users: true
|
||||
enable_software_inventory: true
|
||||
host_expiry_settings:
|
||||
host_expiry_enabled: false
|
||||
host_expiry_window: 0
|
||||
secrets:
|
||||
- secret: $DOGFOOD_EXPLORE_DATA_ENROLL_SECRET
|
||||
agent_options:
|
||||
config:
|
||||
decorators:
|
||||
load:
|
||||
- SELECT uuid AS host_uuid FROM system_info;
|
||||
- SELECT hostname AS hostname FROM system_info;
|
||||
options:
|
||||
disable_distributed: false
|
||||
distributed_interval: 5
|
||||
distributed_plugin: tls
|
||||
distributed_tls_max_attempts: 3
|
||||
logger_tls_endpoint: /api/v1/osquery/log
|
||||
pack_delimiter: /
|
||||
controls:
|
||||
enable_disk_encryption: false
|
||||
macos_settings:
|
||||
custom_settings:
|
||||
macos_setup:
|
||||
bootstrap_package: null
|
||||
enable_end_user_authentication: false
|
||||
macos_setup_assistant: null
|
||||
macos_updates:
|
||||
deadline: null
|
||||
minimum_version: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
windows_updates:
|
||||
deadline_days: null
|
||||
grace_period_days: null
|
||||
scripts:
|
||||
policies:
|
||||
queries:
|
||||
- path: ../lib/explore-data.queries.yml
|
31
it-and-security/teams/servers-canary.yml
Normal file
31
it-and-security/teams/servers-canary.yml
Normal file
@ -0,0 +1,31 @@
|
||||
name: "Servers (canary)"
|
||||
team_settings:
|
||||
features:
|
||||
enable_host_users: false
|
||||
enable_software_inventory: false
|
||||
host_expiry_settings:
|
||||
host_expiry_enabled: false
|
||||
host_expiry_window: 0
|
||||
secrets:
|
||||
- secret: $DOGFOOD_SERVERS_CANARY_ENROLL_SECRET
|
||||
agent_options:
|
||||
path: ../lib/servers.agent-options.yml
|
||||
controls:
|
||||
enable_disk_encryption: false
|
||||
macos_settings:
|
||||
custom_settings:
|
||||
macos_setup:
|
||||
bootstrap_package: null
|
||||
enable_end_user_authentication: false
|
||||
macos_setup_assistant: null
|
||||
macos_updates:
|
||||
deadline: null
|
||||
minimum_version: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
windows_updates:
|
||||
deadline_days: null
|
||||
grace_period_days: null
|
||||
scripts:
|
||||
policies:
|
||||
queries:
|
31
it-and-security/teams/servers.yml
Normal file
31
it-and-security/teams/servers.yml
Normal file
@ -0,0 +1,31 @@
|
||||
name: "Servers"
|
||||
team_settings:
|
||||
features:
|
||||
enable_host_users: true
|
||||
enable_software_inventory: true
|
||||
host_expiry_settings:
|
||||
host_expiry_enabled: false
|
||||
host_expiry_window: 0
|
||||
secrets:
|
||||
- secret: $DOGFOOD_SERVERS_ENROLL_SECRET
|
||||
agent_options:
|
||||
path: ../lib/servers.agent-options.yml
|
||||
controls:
|
||||
enable_disk_encryption: false
|
||||
macos_settings:
|
||||
custom_settings:
|
||||
macos_setup:
|
||||
bootstrap_package: null
|
||||
enable_end_user_authentication: false
|
||||
macos_setup_assistant: null
|
||||
macos_updates:
|
||||
deadline: null
|
||||
minimum_version: null
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
windows_updates:
|
||||
deadline_days: null
|
||||
grace_period_days: null
|
||||
scripts:
|
||||
policies:
|
||||
queries:
|
68
it-and-security/teams/workstations-canary.yml
Normal file
68
it-and-security/teams/workstations-canary.yml
Normal file
@ -0,0 +1,68 @@
|
||||
name: "Workstations (canary)"
|
||||
team_settings:
|
||||
features:
|
||||
enable_host_users: true
|
||||
enable_software_inventory: true
|
||||
host_expiry_settings:
|
||||
host_expiry_enabled: false
|
||||
host_expiry_window: 0
|
||||
secrets:
|
||||
- secret: $DOGFOOD_WORKSTATIONS_CANARY_ENROLL_SECRET
|
||||
agent_options:
|
||||
path: ../lib/agent-options.yml
|
||||
controls:
|
||||
enable_disk_encryption: true
|
||||
macos_settings:
|
||||
custom_settings:
|
||||
- path: ../../mdm_profiles/automatic_updates.mobileconfig
|
||||
- path: ../../mdm_profiles/chrome_enrollment.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_bluetooth_file_sharing.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_content_caching.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_guest_account.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_guest_shares.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_internet_sharing.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_media_sharing.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_safari_safefiles.mobileconfig
|
||||
- path: ../../mdm_profiles/enable_doh.mobileconfig
|
||||
- path: ../../mdm_profiles/enable_firewall_logging.mobileconfig
|
||||
- path: ../../mdm_profiles/enable_gatekeeper.mobileconfig
|
||||
- path: ../../mdm_profiles/enforce_library_validation.mobileconfig
|
||||
- path: ../../mdm_profiles/firewall.mobileconfig
|
||||
- path: ../../mdm_profiles/full_disk_access_for_orbit.mobileconfig
|
||||
- path: ../../mdm_profiles/limit_ad_tracking.mobileconfig
|
||||
- path: ../../mdm_profiles/misc.mobileconfig
|
||||
- path: ../../mdm_profiles/password_policy.mobileconfig
|
||||
- path: ../../mdm_profiles/prevent_autologon.mobileconfig
|
||||
- path: ../../mdm_profiles/secure_terminal_keyboard.mobileconfig
|
||||
- path: ../../mdm_profiles/time_and_date.mobileconfig
|
||||
macos_setup:
|
||||
bootstrap_package: ""
|
||||
enable_end_user_authentication: true
|
||||
macos_setup_assistant: null
|
||||
macos_updates:
|
||||
deadline: "2023-12-15"
|
||||
minimum_version: "14.2"
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
windows_updates:
|
||||
deadline_days: 7
|
||||
grace_period_days: 2
|
||||
scripts:
|
||||
- path: ../lib/collect-fleetd-logs.sh
|
||||
- path: ../lib/macos-see-automatic-enrollment-profile.sh
|
||||
- path: ../lib/windows-remove-fleetd.ps1
|
||||
- path: ../lib/windows-turn-off-mdm.ps1
|
||||
policies:
|
||||
- path: ../lib/macos-device-health.policies.yml
|
||||
- path: ../lib/windows-device-health.policies.yml
|
||||
- path: ../lib/linux-device-health.policies.yml
|
||||
- name: chromeOS/macOS - Screenlock enabled
|
||||
query: SELECT 1 FROM screenlock WHERE enabled = 1;
|
||||
critical: false
|
||||
description: ""
|
||||
resolution: ""
|
||||
platform: darwin,chrome
|
||||
queries:
|
||||
- path: ../lib/collect-failed-login-attempts.queries.yml
|
||||
- path: ../lib/collect-usb-devices.queries.yml
|
||||
- path: ../lib/collect-vs-code-extensions.queries.yml
|
62
it-and-security/teams/workstations.yml
Normal file
62
it-and-security/teams/workstations.yml
Normal file
@ -0,0 +1,62 @@
|
||||
name: "Workstations"
|
||||
team_settings:
|
||||
features:
|
||||
enable_host_users: true
|
||||
enable_software_inventory: true
|
||||
host_expiry_settings:
|
||||
host_expiry_enabled: false
|
||||
host_expiry_window: 0
|
||||
secrets:
|
||||
- secret: $DOGFOOD_WORKSTATIONS_ENROLL_SECRET
|
||||
agent_options:
|
||||
path: ../lib/agent-options.yml
|
||||
controls:
|
||||
enable_disk_encryption: true
|
||||
macos_settings:
|
||||
custom_settings:
|
||||
- path: ../../mdm_profiles/automatic_updates.mobileconfig
|
||||
- path: ../../mdm_profiles/chrome_enrollment.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_bluetooth_file_sharing.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_content_caching.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_guest_account.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_guest_shares.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_internet_sharing.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_media_sharing.mobileconfig
|
||||
- path: ../../mdm_profiles/disable_safari_safefiles.mobileconfig
|
||||
- path: ../../mdm_profiles/enable_doh.mobileconfig
|
||||
- path: ../../mdm_profiles/enable_firewall_logging.mobileconfig
|
||||
- path: ../../mdm_profiles/enable_gatekeeper.mobileconfig
|
||||
- path: ../../mdm_profiles/enforce_library_validation.mobileconfig
|
||||
- path: ../../mdm_profiles/firewall.mobileconfig
|
||||
- path: ../../mdm_profiles/full_disk_access_for_orbit.mobileconfig
|
||||
- path: ../../mdm_profiles/limit_ad_tracking.mobileconfig
|
||||
- path: ../../mdm_profiles/misc.mobileconfig
|
||||
- path: ../../mdm_profiles/password_policy.mobileconfig
|
||||
- path: ../../mdm_profiles/prevent_autologon.mobileconfig
|
||||
- path: ../../mdm_profiles/secure_terminal_keyboard.mobileconfig
|
||||
- path: ../../mdm_profiles/time_and_date.mobileconfig
|
||||
macos_setup:
|
||||
bootstrap_package: ""
|
||||
enable_end_user_authentication: true
|
||||
macos_setup_assistant: null
|
||||
macos_updates:
|
||||
deadline: "2023-12-19"
|
||||
minimum_version: "14.2"
|
||||
windows_settings:
|
||||
custom_settings: null
|
||||
windows_updates:
|
||||
deadline_days: 7
|
||||
grace_period_days: 2
|
||||
scripts:
|
||||
- path: ../lib/collect-fleetd-logs.sh
|
||||
- path: ../lib/macos-see-automatic-enrollment-profile.sh
|
||||
- path: ../lib/windows-remove-fleetd.ps1
|
||||
- path: ../lib/windows-turn-off-mdm.ps1
|
||||
policies:
|
||||
- path: ../lib/macos-device-health.policies.yml
|
||||
- path: ../lib/windows-device-health.policies.yml
|
||||
- path: ../lib/linux-device-health.policies.yml
|
||||
queries:
|
||||
- path: ../lib/collect-failed-login-attempts.queries.yml
|
||||
- path: ../lib/collect-usb-devices.queries.yml
|
||||
- path: ../lib/collect-vs-code-extensions.queries.yml
|
@ -94,6 +94,7 @@ type ServerConfig struct {
|
||||
Keepalive bool `yaml:"keepalive"`
|
||||
SandboxEnabled bool `yaml:"sandbox_enabled"`
|
||||
WebsocketsAllowUnsafeOrigin bool `yaml:"websockets_allow_unsafe_origin"`
|
||||
FrequentCleanupsEnabled bool `yaml:"frequent_cleanups_enabled"`
|
||||
}
|
||||
|
||||
func (s *ServerConfig) DefaultHTTPServer(ctx context.Context, handler http.Handler) *http.Server {
|
||||
@ -841,6 +842,7 @@ func (man Manager) addConfigs() {
|
||||
man.addConfigBool("server.sandbox_enabled", false,
|
||||
"When enabled, Fleet limits some features for the Sandbox")
|
||||
man.addConfigBool("server.websockets_allow_unsafe_origin", false, "Disable checking the origin header on websocket connections, this is sometimes necessary when proxies rewrite origin headers between the client and the Fleet webserver")
|
||||
man.addConfigBool("server.frequent_cleanups_enabled", false, "Enable frequent cleanups of expired data (15 minute interval)")
|
||||
|
||||
// Hide the sandbox flag as we don't want it to be discoverable for users for now
|
||||
sandboxFlag := man.command.PersistentFlags().Lookup(flagNameFromConfigKey("server.sandbox_enabled"))
|
||||
@ -1191,6 +1193,7 @@ func (man Manager) LoadConfig() FleetConfig {
|
||||
Keepalive: man.getConfigBool("server.keepalive"),
|
||||
SandboxEnabled: man.getConfigBool("server.sandbox_enabled"),
|
||||
WebsocketsAllowUnsafeOrigin: man.getConfigBool("server.websockets_allow_unsafe_origin"),
|
||||
FrequentCleanupsEnabled: man.getConfigBool("server.frequent_cleanups_enabled"),
|
||||
},
|
||||
Auth: AuthConfig{
|
||||
BcryptCost: man.getConfigInt("auth.bcrypt_cost"),
|
||||
|
@ -404,6 +404,7 @@ func saltAndHashPassword(keySize int, plaintext string, cost int) (hashed []byte
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
salt = salt[:keySize]
|
||||
withSalt := []byte(fmt.Sprintf("%s%s", plaintext, salt))
|
||||
hashed, err = bcrypt.GenerateFromPassword(withSalt, cost)
|
||||
if err != nil {
|
||||
|
@ -164,11 +164,11 @@ func TestUserPasswordRequirements(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSaltAndHashPassword(t *testing.T) {
|
||||
passwordTests := []string{"foobar!!", "bazbing!!"}
|
||||
goodTests := []string{"foobar!!", "bazbing!!", "foobarbaz!!!foobarbaz!!!foobarbaz!!!foobarbaz!!", "foobarbaz!!!foobarbaz!!!foobarbaz!!!foobarbaz!!!"}
|
||||
keySize := 24
|
||||
cost := 10
|
||||
|
||||
for _, pwd := range passwordTests {
|
||||
for _, pwd := range goodTests {
|
||||
hashed, salt, err := saltAndHashPassword(keySize, pwd, cost)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -178,6 +178,14 @@ func TestSaltAndHashPassword(t *testing.T) {
|
||||
|
||||
err = bcrypt.CompareHashAndPassword(hashed, []byte(fmt.Sprint("invalidpassword", salt)))
|
||||
require.Error(t, err)
|
||||
|
||||
// too long
|
||||
badTests := []string{"foobarbaz!!!foobarbaz!!!foobarbaz!!!foobarbaz!!!!"}
|
||||
for _, pwd := range badTests {
|
||||
_, _, err := saltAndHashPassword(keySize, pwd, cost)
|
||||
require.Error(t, err)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ func (m *MDMWindowsConfigProfile) ValidateUserProvided() error {
|
||||
// NOTE: since we're only checking for well-formedness
|
||||
// we don't need to validate the required nesting
|
||||
// structure (Target>Item>LocURI) so we don't need to track all the tags.
|
||||
var inReplace bool
|
||||
var inValidNode bool
|
||||
var inLocURI bool
|
||||
|
||||
for {
|
||||
@ -96,24 +96,24 @@ func (m *MDMWindowsConfigProfile) ValidateUserProvided() error {
|
||||
|
||||
case xml.StartElement:
|
||||
switch t.Name.Local {
|
||||
case "Replace":
|
||||
inReplace = true
|
||||
case "Replace", "Add":
|
||||
inValidNode = true
|
||||
case "LocURI":
|
||||
if !inReplace {
|
||||
return errors.New("Only <Replace> supported as a top level element. Make sure you don't have other top level elements.")
|
||||
if !inValidNode {
|
||||
return errors.New("Windows configuration profiles can only have <Replace> or <Add> top level elements.")
|
||||
}
|
||||
inLocURI = true
|
||||
|
||||
default:
|
||||
if !inReplace {
|
||||
return errors.New("Only <Replace> supported as a top level element. Make sure you don't have other top level elements.")
|
||||
if !inValidNode {
|
||||
return errors.New("Windows configuration profiles can only have <Replace> or <Add> top level elements.")
|
||||
}
|
||||
}
|
||||
|
||||
case xml.EndElement:
|
||||
switch t.Name.Local {
|
||||
case "Replace":
|
||||
inReplace = false
|
||||
case "Replace", "Add":
|
||||
inValidNode = false
|
||||
case "LocURI":
|
||||
inLocURI = false
|
||||
}
|
||||
|
@ -39,10 +39,10 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</SyncML>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "Invalid top level element",
|
||||
name: "Add top level element",
|
||||
profile: MDMWindowsConfigProfile{
|
||||
SyncML: []byte(`
|
||||
<Add>
|
||||
@ -52,7 +52,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Add>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements.",
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "Reserved LocURI",
|
||||
@ -139,7 +139,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Add>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "XML with Replace and Alert",
|
||||
@ -157,7 +157,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Alert>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "XML with Replace and Atomic",
|
||||
@ -175,7 +175,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Atomic>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "XML with Replace and Delete",
|
||||
@ -193,7 +193,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Delete>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "XML with Replace and Exec",
|
||||
@ -211,7 +211,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Exec>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "XML with Replace and Get",
|
||||
@ -229,7 +229,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Get>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "XML with Replace and Results",
|
||||
@ -247,7 +247,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Results>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "XML with Replace and Status",
|
||||
@ -265,7 +265,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Status>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "XML with elements not defined in the protocol",
|
||||
@ -283,7 +283,7 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
</Foo>
|
||||
`),
|
||||
},
|
||||
wantErr: "Only <Replace> supported as a top level element. Make sure you don't have other top level elements",
|
||||
wantErr: "Windows configuration profiles can only have <Replace> or <Add> top level elements.",
|
||||
},
|
||||
{
|
||||
name: "invalid XML with mismatched tags",
|
||||
@ -359,7 +359,8 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
<Data>Invalid & Data</Data>
|
||||
</Item>
|
||||
</Replace>
|
||||
`)},
|
||||
`),
|
||||
},
|
||||
wantErr: "The file should include valid XML",
|
||||
},
|
||||
{
|
||||
|
@ -35,8 +35,7 @@ func DecryptBase64CMS(p7Base64 string, cert *x509.Certificate, key crypto.Privat
|
||||
//
|
||||
// - Returns "darwin" if the profile starts with "<?xml", typical of Darwin
|
||||
// platform profiles.
|
||||
// - Returns "windows" if the profile begins with "<replace", as we only accept
|
||||
// replaces directives for profiles.
|
||||
// - Returns "windows" if the profile begins with "<replace" or "<add",
|
||||
// - Returns an empty string for profiles that are either unrecognized or
|
||||
// empty.
|
||||
func GetRawProfilePlatform(profile []byte) string {
|
||||
@ -46,13 +45,16 @@ func GetRawProfilePlatform(profile []byte) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
darwinPrefix := []byte("<?xml")
|
||||
if len(trimmedProfile) >= len(darwinPrefix) && bytes.EqualFold(darwinPrefix, trimmedProfile[:len(darwinPrefix)]) {
|
||||
prefixMatches := func(prefix []byte) bool {
|
||||
return len(trimmedProfile) >= len(prefix) &&
|
||||
bytes.EqualFold(prefix, trimmedProfile[:len(prefix)])
|
||||
}
|
||||
|
||||
if prefixMatches([]byte("<?xml")) {
|
||||
return "darwin"
|
||||
}
|
||||
|
||||
windowsPrefix := []byte("<replace")
|
||||
if len(trimmedProfile) >= len(windowsPrefix) && bytes.EqualFold(windowsPrefix, trimmedProfile[:len(windowsPrefix)]) {
|
||||
if prefixMatches([]byte("<replace")) || prefixMatches([]byte("<add")) {
|
||||
return "windows"
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,16 @@ func TestGetRawProfilePlatform(t *testing.T) {
|
||||
input: []byte("<REPLACE this=\"that\">"),
|
||||
expected: "windows",
|
||||
},
|
||||
{
|
||||
name: "Windows case insensitive add ",
|
||||
input: []byte("<ADD this=\"that\">"),
|
||||
expected: "windows",
|
||||
},
|
||||
{
|
||||
name: "Windows case sensitive add",
|
||||
input: []byte("<Add this=\"that\">"),
|
||||
expected: "windows",
|
||||
},
|
||||
{
|
||||
name: "Whitespace before prefix",
|
||||
input: []byte(" <?xml version=\"1.0\"?>"),
|
||||
|
@ -8078,10 +8078,36 @@ func (s *integrationMDMTestSuite) TestWindowsMDM() {
|
||||
err = s.ds.MDMWindowsInsertCommandForHosts(context.Background(), []string{orbitHost.UUID}, commandThree)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmdFourUUID := uuid.New().String()
|
||||
commandFour := &fleet.MDMWindowsCommand{
|
||||
CommandUUID: cmdFourUUID,
|
||||
RawCommand: []byte(fmt.Sprintf(`
|
||||
<Add>
|
||||
<CmdID>%s</CmdID>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>./Vendor/MSFT/WiFi/Profile/MyNetwork/WlanXml</LocURI>
|
||||
</Target>
|
||||
<Meta>
|
||||
<Type xmlns="syncml:metinf">text/plain</Type>
|
||||
<Format xmlns="syncml:metinf">chr</Format>
|
||||
</Meta>
|
||||
<Data>
|
||||
<?xml version="1.0"?><WLANProfile
|
||||
xmlns="http://contoso.com/provisioning/EapHostConfig"><EapMethod><Type
|
||||
</Data>
|
||||
</Item>
|
||||
</Add>
|
||||
`, cmdFourUUID)),
|
||||
TargetLocURI: "./Vendor/MSFT/WiFi/Profile/MyNetwork/WlanXml",
|
||||
}
|
||||
err = s.ds.MDMWindowsInsertCommandForHosts(context.Background(), []string{orbitHost.UUID}, commandFour)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmds, err = d.StartManagementSession()
|
||||
require.NoError(t, err)
|
||||
// two status + the two commands we enqueued
|
||||
require.Len(t, cmds, 4)
|
||||
// two status + the three commands we enqueued
|
||||
require.Len(t, cmds, 5)
|
||||
receivedCmdTwo := cmds[cmdTwoUUID]
|
||||
require.NotNil(t, receivedCmdTwo)
|
||||
require.Equal(t, receivedCmdTwo.Verb, fleet.CmdGet)
|
||||
@ -8094,6 +8120,12 @@ func (s *integrationMDMTestSuite) TestWindowsMDM() {
|
||||
require.Len(t, receivedCmdThree.Cmd.Items, 1)
|
||||
require.EqualValues(t, "./Device/Vendor/MSFT/DMClient/Provider/DEMO%20MDM/SignedEntDMID", *receivedCmdThree.Cmd.Items[0].Target)
|
||||
|
||||
receivedCmdFour := cmds[cmdFourUUID]
|
||||
require.NotNil(t, receivedCmdFour)
|
||||
require.Equal(t, receivedCmdFour.Verb, fleet.CmdAdd)
|
||||
require.Len(t, receivedCmdFour.Cmd.Items, 1)
|
||||
require.EqualValues(t, "./Vendor/MSFT/WiFi/Profile/MyNetwork/WlanXml", *receivedCmdFour.Cmd.Items[0].Target)
|
||||
|
||||
// status 200 for command Two (Get)
|
||||
d.AppendResponse(fleet.SyncMLCmd{
|
||||
XMLName: xml.Name{Local: mdm_types.CmdStatus},
|
||||
@ -8130,8 +8162,19 @@ func (s *integrationMDMTestSuite) TestWindowsMDM() {
|
||||
Items: nil,
|
||||
CmdID: fleet.CmdID{Value: uuid.NewString()},
|
||||
})
|
||||
// status 200 for command Four (Add)
|
||||
d.AppendResponse(fleet.SyncMLCmd{
|
||||
XMLName: xml.Name{Local: mdm_types.CmdStatus},
|
||||
MsgRef: &msgID,
|
||||
CmdRef: &cmdFourUUID,
|
||||
Cmd: ptr.String("Add"),
|
||||
Data: ptr.String("200"),
|
||||
Items: nil,
|
||||
CmdID: fleet.CmdID{Value: uuid.NewString()},
|
||||
})
|
||||
cmds, err = d.SendResponse()
|
||||
require.NoError(t, err)
|
||||
|
||||
// the ack of the message should be the only returned command
|
||||
require.Len(t, cmds, 1)
|
||||
|
||||
@ -8192,6 +8235,20 @@ func (s *integrationMDMTestSuite) TestWindowsMDM() {
|
||||
Hostname: "TestIntegrationsMDM/TestWindowsMDMh1.local",
|
||||
Payload: commandThree.RawCommand,
|
||||
}, getMDMCmdResp.Results[0])
|
||||
|
||||
s.DoJSON("GET", "/api/latest/fleet/mdm/commandresults", nil, http.StatusOK, &getMDMCmdResp, "command_uuid", cmdFourUUID)
|
||||
require.Len(t, getMDMCmdResp.Results, 1)
|
||||
require.NotZero(t, getMDMCmdResp.Results[0].UpdatedAt)
|
||||
getMDMCmdResp.Results[0].UpdatedAt = time.Time{}
|
||||
require.Equal(t, &fleet.MDMCommandResult{
|
||||
HostUUID: orbitHost.UUID,
|
||||
CommandUUID: cmdFourUUID,
|
||||
Status: "200",
|
||||
RequestType: "./Vendor/MSFT/WiFi/Profile/MyNetwork/WlanXml",
|
||||
Result: getCommandFullResult(cmdFourUUID),
|
||||
Hostname: "TestIntegrationsMDM/TestWindowsMDMh1.local",
|
||||
Payload: commandFour.RawCommand,
|
||||
}, getMDMCmdResp.Results[0])
|
||||
}
|
||||
|
||||
func (s *integrationMDMTestSuite) TestWindowsAutomaticEnrollmentCommands() {
|
||||
@ -8730,7 +8787,7 @@ func (s *integrationMDMTestSuite) TestMDMConfigProfileCRUD() {
|
||||
body, headers := generateNewProfileMultipartRequest(
|
||||
t,
|
||||
filename,
|
||||
[]byte(fmt.Sprintf(`<Replace><Item><Target><LocURI>%s</LocURI></Target></Item></Replace>`, locURI)),
|
||||
[]byte(fmt.Sprintf(`<Add><Item><Target><LocURI>%s</LocURI></Target></Item></Add><Replace><Item><Target><LocURI>%s</LocURI></Target></Item></Replace>`, locURI, locURI)),
|
||||
s.token,
|
||||
fields,
|
||||
)
|
||||
@ -9011,7 +9068,7 @@ func (s *integrationMDMTestSuite) TestListMDMConfigProfiles() {
|
||||
tm2ProfG, err := s.ds.NewMDMWindowsConfigProfile(ctx, fleet.MDMWindowsConfigProfile{
|
||||
Name: "tG",
|
||||
TeamID: &tm2.ID,
|
||||
SyncML: []byte(`<Replace></Replace>`),
|
||||
SyncML: []byte(`<Add></Add>`),
|
||||
Labels: []mdm_types.ConfigurationProfileLabel{
|
||||
{LabelID: lblFoo.ID, LabelName: lblFoo.Name},
|
||||
{LabelID: lblBar.ID, LabelName: lblBar.Name},
|
||||
|
@ -1028,7 +1028,7 @@ func TestUploadWindowsMDMConfigProfileValidations(t *testing.T) {
|
||||
{"mdm not enabled", 0, `<Replace></Replace>`, false, "Windows MDM isn't turned on."},
|
||||
{"duplicate profile name", 0, `<Replace>duplicate</Replace>`, true, "configuration profile with this name already exists."},
|
||||
{"multiple Replace", 0, `<Replace>a</Replace><Replace>b</Replace>`, true, ""},
|
||||
{"Replace and non-Replace", 0, `<Replace>a</Replace><Get>b</Get>`, true, "Only <Replace> supported as a top level element."},
|
||||
{"Replace and non-Replace", 0, `<Replace>a</Replace><Get>b</Get>`, true, "Windows configuration profiles can only have <Replace> or <Add> top level elements."},
|
||||
{"BitLocker profile", 0, `<Replace><Item><Target><LocURI>./Device/Vendor/MSFT/BitLocker/AllowStandardUserEncryption</LocURI></Target></Item></Replace>`, true, "Custom configuration profiles can't include BitLocker settings."},
|
||||
{"Windows updates profile", 0, `<Replace><Item><Target><LocURI> ./Device/Vendor/MSFT/Policy/Config/Update/ConfigureDeadlineNoAutoRebootForFeatureUpdates </LocURI></Target></Item></Replace>`, true, "Custom configuration profiles can't include Windows updates settings."},
|
||||
|
||||
@ -1039,7 +1039,7 @@ func TestUploadWindowsMDMConfigProfileValidations(t *testing.T) {
|
||||
{"team mdm not enabled", 1, `<Replace></Replace>`, false, "Windows MDM isn't turned on."},
|
||||
{"team duplicate profile name", 1, `<Replace>duplicate</Replace>`, true, "configuration profile with this name already exists."},
|
||||
{"team multiple Replace", 1, `<Replace>a</Replace><Replace>b</Replace>`, true, ""},
|
||||
{"team Replace and non-Replace", 1, `<Replace>a</Replace><Get>b</Get>`, true, "Only <Replace> supported as a top level element."},
|
||||
{"team Replace and non-Replace", 1, `<Replace>a</Replace><Get>b</Get>`, true, "Windows configuration profiles can only have <Replace> or <Add> top level elements."},
|
||||
{"team BitLocker profile", 1, `<Replace><Item><Target><LocURI>./Device/Vendor/MSFT/BitLocker/AllowStandardUserEncryption</LocURI></Target></Item></Replace>`, true, "Custom configuration profiles can't include BitLocker settings."},
|
||||
{"team Windows updates profile", 1, `<Replace><Item><Target><LocURI> ./Device/Vendor/MSFT/Policy/Config/Update/ConfigureDeadlineNoAutoRebootForFeatureUpdates </LocURI></Target></Item></Replace>`, true, "Custom configuration profiles can't include Windows updates settings."},
|
||||
|
||||
|
@ -407,11 +407,18 @@ func TestBuildCommandFromProfileBytes(t *testing.T) {
|
||||
|
||||
func syncMLForTest(locURI string) []byte {
|
||||
return []byte(fmt.Sprintf(`
|
||||
<Add>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>%s</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Add>
|
||||
<Replace>
|
||||
<Item>
|
||||
<Target>
|
||||
<LocURI>%s</LocURI>
|
||||
</Target>
|
||||
</Item>
|
||||
</Replace>`, locURI))
|
||||
</Replace>`, locURI, locURI))
|
||||
}
|
||||
|
5
website/views/pages/device-management.ejs
vendored
5
website/views/pages/device-management.ejs
vendored
@ -157,11 +157,12 @@
|
||||
<div purpose="page-section">
|
||||
<div purpose="feature" class="d-flex flex-md-row flex-column-reverse justify-content-between mx-auto align-items-center">
|
||||
<div purpose="feature-text" class="d-flex flex-column">
|
||||
<h2>Absolute certainty</h2>
|
||||
<p>Reduce time wasted hunting down whether a change happened. Actually verify that settings are applied using real data pulled from your users' devices.</p>
|
||||
<h2>Shorten the feedback loop</h2>
|
||||
<p>Spend less time debugging whether changes actually happened. Auto-verify using real data pulled from your users' devices.</p>
|
||||
<div purpose="checklist" class="flex-column d-flex">
|
||||
<p>Use a git repo as the source of truth to reduce errors (submitting the wrong patch, configuration setting etc)</p>
|
||||
<p>Every change to a policy or security control is tracked and auditable in Fleet’s history, or via the repo commit log</p>
|
||||
<p>Instantly reveal failed patches and broken settings with osquery to shorten the feedback loop and avoid tickets.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div purpose="feature-image" class="right">
|
||||
|
Loading…
Reference in New Issue
Block a user