From 9a1b3769c868cbb458e0190df848d78603d5050b Mon Sep 17 00:00:00 2001 From: Gabriel Hernandez Date: Thu, 19 Sep 2024 11:50:18 +0100 Subject: [PATCH 01/12] show correct chrome software icon for chrome packages (#22233) relates to #20865 Show the correct software icon for uploaded chrome packages ![image](https://github.com/user-attachments/assets/85215a31-0b63-438b-a4dc-661cea026c3b) - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - [x] Manual QA for all new/changed functionality --- changes/20865-fix-chrome-icon | 1 + frontend/pages/SoftwarePage/components/icons/index.ts | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 changes/20865-fix-chrome-icon diff --git a/changes/20865-fix-chrome-icon b/changes/20865-fix-chrome-icon new file mode 100644 index 0000000000..9ac53c39cc --- /dev/null +++ b/changes/20865-fix-chrome-icon @@ -0,0 +1 @@ +- show proper software icon for chrome packages diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index 59e6187009..2c8d355f7e 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -45,6 +45,7 @@ const SOFTWARE_NAME_TO_ICON_MAP = { "microsoft teams": Teams, "visual studio code": VisualStudioCode, "microsoft word": Word, + "google chrome": ChromeApp, darwin: MacOS, windows: WindowsOS, chrome: ChromeOS, @@ -113,8 +114,6 @@ const matchStrictNameSourceToIcon = ({ return Zoom; case name === "zoom": return Zoom; - case name === "google chrome": - return ChromeApp; default: return null; } From ebb62af6d99c41c92fbeb2f6b3375466a766ba56 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 19 Sep 2024 09:09:21 -0500 Subject: [PATCH 02/12] Website: Deliver contact form messages to Slack (#22231) Related to: https://github.com/fleetdm/confidential/issues/8098 Changes: - Updated `deliver-contact-form-message` to send contact form submissions to a Slack webhook. --- .../deliver-contact-form-message.js | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/website/api/controllers/deliver-contact-form-message.js b/website/api/controllers/deliver-contact-form-message.js index ea5d6251ec..37e5693f5c 100644 --- a/website/api/controllers/deliver-contact-form-message.js +++ b/website/api/controllers/deliver-contact-form-message.js @@ -66,26 +66,9 @@ module.exports = { throw 'invalidEmailDomain'; } - // await sails.helpers.http.post(sails.config.custom.slackWebhookUrlForContactForm, { - // text: `New contact form message: (Remember: we have to email back; can't just reply to this thread.) cc @sales `+ - // `Name: ${firstName + ' ' + lastName}, Email: ${emailAddress}, Message: ${message ? message : 'No message.'}` - // }); - - await sails.helpers.sendTemplateEmail.with({ - to: sails.config.custom.fromEmailAddress, - replyTo: { - name: firstName + ' '+ lastName, - emailAddress: emailAddress, - }, - subject: 'New contact form message', - layout: false, - template: 'email-contact-form', - templateData: { - emailAddress, - firstName, - lastName, - message, - }, + await sails.helpers.http.post(sails.config.custom.slackWebhookUrlForContactForm, { + text: `New contact form message: (Remember: we have to email back; can't just reply to this thread.)`+ + `Name: ${firstName + ' ' + lastName}, Email: ${emailAddress}, Message: ${message ? message : 'No message.'}` }); sails.helpers.salesforce.updateOrCreateContactAndAccount.with({ From 246fa60007227b1b89274aaf129b17ac38f1f827 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Thu, 19 Sep 2024 10:04:51 -0500 Subject: [PATCH 03/12] Iron out the nav -- Update layout.ejs (#22151) --- website/views/layouts/layout.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/views/layouts/layout.ejs b/website/views/layouts/layout.ejs index 702ba0d5f5..c8a438213f 100644 --- a/website/views/layouts/layout.ejs +++ b/website/views/layouts/layout.ejs @@ -169,7 +169,7 @@ Docs REST API Guides - <%= ['eo-it', 'mdm'].includes(primaryBuyingSituation) ? 'Device health checks' : 'Built-in queries' %> + Built-in queries Data tables SUPPORT
From 6ab05ded4c951e624fdddb5c1798de5b2072aff5 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Thu, 19 Sep 2024 10:06:45 -0500 Subject: [PATCH 04/12] Update link + CTA on pricing.ejs (#22229) Co-authored-by: Eric --- website/assets/js/pages/contact.page.js | 4 ++-- website/views/pages/pricing.ejs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/assets/js/pages/contact.page.js b/website/assets/js/pages/contact.page.js index 36571b672a..c7595825ca 100644 --- a/website/assets/js/pages/contact.page.js +++ b/website/assets/js/pages/contact.page.js @@ -50,8 +50,8 @@ parasails.registerPage('contact', { if(this.formToShow === 'contact'){ this.formToDisplay = this.formToShow; } else if(!this.primaryBuyingSituation){ - // Default to contact form for users who have no primaryBuyingSituation set. - this.formToDisplay = 'contact'; + // Otherwise, default to the formToShow value from the page's controller. + this.formToDisplay = this.formToShow; } if(this.primaryBuyingSituation){ // If the user has a priamry buying situation set in their sesssion, pre-fill the form. // Note: this will be overriden if the user is logged in and has a primaryBuyingSituation set in the database. diff --git a/website/views/pages/pricing.ejs b/website/views/pages/pricing.ejs index fe1865886a..0a739c7529 100644 --- a/website/views/pages/pricing.ejs +++ b/website/views/pages/pricing.ejs @@ -380,7 +380,7 @@
-

Couldn’t find an answer? Message us.

+

Couldn’t find an answer? Talk to us.

From ad4c05e9ec47480730de7adba73de075bb1840c3 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 19 Sep 2024 10:24:06 -0500 Subject: [PATCH 05/12] Website: Update start CTA orb image (psyStage 4) (#22232) Changes: - Updated the /start CTA image for psystage 4 users --- ...ail-psystage-4-has-use-case-128x128@2x.png | Bin 32368 -> 24713 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/website/assets/images/cta-thumbnail-psystage-4-has-use-case-128x128@2x.png b/website/assets/images/cta-thumbnail-psystage-4-has-use-case-128x128@2x.png index 29347073c01ca0a7a43f43f09124f9b7c46cb51d..c00066c4087dc112b74cfc352c5584f007e72fd1 100644 GIT binary patch literal 24713 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 literal 32368 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 From 90c04eef37690b8ebb98849f37fb0f403b775527 Mon Sep 17 00:00:00 2001 From: Jahziel Villasana-Espinoza Date: Thu, 19 Sep 2024 11:31:46 -0400 Subject: [PATCH 06/12] fix: stop profiles that never reached the host from showing up as failed (#22186) > Related issue: #21891 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --- changes/21891-mdm-profile-fails | 2 + server/datastore/mysql/apple_mdm.go | 10 +- server/fleet/apple_mdm.go | 6 +- server/service/apple_mdm.go | 4 +- .../service/integration_mdm_profiles_test.go | 10 +- server/service/integration_mdm_test.go | 95 +++++++++++-------- 6 files changed, 74 insertions(+), 53 deletions(-) create mode 100644 changes/21891-mdm-profile-fails diff --git a/changes/21891-mdm-profile-fails b/changes/21891-mdm-profile-fails new file mode 100644 index 0000000000..a01bac1649 --- /dev/null +++ b/changes/21891-mdm-profile-fails @@ -0,0 +1,2 @@ +- Fixes a bug where a profile wouldn't be removed from a host if it was deleted or if the host was + moved to another team before the profile was installed on the host. \ No newline at end of file diff --git a/server/datastore/mysql/apple_mdm.go b/server/datastore/mysql/apple_mdm.go index c545c898cc..b4ae8c5ac0 100644 --- a/server/datastore/mysql/apple_mdm.go +++ b/server/datastore/mysql/apple_mdm.go @@ -2087,11 +2087,11 @@ func (ds *Datastore) bulkSetPendingMDMAppleHostProfilesDB( if _, ok := profileIntersection.GetMatchingProfileInDesiredState(p); ok { continue } - // If the installation failed, then we do not want to change the operation to "Remove". + // If the profile wasn't installed, then we do not want to change the operation to "Remove". // Doing so will result in Fleet attempting to remove a profile that doesn't exist on the // host (since the installation failed). Skipping it here will lead to it being removed from // the host in Fleet during profile reconciliation, which is what we want. - if p.FailedToInstallOnHost() { + if p.DidNotInstallOnHost() { continue } profilesToInsert[fmt.Sprintf("%s\n%s", p.HostUUID, p.ProfileUUID)] = &fleet.MDMAppleProfilePayload{ @@ -4410,7 +4410,8 @@ func (ds *Datastore) insertOrUpsertMDMAppleDeclaration(ctx context.Context, insO } func batchSetDeclarationLabelAssociationsDB(ctx context.Context, tx sqlx.ExtContext, - declarationLabels []fleet.ConfigurationProfileLabel) (updatedDB bool, err error) { + declarationLabels []fleet.ConfigurationProfileLabel, +) (updatedDB bool, err error) { if len(declarationLabels) == 0 { return false, nil } @@ -4618,7 +4619,8 @@ func (ds *Datastore) MDMAppleBatchSetHostDeclarationState(ctx context.Context) ( } func mdmAppleBatchSetHostDeclarationStateDB(ctx context.Context, tx sqlx.ExtContext, batchSize int, - status *fleet.MDMDeliveryStatus) ([]string, bool, error) { + status *fleet.MDMDeliveryStatus, +) ([]string, bool, error) { // once all the declarations are in place, compute the desired state // and find which hosts need a DDM sync. changedDeclarations, err := mdmAppleGetHostsWithChangedDeclarationsDB(ctx, tx) diff --git a/server/fleet/apple_mdm.go b/server/fleet/apple_mdm.go index 9a3bb005f8..832ee5d237 100644 --- a/server/fleet/apple_mdm.go +++ b/server/fleet/apple_mdm.go @@ -311,10 +311,10 @@ type MDMAppleProfilePayload struct { CommandUUID string `db:"command_uuid"` } -// FailedToInstallOnHost indicates whether this profile failed to be installed on the host (and +// DidNotInstallOnHost indicates whether this profile was not installed on the host (and // therefore is not, as far as Fleet knows, currently on the host). -func (p *MDMAppleProfilePayload) FailedToInstallOnHost() bool { - return p.Status != nil && *p.Status == MDMDeliveryFailed && p.OperationType == MDMOperationTypeInstall +func (p *MDMAppleProfilePayload) DidNotInstallOnHost() bool { + return p.Status != nil && (*p.Status == MDMDeliveryFailed || *p.Status == MDMDeliveryPending) && p.OperationType == MDMOperationTypeInstall } func (p MDMAppleProfilePayload) Equal(other MDMAppleProfilePayload) bool { diff --git a/server/service/apple_mdm.go b/server/service/apple_mdm.go index 99bfa2195d..4387367ef0 100644 --- a/server/service/apple_mdm.go +++ b/server/service/apple_mdm.go @@ -3298,8 +3298,8 @@ func ReconcileAppleProfiles( continue } - if p.FailedToInstallOnHost() { - // then we shouldn't send an additional remove command since it failed to install on the + if p.DidNotInstallOnHost() { + // then we shouldn't send an additional remove command since it wasn't installed on the // host. hostProfilesToCleanup = append(hostProfilesToCleanup, p) continue diff --git a/server/service/integration_mdm_profiles_test.go b/server/service/integration_mdm_profiles_test.go index f7fc2e2373..49a1f6eab0 100644 --- a/server/service/integration_mdm_profiles_test.go +++ b/server/service/integration_mdm_profiles_test.go @@ -1159,18 +1159,16 @@ func (s *integrationMDMTestSuite) TestPuppetMatchPreassignProfiles() { s.awaitTriggerProfileSchedule(t) // useful for debugging - //mysql.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error { - // mysql.DumpTable(t, q, "host_mdm_apple_profiles") - // return nil - //}) + // mysql.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error { + // mysql.DumpTable(t, q, "host_mdm_apple_profiles") + // return nil + // }) s.assertHostAppleConfigProfiles(map[*fleet.Host][]fleet.HostMDMAppleProfile{ mdmHost: { {Identifier: "i1", OperationType: fleet.MDMOperationTypeInstall, Status: &fleet.MDMDeliveryPending}, - {Identifier: "i2", OperationType: fleet.MDMOperationTypeRemove, Status: &fleet.MDMDeliveryPending}, {Identifier: "i4", OperationType: fleet.MDMOperationTypeInstall, Status: &fleet.MDMDeliveryPending}, {Identifier: mobileconfig.FleetdConfigPayloadIdentifier, OperationType: fleet.MDMOperationTypeInstall, Status: &fleet.MDMDeliveryPending}, {Identifier: mobileconfig.FleetCARootConfigPayloadIdentifier, OperationType: fleet.MDMOperationTypeInstall, Status: &fleet.MDMDeliveryPending}, - {Identifier: mobileconfig.FleetFileVaultPayloadIdentifier, OperationType: fleet.MDMOperationTypeRemove, Status: &fleet.MDMDeliveryPending}, }, }) diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index 2e7ef1f152..ce134a2bd5 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -9383,32 +9383,34 @@ func (s *integrationMDMTestSuite) TestRemoveFailedProfiles() { ident := uuid.NewString() + mdmDeviceRespond := func(device *mdmtest.TestAppleMDMClient) { + cmd, err := device.Idle() + require.NoError(t, err) + for cmd != nil { + if cmd.Command.RequestType == "InstallProfile" { + var fullCmd micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) + + if strings.Contains(string(fullCmd.Command.InstallProfile.Payload), ident) { + var errChain []mdm.ErrorChain + errChain = append(errChain, mdm.ErrorChain{ErrorCode: -102, ErrorDomain: "CPProfile", USEnglishDescription: "The profile is either missing some required information, or contains information in an invalid format."}) + cmd, err = device.Err(cmd.CommandUUID, errChain) + require.NoError(t, err) + continue + } + } + cmd, err = device.Acknowledge(cmd.CommandUUID) + require.NoError(t, err) + } + } + globalProfiles := [][]byte{ mobileconfigForTest("N1", ident), mobileconfigForTest("N2", "I2"), } s.Do("POST", "/api/v1/fleet/mdm/apple/profiles/batch", batchSetMDMAppleProfilesRequest{Profiles: globalProfiles}, http.StatusNoContent) s.awaitTriggerProfileSchedule(t) - - cmd, err := mdmDevice.Idle() - require.NoError(t, err) - for cmd != nil { - if cmd.Command.RequestType == "InstallProfile" { - var fullCmd micromdm.CommandPayload - require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) - - if strings.Contains(string(fullCmd.Command.InstallProfile.Payload), ident) { - var errChain []mdm.ErrorChain - errChain = append(errChain, mdm.ErrorChain{ErrorCode: -102, ErrorDomain: "CPProfile", USEnglishDescription: "The profile is either missing some required information, or contains information in an invalid format."}) - cmd, err = mdmDevice.Err(cmd.CommandUUID, errChain) - require.NoError(t, err) - continue - } - } - cmd, err = mdmDevice.Acknowledge(cmd.CommandUUID) - require.NoError(t, err) - } - + mdmDeviceRespond(mdmDevice) require.NoError(t, apple_mdm.VerifyHostMDMProfiles(context.Background(), s.ds, host, map[string]*fleet.HostMacOSProfile{ "I2": {Identifier: "I2", DisplayName: "I2", InstallDate: time.Now()}, "I1": {Identifier: "I1", DisplayName: "I1", InstallDate: time.Now()}, @@ -9416,24 +9418,7 @@ func (s *integrationMDMTestSuite) TestRemoveFailedProfiles() { // Do another trigger + command fetching cycle, since we retry when a profile fails on install. s.awaitTriggerProfileSchedule(t) - cmd, err = mdmDevice.Idle() - require.NoError(t, err) - for cmd != nil { - if cmd.Command.RequestType == "InstallProfile" { - var fullCmd micromdm.CommandPayload - require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) - - if strings.Contains(string(fullCmd.Command.InstallProfile.Payload), ident) { - var errChain []mdm.ErrorChain - errChain = append(errChain, mdm.ErrorChain{ErrorCode: -102, ErrorDomain: "CPProfile", USEnglishDescription: "The profile is either missing some required information, or contains information in an invalid format."}) - cmd, err = mdmDevice.Err(cmd.CommandUUID, errChain) - require.NoError(t, err) - continue - } - } - cmd, err = mdmDevice.Acknowledge(cmd.CommandUUID) - require.NoError(t, err) - } + mdmDeviceRespond(mdmDevice) require.NoError(t, apple_mdm.VerifyHostMDMProfiles(context.Background(), s.ds, host, map[string]*fleet.HostMacOSProfile{ "I1": {Identifier: "I1", DisplayName: "I1", InstallDate: time.Now()}, @@ -9468,6 +9453,40 @@ func (s *integrationMDMTestSuite) TestRemoveFailedProfiles() { for _, hm := range *getHostResp.Host.MDM.Profiles { require.NotEqual(t, "N1", hm.Name) } + + // Test case where the profile never makes it to the host at all + host, _ = createHostThenEnrollMDM(s.ds, s.server.URL, t) + ident = uuid.NewString() + + globalProfiles = [][]byte{ + mobileconfigForTest("N3", ident), + } + s.Do("POST", "/api/v1/fleet/mdm/apple/profiles/batch", batchSetMDMAppleProfilesRequest{Profiles: globalProfiles}, http.StatusNoContent) + s.awaitTriggerProfileSchedule(t) + + getHostResp = getHostResponse{} + s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/hosts/%d", host.ID), nil, http.StatusOK, &getHostResp) + require.NotNil(t, getHostResp.Host.MDM.Profiles) + require.Len(t, *getHostResp.Host.MDM.Profiles, 3) + var profUUID string + for _, hm := range *getHostResp.Host.MDM.Profiles { + require.Equal(t, fleet.MDMDeliveryPending, *hm.Status) + if hm.Name == "N3" { + profUUID = hm.ProfileUUID + } + } + + // delete the custom profile + s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/mdm/profiles/%s", profUUID), &deleteMDMAppleConfigProfileRequest{}, http.StatusOK) + s.awaitTriggerProfileSchedule(t) + + getHostResp = getHostResponse{} + s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/hosts/%d", host.ID), nil, http.StatusOK, &getHostResp) + require.NotNil(t, getHostResp.Host.MDM.Profiles) + require.Len(t, *getHostResp.Host.MDM.Profiles, 2) + for _, hm := range *getHostResp.Host.MDM.Profiles { + require.Equal(t, fleet.MDMDeliveryPending, *hm.Status) + } } func (s *integrationMDMTestSuite) TestABMAssetManagement() { From e2ac27e011d913eca5a6c6428ece4a25fba7b3b2 Mon Sep 17 00:00:00 2001 From: Luke Heath Date: Thu, 19 Sep 2024 13:35:17 -0500 Subject: [PATCH 07/12] Document 0-day macOS major version support process beginning with macOS 16 (#22243) Co-authored-by: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com> --- handbook/engineering/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/handbook/engineering/README.md b/handbook/engineering/README.md index 13f3d21c15..388a5c8724 100644 --- a/handbook/engineering/README.md +++ b/handbook/engineering/README.md @@ -538,13 +538,25 @@ Upon receiving any device, follow these steps to process incoming equipment. Once the Digital Experience department approves inventory to be shipped from Fleet IT, follow these step to ship the equipment. 1. Compare the equipment request issue with the ["Company equipment" spreadsheet](https://docs.google.com/spreadsheets/d/1hFlymLlRWIaWeVh14IRz03yE-ytBLfUaqVz0VVmmoGI/edit#gid=0) and verify physical inventory. 2. Plug in the device and ensure inventory has been correctly processed and all components are present (e.g. charger cord, power converter). -3. package equipment for shipment and include Yubikeys (if requested). +3. Package equipment for shipment and include Yubikeys (if requested). 4. Change the "Company equipment" spreadsheet to reflect the new user. - If you encounter any issues, repeat the [process incoming equipment steps](https://fleetdm.com/handbook/engineering#process-incoming-equipment). If problems persist, create a ["πŸ’» IT support issue](https://github.com/fleetdm/confidential/issues/new?assignees=%40spokanemac&labels=%3Ahelp-it&projects=&template=request-it-support.md&title=%F0%9F%92%BB+Request+IT+support) for IT to troubleshoot the device. 6. Ship via FedEx to the address listed in the equipment request. 7. Add a comment to the equipment request issue, at-mentioning the requestor with the FedEx tracking info and close the issue. +### Provide 0-day support for major version macOS releases + +Beginning with macOS 16, Fleet will offer 0-day support for all major version macOS releases. + +1. Install major version macOS beta release on test devices. +2. Create a new [QA release issue](https://github.com/fleetdm/fleet/issues/new?assignees=xpkoala%2Cpezhub&labels=%23g-mdm%2C%23g-endpoint-ops%2C%3Arelease&projects=&template=release-qa.md&title=Release+QA%3A+macOS+16) with the new major version in the issue title. +3. Complete all manual smoke tests in the issue and confirm they are passing. +4. Confirm all automated tests are passing. +5. [File bugs](https://github.com/fleetdm/fleet/issues/new?assignees=&labels=P1%2Cbug%2C%3Areproduce%2C%3Aincoming&projects=&template=bug-report.md&title=) with a `P1` label and assign to the appropriate [product group](https://fleetdm.com/handbook/company/product-groups#current-product-groups). +6. When all bugs are fixed, follow the [writing a feature guide](https://fleetdm.com/handbook/engineering#write-a-feature-guide) process to publish an article announcing Fleet 0-day support for the new major release. + + ## Rituals From d52335eb1326123326003d79dcf14fa1b0882160 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Thu, 19 Sep 2024 15:51:44 -0500 Subject: [PATCH 08/12] Update link, clarify iOS (#22230) --- handbook/company/pricing-features-table.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handbook/company/pricing-features-table.yml b/handbook/company/pricing-features-table.yml index c8b17d8ce3..dcc3c26b52 100644 --- a/handbook/company/pricing-features-table.yml +++ b/handbook/company/pricing-features-table.yml @@ -214,8 +214,8 @@ # β•‘ ╠╦╝║ β•‘β•šβ•β•—β•šβ•β•—β”€β”€β”€β• β•β•β•‘ ╠═╣ β•‘ β• β•£ β•‘ ║╠╦╝║║║ β•‘β•‘β•‘ β•‘β•‘β•‘β•‘β•‘ β•šβ•β•—β•‘ ║╠═╝╠═╝║ ║╠╦╝ β•‘ # β•šβ•β•β•©β•šβ•β•šβ•β•β•šβ•β•β•šβ•β• β•© ╩═╝╩ β•© β•© β•š β•šβ•β•β•©β•šβ•β•© β•© β•© ╩═╩╝╩ β•© β•šβ•β•β•šβ•β•β•© β•© β•šβ•β•β•©β•šβ• β•© - industryName: Cross-platform MDM support - description: macOS, Windows, and Linux. - documentationUrl: https://fleetdm.com/announcements/fleet-introduces-windows-mdm + description: Apple, Windows, and Linux. + documentationUrl: https://fleetdm.com/announcements/debunk-the-cross-platform-myth tier: Premium jamfProHasFeature: appleOnly jamfProtectHasFeature: no From f247e57931a09b83d07b07d78306d5691d39e62a Mon Sep 17 00:00:00 2001 From: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:01:31 -0500 Subject: [PATCH 09/12] Add template response to hiring steps (#22255) --- handbook/company/leadership.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/handbook/company/leadership.md b/handbook/company/leadership.md index 3b5448f580..05097bf552 100644 --- a/handbook/company/leadership.md +++ b/handbook/company/leadership.md @@ -380,6 +380,7 @@ Once the new team member replies and accepts their offer in writing, 🌐 Head o - **"Offer accepted?"** _(Set this to `TRUE`)_ - _[Create a "Hiring" issue](https://github.com/fleetdm/confidential/issues/new/choose)_ for the new team member. (This issue will keep track of the hiring tasks for the new team member.) - _Send a reply_ welcoming the team member to Fleet and letting them know to expect a separate email with next steps for getting the team member's laptop, Yubikeys, and agreement going ASAP so they can start on time. For example: + ``` \o/ It's official! @@ -387,15 +388,24 @@ Once the new team member replies and accepts their offer in writing, 🌐 Head o Thanks, and welcome to the team! - -Sam + Cheers, + Sam ``` -2. **Ask hiring manager to send rejections:** Post to the `hiring-xxxxx-yyyy` Slack channel to let folks know the offer was accepted, and at-mention the _hiring manager_ to ask them to communicate with [all other interviewees](https://fleetdm.com/handbook/company#empathy) who are still in the running and [let them know that we chose a different person](https://fleetdm.com/handbook/company/leadership#candidate-correspondence-email-templates). + +2. **Ask hiring manager to send rejections:** Post to the `hiring-xxxxx-yyyy` Slack channel to let folks know the offer was accepted, and at-mention the _hiring manager_ using the following template: + +``` +@HIRING_MANAGER, :astronaut: TEAM_MEMBER_NAME has accepted the offer :fleet: and this position is now filled :white_check_mark:. Please inform any other interviewees who are still in the running and let them know that we chose a different person. :thankyou-ty: +``` + +3. **Close Slack channel:** Then archive the channel. + >_**Note:** Send rejection emails quickly, within 1 business day. It only gets harder if you wait._ -3. **Remove open position:** Ensure the hiring manager removes the newly-filled position from the fleetdm.com website by [making a pull request](https://fleetdm.com/handbook/company/communications#making-a-pull-request) to delete it from the [open-positions.yml](https://github.com/fleetdm/fleet/blob/main/handbook/company/open-positions.yml) file. -4. **Create 30-60-90 day plan:** πŸ§‘β€πŸš€ Hiring manager creates a 30-60-90 day plan outlining key role objectives. The plan is reviewed weekly in 1:1 meetings during the first three months of employment, ensuring continuous support and alignment with company goals. To create the 30-60-90 day plan, hiring manager will: +4. **Remove open position:** Ensure the hiring manager removes the newly-filled position from the fleetdm.com website by [making a pull request](https://fleetdm.com/handbook/company/communications#making-a-pull-request) to delete it from the [open-positions.yml](https://github.com/fleetdm/fleet/blob/main/handbook/company/open-positions.yml) file. +5. **Create 30-60-90 day plan:** πŸ§‘β€πŸš€ Hiring manager creates a 30-60-90 day plan outlining key role objectives. The plan is reviewed weekly in 1:1 meetings during the first three months of employment, ensuring continuous support and alignment with company goals. To create the 30-60-90 day plan, hiring manager will: - Create a copy of the [30-60-90 day plan template](https://docs.google.com/document/d/1EztmPBuMFXbVoy4ZToXcxasNO38ooOh8Gh5hPXFvJhI/copy) and rename the copied file using the naming convention `[start date] - 30-60-90 day plan - [teammate full name]` and move it to the [30-60-90 day plan folder](https://drive.google.com/drive/u/0/folders/1QWiAbgBFuuofT_3M8oIoBsbEBmubQAj7) in Google Drive. - Follow the prompts in the template to fill out the 30-60-90 day plan for the new teammate before they start. -5. **Close Slack channel:** Then archive and close the channel. + Now what happens? 🌐 Head of Digital Experience will then follow the steps in the "Hiring" issue, which includes reaching out to the new team member within 1 business day from a separate email thread to get additional information as needed, prepare their agreement, add them to the company's payroll system, and get their new laptop and hardware security keys ordered so that everything is ready for them to start on their first day. From edec764a27a3a54e212ca4e40badc2497318c3e8 Mon Sep 17 00:00:00 2001 From: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:10:52 -0500 Subject: [PATCH 10/12] Remove AE position (#22256) --- handbook/company/open-positions.yml | 32 ----------------------------- 1 file changed, 32 deletions(-) diff --git a/handbook/company/open-positions.yml b/handbook/company/open-positions.yml index 36eb7e05df..19ad611e9e 100644 --- a/handbook/company/open-positions.yml +++ b/handbook/company/open-positions.yml @@ -36,35 +36,3 @@ - πŸ› οΈ Technical: You understand the software development processes. You understand that software quality matters. - 🟣 Openness: You are flexible and open to new ideas and ways of working. - βž• Bonus: Cybersecurity or IT background. - -- jobTitle: πŸ‹ Account Executive - department: Customers - hiringManagerName: Alex Mitchell - hiringManagerLinkedInUrl: https://www.linkedin.com/in/alexandercmitchell/ - hiringManagerGithubUsername: alexmitchelliii - responsibilities: | - - 🎯 Direct and participate in prospecting target companies, identifying key decision makers and influencers, leading when assigned/necessary/appropriate. - - πŸ“ˆ Use available data to identify opportunities and trends with individual prospects. - - πŸ“£ Actively promote FleetDM product and services on social media. - - πŸ–₯️ Actively present and demonstrate the value of FleetDM products and services and upgrades targeting customer expansion opportunities. - - ❔ Appropriately use and follow MEDDPPICC process to qualify and progress opportunities to best help prospects solve problems. - - πŸ€” Anticipate market trends and identify new opportunities for growth. - - πŸ•΄οΈ Utilize systems and tools such as salesforce to analyze pipeline and opportunity data and keep all information up to date for leadership reporting. - - πŸš€ Work collaboratively with the product management, customer support, and engineering teams to facilitate feature development based on customer asks. - - πŸ§‘β€πŸ’» Collaborate with the marketing team to plan, execute and track impactful marketing campaigns, in order to meet and/or exceed quarterly pipeline and revenue targets. - - 🀝 Work with prospects to find win-win commercial agreements. - experience: | - - πŸ¦‰ 5+ years experience selling to enterprise customers. - - πŸ“£ Have excellent communication and interpersonal skills. - - πŸ§‘β€πŸ’» Love technology and can explain how things work in detail. - - πŸ§ͺ Extensive experience with Slack, Salesforce, Google Suite, and GitHub. - - ⏩ Thrive in a complex, fast-paced, results driven environment with the ability to pivot to organizational changes easily. - - 🀝 Decisive with the ability to shift gears between thinking and doing. - - πŸ“ˆ Ability to partner with various teams and stakeholders to drive sales. - - πŸ‘€ Strong understanding of the enterprise procurement process. - - βž• Bonus: Direct experience with Fleet, MDM, osquery or SQL query writing, and working with Client Platform Engineering, SRE, or Security Engineering teams. - - πŸ’­ You know how to manage complex sales, difficult escalations, and challenging procurement processes with the utmost care and organization. - - πŸ’– You know how to manage your time and priorities between leads, opportunities other day-to-day responsibilities. - - ✍ You have the ability to effectively influence key stakeholders, from senior executives to day-to-day engineering contacts, and discuss Fleet's value with them. - - 🧬 You care about delivering an outstanding customer experience and advocating for the customer's needs within Fleet. - - βž• Bonus: You are comfortable with concepts like DevOps/GitOps, APIs, and security. From 07a58266abd212b81ecf8de705716a60826b92b9 Mon Sep 17 00:00:00 2001 From: Noah Talerman <47070608+noahtalerman@users.noreply.github.com> Date: Thu, 19 Sep 2024 19:11:00 -0400 Subject: [PATCH 11/12] fleetdm.com/start: suggested copy change for fleetctl install (#22251) - Suggesting capital "Linux" and "macOS" b/c it feels more official. --------- Co-authored-by: Eric --- website/assets/resources/install-fleetctl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/assets/resources/install-fleetctl.sh b/website/assets/resources/install-fleetctl.sh index 08fb727385..5f5d4a2774 100644 --- a/website/assets/resources/install-fleetctl.sh +++ b/website/assets/resources/install-fleetctl.sh @@ -28,8 +28,8 @@ version_gt() { OS="$(uname -s)" case "${OS}" in - Linux*) OS='linux';; - Darwin*) OS='macos';; + Linux*) OS='linux' OS_DISPLAY_NAME='Linux';; + Darwin*) OS='macos' OS_DISPLAY_NAME='macOS';; *) echo "Unsupported operating system: ${OS}"; exit 1;; esac @@ -41,7 +41,7 @@ mkdir -p "${FLEETCTL_INSTALL_DIR}" DOWNLOAD_URL="https://github.com/fleetdm/fleet/releases/download/fleet-v${latest_strippedVersion}/fleetctl_v${latest_strippedVersion}_${OS}.tar.gz" # Download the latest version of fleetctl and extract it. -echo "Downloading fleetctl ${latest_strippedVersion} for ${OS}..." +echo "Downloading fleetctl ${latest_strippedVersion} for ${OS_DISPLAY_NAME}..." curl -sSL "$DOWNLOAD_URL" | tar -xz -C "$FLEETCTL_INSTALL_DIR" --strip-components=1 fleetctl_v"${latest_strippedVersion}"_${OS}/ echo "fleetctl installed successfully in ${FLEETCTL_INSTALL_DIR}" echo From 2a88d5a21021f731ee9b061abaa34c53f3864741 Mon Sep 17 00:00:00 2001 From: Noah Talerman <47070608+noahtalerman@users.noreply.github.com> Date: Thu, 19 Sep 2024 20:06:06 -0400 Subject: [PATCH 12/12] Add Product Designer position (#22250) Co-authored-by: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com> --- handbook/company/open-positions.yml | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/handbook/company/open-positions.yml b/handbook/company/open-positions.yml index 19ad611e9e..71bcb2af6b 100644 --- a/handbook/company/open-positions.yml +++ b/handbook/company/open-positions.yml @@ -9,6 +9,30 @@ # experience: | # Add markdown content to this field. ################################################ +- jobTitle: 🦒 Product Designer + department: Product Design + hiringManagerName: Noah Talerman + hiringManagerLinkedInUrl: https://www.linkedin.com/in/noah-talerman/ + hiringManagerGithubUsername: noahtalerman + responsibilities: | + - ⏫ Engage with product management, engineering, business stakeholders, and customers to understand initiatives. + - πŸ“£ Design consistent interactions across the Fleet user experience, including API and CLI. + - 🌑️ Drive the refinement process from concept to high-fidelity prototypes. + experience: | + - πŸ’­ 3 - 5 years of experience as a Product Designer. + - πŸ’– Proficient in visual design and wireframing tools (we use Figma). + - πŸ¦‰ Articulate the problem to be solved and create a compelling narrative around proposed solutions. + - πŸ“– Maintain a design system that enables speed for designers, PMs, and engineers. + - πŸ§‘β€πŸ”¬ Develop an understanding of developer-first automation workflows, including API and CLI experiences. + - πŸ§ͺ Translate user insights into digital experiences that are well-crafted and easy to use. + - 🀝 Collaboration: You work best in a participatory, team-based environment. + - πŸš€ Prototype-first: You embrace speed and failure as we iterate towards the right solution. You have hands-on experience in creating low and high-fidelity prototypes. You’re comfortable accepting suboptimal designs in favor of iteration. + - 🧬 Simplicity: You love complex questions and use your work to simplify that complexity for users. + - 🟣 Openness: You are flexible and open to new ideas and ways of working. + - ✍️ Experience designing CLI experiences for developers or willingness to learn. + - βž• Bonus: YB2B SaaS background + - βž• Bonus: cybersecurity or IT background + - jobTitle: πŸš€ Software Engineer department: Engineering hiringManagerName: Luke Heath @@ -22,7 +46,7 @@ - πŸš€ Actively participate in all engineering scrum meetings, including sprint planning, daily standups, sprint demos, sprint retrospectives, and estimation sessions. - 🌟 Contribute to the overall success of the [MDM](https://fleetdm.com/handbook/company/product-groups#mdm-group) product group by ensuring users receive valuable new features. experience: | - - πŸ’­ 3-5 years' of experience in backend/SaaS development. + - πŸ’­ 3-5 years of experience in backend/SaaS development. - πŸ¦‰ Proficient in backend development. You practice OOP design and are comfortable in a lean software development environment. - πŸ¦‰ Translate requirements into well-designed and functional software. - 🀝 Communicate regularly with stakeholders, project managers, quality assurance teams, and other developers regarding progress on long-term technology roadmap. @@ -36,3 +60,4 @@ - πŸ› οΈ Technical: You understand the software development processes. You understand that software quality matters. - 🟣 Openness: You are flexible and open to new ideas and ways of working. - βž• Bonus: Cybersecurity or IT background. +