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/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/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; } 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. diff --git a/handbook/company/open-positions.yml b/handbook/company/open-positions.yml index 36eb7e05df..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,35 +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. - -- 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. + 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 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 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() { 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({ 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 29347073c0..c00066c408 100644 Binary files a/website/assets/images/cta-thumbnail-psystage-4-has-use-case-128x128@2x.png and b/website/assets/images/cta-thumbnail-psystage-4-has-use-case-128x128@2x.png differ 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/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 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
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.