From 13e5e14a2f98059c903bf0770d6d4921d2d62729 Mon Sep 17 00:00:00 2001 From: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:03:10 -0500 Subject: [PATCH 01/88] Update UI to allow for showing software install details from activities related to deleted hosts (#20866) --- .../AppInstallDetails/AppInstallDetails.tsx | 11 ++++-- .../SoftwareInstallDetails.tsx | 37 +++++++++++++------ .../cards/ActivityFeed/ActivityFeed.tsx | 16 ++++---- .../HostDetailsPage/HostDetailsPage.tsx | 18 ++++++--- .../SoftwareDetailsModal.tsx | 3 +- 5 files changed, 57 insertions(+), 28 deletions(-) diff --git a/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx b/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx index c4991f0fd7..dd1de5a727 100644 --- a/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx +++ b/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx @@ -90,6 +90,12 @@ export const AppInstallDetails = ({ subordinate = status === "pending" ? " when it comes online" : ""; } + const formattedHost = host_display_name ? ( + {host_display_name} + ) : ( + "the host" + ); + const showCommandResponse = isStatusNotNow || status !== "pending"; return ( @@ -98,8 +104,7 @@ export const AppInstallDetails = ({
{!!iconName && } - Fleet {predicate} {software_title} on{" "} - {host_display_name} + Fleet {predicate} {software_title} on {formattedHost} {subordinate}.
@@ -111,7 +116,7 @@ export const AppInstallDetails = ({ {showCommandResponse && (
- The response from {host_display_name}: + The response from {formattedHost}: diff --git a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/SoftwareInstallDetails.tsx b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/SoftwareInstallDetails.tsx index 27480cd8e5..61c2d5f04f 100644 --- a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/SoftwareInstallDetails.tsx +++ b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/SoftwareInstallDetails.tsx @@ -1,6 +1,7 @@ import React from "react"; import { useQuery } from "react-query"; +import { IActivityDetails } from "interfaces/activity"; import { ISoftwareInstallResult, ISoftwareInstallResults, @@ -21,17 +22,28 @@ import { const baseClass = "software-install-details"; +// TODO: Expand to include more details as needed +export type IPackageInstallDetails = Pick< + IActivityDetails, + "install_uuid" | "host_display_name" +>; + const StatusMessage = ({ result: { host_display_name, software_package, software_title, status }, }: { result: ISoftwareInstallResult; }) => { + const formattedHost = host_display_name ? ( + {host_display_name} + ) : ( + "the host" + ); return (
Fleet {getInstallDetailsStatusPredicate(status)} {software_title}{" "} - ({software_package}) on {host_display_name} + ({software_package}) on {formattedHost} {status === "pending" ? " when it comes online" : ""}.
@@ -56,18 +68,17 @@ const Output = ({ }; export const SoftwareInstallDetails = ({ - installUuid, -}: { - installUuid: string; -}) => { + host_display_name = "", + install_uuid = "", +}: IPackageInstallDetails) => { const { data: result, isLoading, isError } = useQuery< ISoftwareInstallResults, Error, ISoftwareInstallResult >( - ["softwareInstallResults", installUuid], + ["softwareInstallResults", install_uuid], () => { - return softwareAPI.getSoftwareInstallResult(installUuid); + return softwareAPI.getSoftwareInstallResult(install_uuid); }, { refetchOnWindowFocus: false, @@ -88,7 +99,11 @@ export const SoftwareInstallDetails = ({ return ( <>
- + {result.status !== "pending" && ( <> {result.pre_install_query_output && ( @@ -106,10 +121,10 @@ export const SoftwareInstallDetails = ({ }; export const SoftwareInstallDetailsModal = ({ - installUuid, + details, onCancel, }: { - installUuid: string; + details: IPackageInstallDetails; onCancel: () => void; }) => { return ( @@ -121,7 +136,7 @@ export const SoftwareInstallDetailsModal = ({ > <>
- +
)} {!!host && showPolicyDetailsModal && ( diff --git a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/ResetKeyModal.tsx b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/ResetKeyModal.tsx deleted file mode 100644 index e9fe2b3f05..0000000000 --- a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/ResetKeyModal.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from "react"; - -import Button from "components/buttons/Button"; -import Modal from "components/Modal"; -import mdmAPI from "services/entities/mdm"; -import { useQuery } from "react-query"; -import Spinner from "components/Spinner"; -import DataError from "components/DataError"; - -interface IResetKeyModalProps { - onClose: () => void; - deviceAuthToken: string; -} - -const baseClass = "reset-key-modal"; - -const ResetKeyModal = ({ - onClose, - deviceAuthToken, -}: IResetKeyModalProps): JSX.Element => { - const { isLoading: isLoadingResetDEKey, error: errorResetDEKey } = useQuery( - ["resetDEkey", deviceAuthToken], - () => mdmAPI.resetEncryptionKey(deviceAuthToken), - { refetchOnWindowFocus: false } - ); - - const renderModalBody = () => { - if (isLoadingResetDEKey) { - return ; - } - if (errorResetDEKey) { - return ; - } - - return ( -
-
    -
  1. - Wait 30 seconds for the Reset disk encryption key pop up to - open. -
  2. -
  3. - In the popup, enter the password you use to login to your Mac. -
  4. -
  5. - Close this window and select Refetch on your My device page. - This tells your organization that you reset your key. -
  6. -
-
- -
-
- ); - }; - return ( - - {renderModalBody()} - - ); -}; - -export default ResetKeyModal; diff --git a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/_styles.scss deleted file mode 100644 index f40c1f1c1d..0000000000 --- a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/_styles.scss +++ /dev/null @@ -1,10 +0,0 @@ -.reset-key-modal { - ol { - padding-left: 0; - } - - li { - margin-bottom: $pad-large; - list-style: number inside; - } -} diff --git a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/index.ts b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/index.ts deleted file mode 100644 index 3cd713ee62..0000000000 --- a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./ResetKeyModal"; diff --git a/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tests.tsx b/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tests.tsx index dc7a052653..cd3f28c01b 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tests.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tests.tsx @@ -6,8 +6,7 @@ import DeviceUserBanners from "./DeviceUserBanners"; describe("Device User Banners", () => { const turnOnMdmExpcetedText = /Mobile device management \(MDM\) is off\./; - const logoutDiskEncryptExpectedText = /Disk encryption: Log out of your device or restart to turn on disk encryption\./; - const resetKeyDiskEncryptExpcetedText = /Disk encryption: Reset your disk encryption key\./; + const resetKeyDiskEncryptExpcetedText = /Disk encryption: Log out of your device or restart it to safeguard your data in case your device is lost or stolen\./; it("renders the turn on mdm banner correctly", () => { render( @@ -19,28 +18,11 @@ describe("Device User Banners", () => { diskEncryptionStatus={null} diskEncryptionActionRequired={null} onTurnOnMdm={noop} - onResetKey={noop} /> ); expect(screen.getByText(turnOnMdmExpcetedText)).toBeInTheDocument(); }); - it("renders the logout for disk encrpytion banner correctly", () => { - render( - - ); - expect(screen.getByText(logoutDiskEncryptExpectedText)).toBeInTheDocument(); - }); - it("renders the reset key for disk encryption banner correctly", () => { render( { diskEncryptionStatus="action_required" diskEncryptionActionRequired="rotate_key" onTurnOnMdm={noop} - onResetKey={noop} /> ); expect( @@ -59,28 +40,6 @@ describe("Device User Banners", () => { ).toBeInTheDocument(); }); - it("renders only one banner in a priority order", () => { - // set up to render logout disk encryption banner, which is 2nd in priority - render( - - ); - - expect(screen.queryByText(turnOnMdmExpcetedText)).not.toBeInTheDocument(); - expect(screen.getByText(logoutDiskEncryptExpectedText)).toBeInTheDocument(); - expect( - screen.queryByText(resetKeyDiskEncryptExpcetedText) - ).not.toBeInTheDocument(); - }); - it("renders no banner correctly", () => { // setup so mdm is not enabled and configured. render( @@ -92,13 +51,12 @@ describe("Device User Banners", () => { diskEncryptionStatus={null} diskEncryptionActionRequired={null} onTurnOnMdm={noop} - onResetKey={noop} /> ); expect(screen.queryByText(turnOnMdmExpcetedText)).not.toBeInTheDocument(); expect( - screen.queryByText(logoutDiskEncryptExpectedText) + screen.queryByText(resetKeyDiskEncryptExpcetedText) ).not.toBeInTheDocument(); expect( screen.queryByText(resetKeyDiskEncryptExpcetedText) diff --git a/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx b/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx index 9cc5e3256a..028165648f 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx @@ -15,7 +15,6 @@ interface IDeviceUserBannersProps { diskEncryptionStatus: DiskEncryptionStatus | null; diskEncryptionActionRequired: MacDiskEncryptionActionRequired | null; onTurnOnMdm: () => void; - onResetKey: () => void; } const DeviceUserBanners = ({ @@ -26,7 +25,6 @@ const DeviceUserBanners = ({ diskEncryptionStatus, diskEncryptionActionRequired, onTurnOnMdm, - onResetKey, }: IDeviceUserBannersProps) => { const isMdmUnenrolled = mdmEnrollmentStatus === "Off" || mdmEnrollmentStatus === null; @@ -37,11 +35,6 @@ const DeviceUserBanners = ({ const showTurnOnMdmBanner = hostPlatform === "darwin" && isMdmUnenrolled && mdmEnabledAndConfigured; - const showDiskEncryptionLogoutRestart = - diskEncryptionBannersEnabled && - diskEncryptionStatus === "action_required" && - diskEncryptionActionRequired === "log_out"; - const showDiskEncryptionKeyResetRequired = diskEncryptionBannersEnabled && diskEncryptionStatus === "action_required" && @@ -53,12 +46,6 @@ const DeviceUserBanners = ({ ); - const resetKeyButton = ( - - ); - const renderBanner = () => { if (showTurnOnMdmBanner) { return ( @@ -68,19 +55,14 @@ const DeviceUserBanners = ({ your device up to date so you don't have to. ); - } else if (showDiskEncryptionLogoutRestart) { + } + + if (showDiskEncryptionKeyResetRequired) { return ( - Disk encryption: Log out of your device or restart to turn on disk - encryption. Then, select Refetch. This prevents - unauthorized access to the information on your device. - - ); - } else if (showDiskEncryptionKeyResetRequired) { - return ( - - Disk encryption: Reset your disk encryption key. This lets your - organization help you unlock your device if you forget your password. + Disk encryption: Log out of your device or restart it to safeguard + your data in case your device is lost or stolen. After, select{" "} + Refetch to clear this banner. ); } diff --git a/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx b/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx index ea3110af9b..89632164b0 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx @@ -79,8 +79,7 @@ const HostDetailsBanners = ({ {showDiskEncryptionUserActionRequired && ( Disk encryption: Requires action from the end user. Ask the end user - to follow Disk encryption instructions on their{" "} - My device page. + to log out of their device or restart it. )}
diff --git a/frontend/services/entities/mdm.ts b/frontend/services/entities/mdm.ts index a5b7409922..f8cae4461f 100644 --- a/frontend/services/entities/mdm.ts +++ b/frontend/services/entities/mdm.ts @@ -83,10 +83,6 @@ export interface IGetMdmCommandResultsResponse { } const mdmService = { - resetEncryptionKey: (token: string) => { - const { DEVICE_USER_RESET_ENCRYPTION_KEY } = endpoints; - return sendRequest("POST", DEVICE_USER_RESET_ENCRYPTION_KEY(token)); - }, unenrollHostFromMdm: (hostId: number, timeout?: number) => { const { HOST_MDM_UNENROLL } = endpoints; return sendRequest( diff --git a/frontend/utilities/endpoints.ts b/frontend/utilities/endpoints.ts index 235029bf70..92553ada42 100644 --- a/frontend/utilities/endpoints.ts +++ b/frontend/utilities/endpoints.ts @@ -31,9 +31,6 @@ export default { `/${API_VERSION}/fleet/device/${token}/software`, DEVICE_SOFTWARE_INSTALL: (token: string, softwareTitleId: number) => `/${API_VERSION}/fleet/device/${token}/software/install/${softwareTitleId}`, - DEVICE_USER_RESET_ENCRYPTION_KEY: (token: string): string => { - return `/${API_VERSION}/fleet/device/${token}/rotate_encryption_key`; - }, DEVICE_USER_MDM_ENROLLMENT_PROFILE: (token: string): string => { return `/${API_VERSION}/fleet/device/${token}/mdm/apple/manual_enrollment_profile`; }, From fbf1f553992d0b8b895d0af73cf3cc0be94ac3d9 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 31 Jul 2024 14:50:42 -0500 Subject: [PATCH 10/88] Website: Remove duplicate "Fleet" from page titles (#20893) Changes: - Removed the duplicate "Fleet" from page titles. --- .../api/controllers/articles/view-articles.js | 18 ++++----- .../articles/view-basic-article.js | 2 +- .../docs/view-basic-documentation.js | 2 +- .../handbook/view-basic-handbook.js | 2 +- website/api/controllers/view-query-detail.js | 2 +- website/config/routes.js | 38 +++++++++---------- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/website/api/controllers/articles/view-articles.js b/website/api/controllers/articles/view-articles.js index f8b685a8eb..8f28c6c5c4 100644 --- a/website/api/controllers/articles/view-articles.js +++ b/website/api/controllers/articles/view-articles.js @@ -50,7 +50,7 @@ module.exports = { }); } - let pageTitleForMeta = 'Fleet blog | Fleet'; + let pageTitleForMeta = 'Fleet blog'; let pageDescriptionForMeta = 'Read the latest articles written by Fleet.'; // Create a currentSection variable, this will be used to highlight the header dropdown that this article category lives under. // There are three possible values for this (documentation, community, and platform), so we'll default to the one with the most article categories (community) and set the value to another section if needed. @@ -60,39 +60,39 @@ module.exports = { // Set a pageTitleForMeta, pageDescriptionForMeta, and currentSection variable based on the article category. switch(category) { case 'success-stories': - pageTitleForMeta = 'Success stories | Fleet'; + pageTitleForMeta = 'Success stories'; pageDescriptionForMeta = 'Read about how others are using Fleet and osquery.'; currentSection = 'platform'; break; case 'deploy': - pageTitleForMeta = 'Deployment guides | Fleet'; + pageTitleForMeta = 'Deployment guides'; pageDescriptionForMeta = 'Learn how to deploy Fleet on a variety of production environments.'; currentSection = 'documentation'; break; case 'releases': - pageTitleForMeta = 'Releases | Fleet'; + pageTitleForMeta = 'Releases'; pageDescriptionForMeta = 'Fleet releases new and updated features every three weeks. Read about the latest product improvements here.'; currentSection = 'documentation'; break; case 'guides': - pageTitleForMeta = 'Guides | Fleet'; + pageTitleForMeta = 'Guides'; pageDescriptionForMeta = 'A collection of how-to guides for Fleet and osquery.'; currentSection = 'documentation'; break; case 'securing': - pageTitleForMeta = 'Security articles | Fleet'; + pageTitleForMeta = 'Security articles'; pageDescriptionForMeta = 'Learn more about how we secure Fleet.'; break; case 'engineering': - pageTitleForMeta = 'Engineering articles | Fleet'; + pageTitleForMeta = 'Engineering articles'; pageDescriptionForMeta = 'Read about engineering at Fleet and beyond.'; break; case 'announcements': - pageTitleForMeta = 'Announcements | Fleet'; + pageTitleForMeta = 'Announcements'; pageDescriptionForMeta = 'Read the latest news from Fleet.'; break; case 'podcasts': - pageTitleForMeta = 'Podcasts | Fleet'; + pageTitleForMeta = 'Podcasts'; pageDescriptionForMeta = 'Listen to the Future of Device Management podcast.'; break; } diff --git a/website/api/controllers/articles/view-basic-article.js b/website/api/controllers/articles/view-basic-article.js index e7fc38ff83..17b997f5f7 100644 --- a/website/api/controllers/articles/view-basic-article.js +++ b/website/api/controllers/articles/view-basic-article.js @@ -52,7 +52,7 @@ module.exports = { // Note: Leaving title and description as `undefined` in our view means we'll default to the generic title and description set in layout.ejs. let pageTitleForMeta; if(thisPage.meta.articleTitle) { - pageTitleForMeta = thisPage.meta.articleTitle + ' | Fleet'; + pageTitleForMeta = thisPage.meta.articleTitle; }//fi let pageDescriptionForMeta; if(thisPage.meta.description){ diff --git a/website/api/controllers/docs/view-basic-documentation.js b/website/api/controllers/docs/view-basic-documentation.js index 3961775bad..b5d1746e8b 100644 --- a/website/api/controllers/docs/view-basic-documentation.js +++ b/website/api/controllers/docs/view-basic-documentation.js @@ -69,7 +69,7 @@ module.exports = { compiledPagePartialsAppPath: sails.config.builtStaticContent.compiledPagePartialsAppPath, pageTitleForMeta: ( thisPage.title !== 'Readme.md' ? thisPage.title + ' | Fleet documentation'// « custom meta title for this page, if provided in markdown - : 'Documentation | Fleet' // « otherwise we're on the landing page for this section of the site, so we'll follow the title format of other top-level pages + : 'Documentation' // « otherwise we're on the landing page for this section of the site, so we'll follow the title format of other top-level pages ), pageDescriptionForMeta: ( thisPage.meta.description ? thisPage.meta.description // « custom meta description for this page, if provided in markdown diff --git a/website/api/controllers/handbook/view-basic-handbook.js b/website/api/controllers/handbook/view-basic-handbook.js index bd30a469d6..6c9f1b4b01 100644 --- a/website/api/controllers/handbook/view-basic-handbook.js +++ b/website/api/controllers/handbook/view-basic-handbook.js @@ -64,7 +64,7 @@ module.exports = { compiledPagePartialsAppPath: sails.config.builtStaticContent.compiledPagePartialsAppPath, pageTitleForMeta: ( thisPage.title !== 'Readme.md' ? thisPage.title + ' | Fleet handbook'// « custom meta title for this page, if provided in markdown - : 'Handbook | Fleet' // « otherwise we're on the landing page for this section of the site, so we'll follow the title format of other top-level pages + : 'Handbook' // « otherwise we're on the landing page for this section of the site, so we'll follow the title format of other top-level pages ), pageDescriptionForMeta: ( thisPage.meta.description ? thisPage.meta.description // « custom meta description for this page, if provided in markdown diff --git a/website/api/controllers/view-query-detail.js b/website/api/controllers/view-query-detail.js index 3d974034ad..c4f8f51430 100644 --- a/website/api/controllers/view-query-detail.js +++ b/website/api/controllers/view-query-detail.js @@ -35,7 +35,7 @@ module.exports = { } // Setting the meta title and description of this page using the query object, and falling back to a generic title or description if query.name or query.description are missing. - let pageTitleForMeta = query.name ? query.name + ' | Query details' : 'Query details | Fleet'; + let pageTitleForMeta = query.name ? query.name + ' | Query details' : 'Query details'; let pageDescriptionForMeta = query.description ? query.description : 'View more information about a query in Fleet\'s standard query library'; // Respond with view. return { diff --git a/website/config/routes.js b/website/config/routes.js index 8339089831..59b068e650 100644 --- a/website/config/routes.js +++ b/website/config/routes.js @@ -23,7 +23,7 @@ module.exports.routes = { 'GET /contact': { action: 'view-contact', locals: { - pageTitleForMeta: 'Contact us | Fleet', + pageTitleForMeta: 'Contact us', pageDescriptionForMeta: 'Get in touch with our team.', hideFooterLinks: true, } @@ -34,7 +34,7 @@ module.exports.routes = { locals: { hideHeaderLinks: true, hideFooterLinks: true, - pageTitleForMeta: 'fleetctl preview | Fleet', + pageTitleForMeta: 'fleetctl preview', pageDescriptionForMeta: 'Learn about getting started with Fleet using fleetctl.' } }, @@ -43,7 +43,7 @@ module.exports.routes = { action: 'view-pricing', locals: { currentSection: 'pricing', - pageTitleForMeta: 'Pricing | Fleet', + pageTitleForMeta: 'Pricing', pageDescriptionForMeta: 'Use Fleet for free or get started with Fleet Premium (self-hosted or managed cloud). Have a large deployment? We\'ve got you covered.' } }, @@ -51,7 +51,7 @@ module.exports.routes = { 'GET /logos': { action: 'view-press-kit', locals: { - pageTitleForMeta: 'Logos | Fleet', + pageTitleForMeta: 'Logos', pageDescriptionForMeta: 'Download Fleet logos, wallpapers, and screenshots.' } }, @@ -60,7 +60,7 @@ module.exports.routes = { action: 'view-query-library', locals: { currentSection: 'documentation', - pageTitleForMeta: 'Queries | Fleet', + pageTitleForMeta: 'Queries', pageDescriptionForMeta: 'A growing collection of useful queries for organizations deploying Fleet and osquery.' } }, @@ -106,7 +106,7 @@ module.exports.routes = { hideHeaderLinks: true, hideFooterLinks: true, hideStartCTA: true, - pageTitleForMeta: 'Get Fleet Premium | Fleet', + pageTitleForMeta: 'Get Fleet Premium', pageDescriptionForMeta: 'Generate your quote and start using Fleet Premium today.', } }, @@ -114,7 +114,7 @@ module.exports.routes = { action: 'entrance/view-signup', locals: { hideFooterLinks: true, - pageTitleForMeta: 'Sign up | Fleet', + pageTitleForMeta: 'Sign up', pageDescriptionForMeta: 'Sign up for a Fleet account.', } }, @@ -122,7 +122,7 @@ module.exports.routes = { action: 'entrance/view-login', locals: { hideFooterLinks: true, - pageTitleForMeta: 'Log in | Fleet', + pageTitleForMeta: 'Log in', pageDescriptionForMeta: 'Log in to Fleet.', } }, @@ -132,7 +132,7 @@ module.exports.routes = { hideHeaderLinks: true, hideFooterLinks: true, hideStartCTA: true, - pageTitleForMeta: 'Customer dashboard | Fleet', + pageTitleForMeta: 'Customer dashboard', pageDescriptionForMeta: 'View and edit information about your Fleet Premium license.', } }, @@ -142,7 +142,7 @@ module.exports.routes = { hideHeaderLinks: true, hideFooterLinks: true, hideStartCTA: true, - pageTitleForMeta: 'Forgot password | Fleet', + pageTitleForMeta: 'Forgot password', pageDescriptionForMeta: 'Recover the password for your Fleet customer account.', } }, @@ -152,7 +152,7 @@ module.exports.routes = { hideHeaderLinks: true, hideFooterLinks: true, hideStartCTA: true, - pageTitleForMeta: 'New password | Fleet', + pageTitleForMeta: 'New password', pageDescriptionForMeta: 'Change the password for your Fleet customer account.', } }, @@ -160,7 +160,7 @@ module.exports.routes = { 'GET /reports/state-of-device-management': { action: 'reports/view-state-of-device-management', locals: { - pageTitleForMeta: 'State of device management | Fleet', + pageTitleForMeta: 'State of device management', pageDescriptionForMeta: 'We surveyed 200+ security practitioners to discover the state of device management in 2022. Click here to learn about their struggles and best practices.', } }, @@ -221,7 +221,7 @@ module.exports.routes = { 'GET /device-management': { action: 'view-device-management', locals: { - pageTitleForMeta: 'Device management (MDM) | Fleet', + pageTitleForMeta: 'Device management (MDM)', pageDescriptionForMeta: 'Manage your devices in any browser or use git to make changes as code.', currentSection: 'platform', } @@ -230,7 +230,7 @@ module.exports.routes = { 'GET /endpoint-ops': { action: 'view-endpoint-ops', locals: { - pageTitleForMeta: 'Endpoint ops | Fleet', + pageTitleForMeta: 'Endpoint ops', pageDescriptionForMeta: 'Pulse check anything, build reports, and ship data to any platform with Fleet.', currentSection: 'platform', } @@ -239,7 +239,7 @@ module.exports.routes = { 'GET /vulnerability-management': { action: 'view-vulnerability-management', locals: { - pageTitleForMeta: 'Vulnerability management | Fleet', + pageTitleForMeta: 'Vulnerability management', pageDescriptionForMeta: 'Report CVEs, software inventory, security posture, and other risks down to the chipset of any endpoint with Fleet.', currentSection: 'platform', } @@ -248,7 +248,7 @@ module.exports.routes = { 'GET /support': { action: 'view-support', locals: { - pageTitleForMeta: 'Support | Fleet', + pageTitleForMeta: 'Support', pageDescriptionForMeta: 'Ask a question, chat with engineers, or get in touch with the Fleet team.', currentSection: 'documentation', } @@ -257,7 +257,7 @@ module.exports.routes = { 'GET /integrations': { action: 'view-integrations', locals: { - pageTitleForMeta: 'Integrations | Fleet', + pageTitleForMeta: 'Integrations', pageDescriptionForMeta: 'Integrate IT ticketing systems, SIEM and SOAR platforms, custom IT workflows, and more.', currentSection: 'platform' } @@ -269,7 +269,7 @@ module.exports.routes = { hideFooterLinks: true, hideGetStartedButton: true, hideStartCTA: true, - pageTitleForMeta: 'Start | Fleet', + pageTitleForMeta: 'Start', pageDescriptionForMeta: 'Get Started with Fleet. Spin up a local demo or get your Premium license key.', } }, @@ -278,7 +278,7 @@ module.exports.routes = { action: 'view-transparency', locals: { pageDescriptionForMeta: 'Discover how Fleet simplifies IT and security, prioritizing privacy, transparency, and trust for end users.', - pageTitleForMeta: 'Better with Fleet | Fleet' + pageTitleForMeta: 'Better with Fleet' } }, From 7a080a9b36aa1c30773478868c1d5f05a58472d6 Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Wed, 31 Jul 2024 16:59:30 -0300 Subject: [PATCH 11/88] use Escrow Buddy to rotate FileVault keys on macOS (#20842) back-end and agent part of #13157 # 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] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated tests - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)). --- Makefile | 8 + changes/13157-fv-escrow | 1 + ee/fleetctl/updates.go | 2 + ee/server/service/devices.go | 4 - orbit/changes/13157-fv-escrow | 1 + orbit/cmd/orbit/orbit.go | 6 +- orbit/pkg/update/escrow_buddy.go | 120 +++++++++++++++ orbit/pkg/update/escrow_buddy_test.go | 86 +++++++++++ orbit/pkg/update/options.go | 6 + orbit/pkg/update/testing_utils.go | 1 + orbit/pkg/update/update.go | 14 ++ server/datastore/mysql/hosts.go | 15 -- server/datastore/mysql/hosts_test.go | 9 +- server/fleet/capabilities.go | 3 + server/fleet/datastore.go | 2 - server/fleet/hosts.go | 26 +--- server/fleet/hosts_test.go | 44 ------ server/fleet/service.go | 2 - server/mock/datastore_mock.go | 12 -- server/service/devices.go | 35 ----- server/service/handler.go | 4 - server/service/hosts_test.go | 195 ++++++++++++++++++++++++- server/service/integration_mdm_test.go | 32 +--- server/service/orbit.go | 78 ++++++++-- tools/tuf/README.md | 13 ++ tools/tuf/test/create_repository.sh | 17 ++- 26 files changed, 537 insertions(+), 199 deletions(-) create mode 100644 changes/13157-fv-escrow create mode 100644 orbit/changes/13157-fv-escrow create mode 100644 orbit/pkg/update/escrow_buddy.go create mode 100644 orbit/pkg/update/escrow_buddy_test.go diff --git a/Makefile b/Makefile index 8f7cf455d5..2e7c317baa 100644 --- a/Makefile +++ b/Makefile @@ -424,6 +424,14 @@ endif tar czf $(out-path)/swiftDialog.app.tar.gz -C $(TMP_DIR)/swiftDialog_pkg_payload_expanded/Library/Application\ Support/Dialog/ Dialog.app rm -rf $(TMP_DIR) +# Generate escrowBuddy.pkg bundle from the Escrow Buddy repo. +# +# Usage: +# make escrow-buddy-pkg version=1.0.0 out-path=. +escrow-buddy-pkg: + curl -L https://github.com/macadmins/escrow-buddy/releases/download/v$(version)/Escrow.Buddy-$(version).pkg --output $(out-path)/escrowBuddy.pkg + + # Build and generate desktop.app.tar.gz bundle. # # Usage: diff --git a/changes/13157-fv-escrow b/changes/13157-fv-escrow new file mode 100644 index 0000000000..e6804a05ec --- /dev/null +++ b/changes/13157-fv-escrow @@ -0,0 +1 @@ +* `fleetd` now uses Escrow Buddy to rotate FileVault keys. Internal API endpoints documented in the API for contributors have been modified and/or removed. diff --git a/ee/fleetctl/updates.go b/ee/fleetctl/updates.go index 8ef04ef1f6..2e55081fa4 100644 --- a/ee/fleetctl/updates.go +++ b/ee/fleetctl/updates.go @@ -270,6 +270,8 @@ func updatesAddFunc(c *cli.Context) error { dstPath += ".exe" case strings.HasSuffix(target, ".app.tar.gz"): dstPath += ".app.tar.gz" + case strings.HasSuffix(target, ".pkg"): + dstPath += ".pkg" // osquery extensions require the .ext suffix case strings.HasSuffix(target, ".ext"): dstPath += ".ext" diff --git a/ee/server/service/devices.go b/ee/server/service/devices.go index 4208ee15c5..590067e916 100644 --- a/ee/server/service/devices.go +++ b/ee/server/service/devices.go @@ -17,10 +17,6 @@ func (svc *Service) ListDevicePolicies(ctx context.Context, host *fleet.Host) ([ return svc.ds.ListPoliciesForHost(ctx, host) } -func (svc *Service) RequestEncryptionKeyRotation(ctx context.Context, hostID uint) error { - return svc.ds.SetDiskEncryptionResetStatus(ctx, hostID, true) -} - const refetchMDMUnenrollCriticalQueryDuration = 3 * time.Minute // TriggerMigrateMDMDevice triggers the webhook associated with the MDM diff --git a/orbit/changes/13157-fv-escrow b/orbit/changes/13157-fv-escrow new file mode 100644 index 0000000000..b4ff408b05 --- /dev/null +++ b/orbit/changes/13157-fv-escrow @@ -0,0 +1 @@ +* Use Escrow Buddy to rotate FileVault keys on macOS diff --git a/orbit/cmd/orbit/orbit.go b/orbit/cmd/orbit/orbit.go index cf24f3c0ef..d124a47d57 100644 --- a/orbit/cmd/orbit/orbit.go +++ b/orbit/cmd/orbit/orbit.go @@ -870,7 +870,11 @@ func main() { orbitClient.RegisterConfigReceiver(update.ApplyNudgeConfigReceiverMiddleware(update.NudgeConfigFetcherOptions{ UpdateRunner: updateRunner, RootDir: c.String("root-dir"), Interval: nudgeLaunchInterval, })) - orbitClient.RegisterConfigReceiver(update.ApplyDiskEncryptionRunnerMiddleware()) + if orbitClient.GetServerCapabilities().Has(fleet.CapabilityEscrowBuddy) { + orbitClient.RegisterConfigReceiver(update.NewEscrowBuddyRunner(updateRunner, 5*time.Minute)) + } else { + orbitClient.RegisterConfigReceiver(update.ApplyDiskEncryptionRunnerMiddleware()) + } orbitClient.RegisterConfigReceiver(update.ApplySwiftDialogDownloaderMiddleware(updateRunner)) case "windows": orbitClient.RegisterConfigReceiver(update.ApplyWindowsMDMEnrollmentFetcherMiddleware(windowsMDMEnrollmentCommandFrequency, orbitHostInfo.HardwareUUID, orbitClient)) diff --git a/orbit/pkg/update/escrow_buddy.go b/orbit/pkg/update/escrow_buddy.go new file mode 100644 index 0000000000..72ef1fab5a --- /dev/null +++ b/orbit/pkg/update/escrow_buddy.go @@ -0,0 +1,120 @@ +package update + +import ( + "fmt" + "sync" + "time" + + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/rs/zerolog/log" +) + +// EscrowBuddyRunner sets up [Escrow Buddy][1] to rotate FileVault keys on +// macOS without user interaction. This runner: +// +// - Ensures Escrow Buddy is added as a target for the update runner, so the +// authorization plugin is downloaded and installed. +// - Shells out to call `defaults` to configure Escrow Buddy according to +// server instructions provided via notifications. +// +// [1]: https://github.com/macadmins/escrow-buddy +type EscrowBuddyRunner struct { + // updateRunner is the wrapped Runner where Escrow Buddy will be set as + // a target. + updateRunner *Runner + // runCmdFunc can be set in tests to mock the command executed to + // configure Escrow Buddy + runCmdFunc func(cmd string, args ...string) error + // runMu guards runs to prevent multiple Run calls happening at the + // same time. + runMu sync.Mutex + // lastRun is used to guarantee that the run interval is enforced + lastRun time.Time + // interval defines how often Run is allowed to perform work + interval time.Duration +} + +// NewEscrowBuddyRunner returns a new instance configured with the provided values +func NewEscrowBuddyRunner(runner *Runner, interval time.Duration) fleet.OrbitConfigReceiver { + return &EscrowBuddyRunner{updateRunner: runner, interval: interval} +} + +func (e *EscrowBuddyRunner) Run(cfg *fleet.OrbitConfig) error { + log.Debug().Msgf("EscrowBuddyRunner: notification: %t", cfg.Notifications.RotateDiskEncryptionKey) + + if e.updateRunner == nil { + log.Debug().Msg("EscrowBuddyRunner: received nil UpdateRunner, this probably indicates that updates are turned off. Skipping any actions related to Disk encryption") + return nil + } + + if !e.runMu.TryLock() { + log.Debug().Msg("EscrowBuddyRunner: a previous instance is currently running, returning early") + return nil + } + + defer e.runMu.Unlock() + if time.Since(e.lastRun) < e.interval { + log.Debug().Msgf("EscrowBuddyRunner: last run (%v) is less than the configured interval (%v), returning early", e.lastRun, e.interval) + return nil + } + + updaterHasTarget := e.updateRunner.HasRunnerOptTarget("escrowBuddy") + // if the notification is false, it could mean that we shouldn't do + // anything at all (eg: MDM is not configured) or that this host + // doesn't need to rotate the key. + // + // if Escrow Buddy is a TUF target, it means that we tried to rotate + // the key before, and we must disable it to keep the local state as + // instructed by the server. + if !cfg.Notifications.RotateDiskEncryptionKey { + if updaterHasTarget { + log.Debug().Msg("EscrowBuddyRunner: disabling disk encryption rotation") + e.lastRun = time.Now() + return e.setGenerateNewKeyTo(false) + } + + log.Debug().Msg("EscrowBuddyRunner: skipping any actions related to disk encryption") + return nil + } + + runnerHasLocalHash := e.updateRunner.HasLocalHash("escrowBuddy") + if !updaterHasTarget || !runnerHasLocalHash { + log.Info().Msg("refreshing the update runner config with Escrow Buddy targets and hashes") + log.Debug().Msgf("updater has target: %t, runner has local hash: %t", updaterHasTarget, runnerHasLocalHash) + if err := e.setTargetsAndHashes(); err != nil { + return fmt.Errorf("setting Escrow Buddy targets and hashes: %w", err) + } + } + + log.Debug().Msg("EscrowBuddyRunner: enabling disk encryption rotation") + if err := e.setGenerateNewKeyTo(true); err != nil { + return fmt.Errorf("enabling disk encryption rotation: %w", err) + } + + e.lastRun = time.Now() + return nil +} + +func (e *EscrowBuddyRunner) setTargetsAndHashes() error { + e.updateRunner.AddRunnerOptTarget("escrowBuddy") + e.updateRunner.updater.SetTargetInfo("escrowBuddy", EscrowBuddyMacOSTarget) + // we don't want to keep escrowBuddy as a target if we failed to update the + // cached hashes in the runner. + if err := e.updateRunner.StoreLocalHash("escrowBuddy"); err != nil { + log.Debug().Msgf("removing escrowBuddy from target options, error updating local hashes: %s", err) + e.updateRunner.RemoveRunnerOptTarget("escrowBuddy") + e.updateRunner.updater.RemoveTargetInfo("escrowBuddy") + return err + } + return nil +} + +func (e *EscrowBuddyRunner) setGenerateNewKeyTo(enabled bool) error { + log.Debug().Msgf("running defaults write to configure Escrow Buddy with value %t", enabled) + cmd := fmt.Sprintf("defaults write /Library/Preferences/com.netflix.Escrow-Buddy.plist GenerateNewKey -bool %t", enabled) + fn := e.runCmdFunc + if fn == nil { + fn = runCmdCollectErr + } + return fn("sh", "-c", cmd) +} diff --git a/orbit/pkg/update/escrow_buddy_test.go b/orbit/pkg/update/escrow_buddy_test.go new file mode 100644 index 0000000000..0ed61883b0 --- /dev/null +++ b/orbit/pkg/update/escrow_buddy_test.go @@ -0,0 +1,86 @@ +package update + +import ( + "testing" + "time" + + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +func TestEscrowBuddy(t *testing.T) { + testingSuite := new(escrowBuddyTestSuite) + testingSuite.s = &testingSuite.Suite + suite.Run(t, testingSuite) +} + +type escrowBuddyTestSuite struct { + suite.Suite + withTUF +} + +func (s *escrowBuddyTestSuite) TestUpdatesDisabled() { + t := s.T() + cfg := &fleet.OrbitConfig{} + cfg.Notifications.RotateDiskEncryptionKey = true + r := NewEscrowBuddyRunner(nil, time.Second) + err := r.Run(cfg) + require.NoError(t, err) +} + +func (s *escrowBuddyTestSuite) TestEscrowBuddyRotatesKey() { + t := s.T() + updater := &Updater{ + client: s.client, + opt: Options{Targets: make(map[string]TargetInfo), RootDirectory: t.TempDir()}, + } + runner := &Runner{updater: updater, localHashes: make(map[string][]byte)} + escrowBuddyPath := "escrowBuddy/macos/stable/escrowBuddy.pkg" + + cfg := &fleet.OrbitConfig{} + r := &EscrowBuddyRunner{updateRunner: runner, interval: time.Millisecond} + // mock the command to run the defaults cli + cmdCalls := []map[string]any{} + r.runCmdFunc = func(cmd string, args ...string) error { + cmdCalls = append(cmdCalls, map[string]any{"cmd": cmd, "args": args}) + return nil + } + + // no new target added if the notification is not set + err := r.Run(cfg) + require.NoError(t, err) + targets := runner.updater.opt.Targets + require.Len(t, targets, 0) + require.Empty(t, cmdCalls) + + // there's an error when the remote repo doesn't have the target yet + cfg.Notifications.RotateDiskEncryptionKey = true + err = r.Run(cfg) + require.ErrorContains(t, err, "tuf: file not found") + require.Empty(t, cmdCalls) + + // add escrow buddy to the remote + s.addRemoteTarget(escrowBuddyPath) + + err = r.Run(cfg) + require.NoError(t, err) + require.Len(t, cmdCalls, 1) + require.Equal(t, cmdCalls[0]["cmd"], "sh") + require.Equal(t, cmdCalls[0]["args"], []string{"-c", "defaults write /Library/Preferences/com.netflix.Escrow-Buddy.plist GenerateNewKey -bool true"}) + + targets = runner.updater.opt.Targets + require.Len(t, targets, 1) + ti, ok := targets["escrowBuddy"] + require.True(t, ok) + require.EqualValues(t, EscrowBuddyMacOSTarget, ti) + + time.Sleep(3 * time.Millisecond) + cfg.Notifications.RotateDiskEncryptionKey = false + err = r.Run(cfg) + require.NoError(t, err) + require.Len(t, cmdCalls, 2) + require.Equal(t, cmdCalls[1]["cmd"], "sh") + require.Equal(t, cmdCalls[1]["args"], []string{"-c", "defaults write /Library/Preferences/com.netflix.Escrow-Buddy.plist GenerateNewKey -bool false"}) + +} diff --git a/orbit/pkg/update/options.go b/orbit/pkg/update/options.go index 90cdcaf62a..ed04f5a10b 100644 --- a/orbit/pkg/update/options.go +++ b/orbit/pkg/update/options.go @@ -122,4 +122,10 @@ var ( TargetFile: "swiftDialog.app.tar.gz", ExtractedExecSubPath: []string{"Dialog.app", "Contents", "MacOS", "Dialog"}, } + + EscrowBuddyMacOSTarget = TargetInfo{ + Platform: "macos", + Channel: "stable", + TargetFile: "escrowBuddy.pkg", + } ) diff --git a/orbit/pkg/update/testing_utils.go b/orbit/pkg/update/testing_utils.go index 53c943f2c8..83698e240e 100644 --- a/orbit/pkg/update/testing_utils.go +++ b/orbit/pkg/update/testing_utils.go @@ -85,6 +85,7 @@ func (ts *withTUF) SetupSuite() { ts.mockFiles = map[string][]byte{ "nudge/macos/stable/nudge.app.tar.gz": ts.memTarGz("/Nudge.app/Contents/MacOS/Nudge", "nudge"), "osqueryd/macos/stable/osqueryd.app.tar.gz": ts.memTarGz("osqueryd", "osqueryd"), + "escrowBuddy/macos/stable/escrowBuddy.pkg": {}, } ts.store = tuf.MemoryStore(nil, ts.mockFiles) diff --git a/orbit/pkg/update/update.go b/orbit/pkg/update/update.go index c6b00df89e..f9bee2413f 100644 --- a/orbit/pkg/update/update.go +++ b/orbit/pkg/update/update.go @@ -384,6 +384,12 @@ func (u *Updater) get(target string) (*LocalTarget, error) { return nil, fmt.Errorf("failed to remove old extracted dir: %q: %w", localTarget.DirPath, err) } } + if strings.HasSuffix(localTarget.Path, ".pkg") { + cmd := exec.Command("installer", "-pkg", localTarget.Path, "-target", "/") + if out, err := cmd.CombinedOutput(); err != nil { + return nil, fmt.Errorf("running pkgutil to install %s: %s: %w", localTarget.Path, string(out), err) + } + } } else { log.Debug().Str("path", localTarget.Path).Str("target", target).Msg("found expected target locally") } @@ -558,6 +564,14 @@ func (u *Updater) checkExec(target, tmpPath string, customCheckExec func(execPat tmpPath = filepath.Join(append([]string{filepath.Dir(tmpPath)}, localTarget.Info.ExtractedExecSubPath...)...) } + if strings.HasSuffix(tmpPath, ".pkg") && runtime.GOOS == "darwin" { + cmd := exec.Command("pkgutil", "--payload-files", tmpPath) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("running pkgutil to verify %s: %s: %w", tmpPath, string(out), err) + } + return nil + } + if customCheckExec != nil { if err := customCheckExec(tmpPath); err != nil { return fmt.Errorf("custom exec new version failed: %w", err) diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index 1afd8e93de..f5ed94d2f4 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -2271,7 +2271,6 @@ func (ds *Datastore) LoadHostByOrbitNodeKey(ctx context.Context, nodeKey string) h.policy_updated_at, h.public_ip, h.orbit_node_key, - COALESCE(hdek.reset_requested, false) AS disk_encryption_reset_requested, IF(hdep.host_id AND ISNULL(hdep.deleted_at), true, false) AS dep_assigned_to_fleet, hd.encrypted as disk_encryption_enabled, COALESCE(hdek.decryptable, false) as encryption_key_available, @@ -4955,20 +4954,6 @@ func (ds *Datastore) ListUpcomingHostMaintenanceWindows(ctx context.Context, hid return mws, nil } -func (ds *Datastore) SetDiskEncryptionResetStatus(ctx context.Context, hostID uint, status bool) error { - const stmt = ` - INSERT INTO host_disk_encryption_keys (host_id, reset_requested, base64_encrypted) - VALUES (?, ?, '') - ON DUPLICATE KEY UPDATE - reset_requested = VALUES(reset_requested)` - - _, err := ds.writer(ctx).ExecContext(ctx, stmt, hostID, status) - if err != nil { - return ctxerr.Wrap(ctx, err, "upsert disk encryption reset status") - } - return nil -} - // countHostNotResponding counts the hosts that haven't been submitting results for sent queries. // // Notes: diff --git a/server/datastore/mysql/hosts_test.go b/server/datastore/mysql/hosts_test.go index fb37661ccf..ed703b0f54 100644 --- a/server/datastore/mysql/hosts_test.go +++ b/server/datastore/mysql/hosts_test.go @@ -7616,7 +7616,6 @@ func testHostsLoadHostByOrbitNodeKey(t *testing.T, ds *Datastore) { // the returned host by LoadHostByOrbitNodeKey will have the orbit key stored h.OrbitNodeKey = &orbitKey - h.DiskEncryptionResetRequested = ptr.Bool(false) returned, err := ds.LoadHostByOrbitNodeKey(ctx, orbitKey) require.NoError(t, err) @@ -7696,8 +7695,8 @@ func testHostsLoadHostByOrbitNodeKey(t *testing.T, ds *Datastore) { require.NoError(t, err) loadFleet, err = ds.LoadHostByOrbitNodeKey(ctx, *hFleet.OrbitNodeKey) require.NoError(t, err) - require.True(t, loadFleet.MDM.EncryptionKeyAvailable) require.NoError(t, err) + require.True(t, loadFleet.MDM.EncryptionKeyAvailable) require.NotNil(t, loadFleet.DiskEncryptionEnabled) require.True(t, *loadFleet.DiskEncryptionEnabled) @@ -8361,8 +8360,8 @@ func testHostsEncryptionKeyRawDecryption(t *testing.T, ds *Datastore) { // no disk encryption key information got, err := ds.Host(ctx, host.ID) require.NoError(t, err) - require.False(t, got.MDM.EncryptionKeyAvailable) require.NotNil(t, got.MDM.TestGetRawDecryptable()) + require.False(t, got.MDM.EncryptionKeyAvailable) require.Equal(t, -1, *got.MDM.TestGetRawDecryptable()) // create the encryption key row, but unknown decryptable @@ -8380,8 +8379,8 @@ func testHostsEncryptionKeyRawDecryption(t *testing.T, ds *Datastore) { got, err = ds.Host(ctx, host.ID) require.NoError(t, err) - require.False(t, got.MDM.EncryptionKeyAvailable) require.NotNil(t, got.MDM.TestGetRawDecryptable()) + require.False(t, got.MDM.EncryptionKeyAvailable) require.Equal(t, 0, *got.MDM.TestGetRawDecryptable()) // mark the key as decryptable @@ -8390,8 +8389,8 @@ func testHostsEncryptionKeyRawDecryption(t *testing.T, ds *Datastore) { got, err = ds.Host(ctx, host.ID) require.NoError(t, err) - require.True(t, got.MDM.EncryptionKeyAvailable) require.NotNil(t, got.MDM.TestGetRawDecryptable()) + require.True(t, got.MDM.EncryptionKeyAvailable) require.Equal(t, 1, *got.MDM.TestGetRawDecryptable()) } diff --git a/server/fleet/capabilities.go b/server/fleet/capabilities.go index b1bfff1139..be397bcc32 100644 --- a/server/fleet/capabilities.go +++ b/server/fleet/capabilities.go @@ -78,6 +78,8 @@ const ( // CapabilityEndUserEmail denotes the ability of the server to support // receiving the end-user email from orbit. CapabilityEndUserEmail Capability = "end_user_email" + // CapabilityEscrowBuddy allows to use Escrow Buddy to rotate FileVault keys + CapabilityEscrowBuddy Capability = "escrow_buddy" ) func GetServerOrbitCapabilities() CapabilityMap { @@ -85,6 +87,7 @@ func GetServerOrbitCapabilities() CapabilityMap { CapabilityOrbitEndpoints: {}, CapabilityTokenRotation: {}, CapabilityEndUserEmail: {}, + CapabilityEscrowBuddy: {}, } } diff --git a/server/fleet/datastore.go b/server/fleet/datastore.go index a043eba04e..7c61870d68 100644 --- a/server/fleet/datastore.go +++ b/server/fleet/datastore.go @@ -883,8 +883,6 @@ type Datastore interface { // GetHostDiskEncryptionKey returns the encryption key information for a given host GetHostDiskEncryptionKey(ctx context.Context, hostID uint) (*HostDiskEncryptionKey, error) - SetDiskEncryptionResetStatus(ctx context.Context, hostID uint, status bool) error - // GetHostCertAssociationsToExpire retrieves host certificate // associations that are close to expire and don't have a renewal in // progress based on the provided arguments. diff --git a/server/fleet/hosts.go b/server/fleet/hosts.go index 8dc1eca42e..ac0e86723d 100644 --- a/server/fleet/hosts.go +++ b/server/fleet/hosts.go @@ -321,10 +321,6 @@ type Host struct { // omitted if we don't have encryption information yet. DiskEncryptionEnabled *bool `json:"disk_encryption_enabled,omitempty" db:"disk_encryption_enabled" csv:"-"` - // DiskEncryptionResetRequested is only fetched when loading a host by - // orbit_node_key, and so it's not used in the UI. - DiskEncryptionResetRequested *bool `json:"disk_encryption_reset_requested,omitempty" db:"disk_encryption_reset_requested" csv:"-"` - HostIssues `json:"issues,omitempty" csv:"-"` // DeviceMapping is in fact included in the CSV export, but it is not directly @@ -574,11 +570,7 @@ func (d *MDMHostData) PopulateOSSettingsAndMacOSSettings(profiles []HostMDMApple // but either we didn't get an encryption key or we're not able to // decrypt the key we've got settings.DiskEncryption = DiskEncryptionActionRequired.addrOf() - if *d.rawDecryptable == 0 { - settings.ActionRequired = ActionRequiredRotateKey.addrOf() - } else { - settings.ActionRequired = ActionRequiredLogOut.addrOf() - } + settings.ActionRequired = ActionRequiredRotateKey.addrOf() } else { // if [a FileVault profile is pending to be installed or] the // matching row in host_disk_encryption_keys has a field decryptable @@ -1230,19 +1222,3 @@ func IsEligibleForDEPMigration(host *Host, mdmInfo *HostMDM, isConnectedToFleetM // the checkout message from the host. (!isConnectedToFleetMDM || mdmInfo.Name != WellKnownMDMFleet) } - -// IsEligibleForBitLockerEncryption checks if the host needs to enforce disk -// encryption using Fleet MDM features. -func IsEligibleForBitLockerEncryption(h *Host, mdmInfo *HostMDM, isConnectedToFleetMDM bool) bool { - isServer := mdmInfo != nil && mdmInfo.IsServer - isWindows := h.FleetPlatform() == "windows" - needsEncryption := h.DiskEncryptionEnabled != nil && !*h.DiskEncryptionEnabled - encryptedWithoutKey := h.DiskEncryptionEnabled != nil && *h.DiskEncryptionEnabled && !h.MDM.EncryptionKeyAvailable - - return isWindows && - h.IsOsqueryEnrolled() && - isConnectedToFleetMDM && - !isServer && - mdmInfo != nil && - (needsEncryption || encryptedWithoutKey) -} diff --git a/server/fleet/hosts_test.go b/server/fleet/hosts_test.go index e350d701cd..94d0cd40a0 100644 --- a/server/fleet/hosts_test.go +++ b/server/fleet/hosts_test.go @@ -214,50 +214,6 @@ func TestMDMEnrollmentStatus(t *testing.T) { } } -func TestIsEligibleForBitLockerEncryption(t *testing.T) { - require.False(t, IsEligibleForBitLockerEncryption(&Host{}, &HostMDM{}, false)) - - hostThatNeedsEnforcement := &Host{ - Platform: "windows", - OsqueryHostID: ptr.String("test"), - MDM: MDMHostData{ - EncryptionKeyAvailable: false, - }, - DiskEncryptionEnabled: ptr.Bool(false), - } - hostThatNeedsEnforcementMdmInfo := &HostMDM{ - Name: WellKnownMDMFleet, - Enrolled: true, - IsServer: false, - InstalledFromDep: true, - } - require.True(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, true)) - - // macOS hosts are not elegible - hostThatNeedsEnforcement.Platform = "darwin" - require.False(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, true)) - hostThatNeedsEnforcement.Platform = "windows" - require.True(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, true)) - - // hosts with disk encryption already enabled are elegible only if we - // can't decrypt the key - hostThatNeedsEnforcement.DiskEncryptionEnabled = ptr.Bool(true) - require.True(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, true)) - hostThatNeedsEnforcement.MDM.EncryptionKeyAvailable = true - require.False(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, true)) - - hostThatNeedsEnforcement.DiskEncryptionEnabled = ptr.Bool(false) - hostThatNeedsEnforcement.MDM.EncryptionKeyAvailable = false - require.True(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, true)) - - // hosts without MDMinfo are not elegible - require.False(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, nil, true)) - require.True(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, true)) - - // hosts that are not enrolled in MDM are not elegible - require.False(t, IsEligibleForBitLockerEncryption(hostThatNeedsEnforcement, hostThatNeedsEnforcementMdmInfo, false)) -} - func TestIsEligibleForDEPMigration(t *testing.T) { testCases := []struct { name string diff --git a/server/fleet/service.go b/server/fleet/service.go index 5375b3d4bd..0148eb4162 100644 --- a/server/fleet/service.go +++ b/server/fleet/service.go @@ -928,8 +928,6 @@ type Service interface { // for all hosts that are already marked as failing. ResetAutomation(ctx context.Context, teamIDs, policyIDs []uint) error - RequestEncryptionKeyRotation(ctx context.Context, hostID uint) error - /////////////////////////////////////////////////////////////////////////////// // Windows MDM diff --git a/server/mock/datastore_mock.go b/server/mock/datastore_mock.go index 3fdb56d30b..7c9523da38 100644 --- a/server/mock/datastore_mock.go +++ b/server/mock/datastore_mock.go @@ -618,8 +618,6 @@ type SetHostsDiskEncryptionKeyStatusFunc func(ctx context.Context, hostIDs []uin type GetHostDiskEncryptionKeyFunc func(ctx context.Context, hostID uint) (*fleet.HostDiskEncryptionKey, error) -type SetDiskEncryptionResetStatusFunc func(ctx context.Context, hostID uint, status bool) error - type GetHostCertAssociationsToExpireFunc func(ctx context.Context, expiryDays int, limit int) ([]fleet.SCEPIdentityAssociation, error) type SetCommandForPendingSCEPRenewalFunc func(ctx context.Context, assocs []fleet.SCEPIdentityAssociation, cmdUUID string) error @@ -1910,9 +1908,6 @@ type DataStore struct { GetHostDiskEncryptionKeyFunc GetHostDiskEncryptionKeyFunc GetHostDiskEncryptionKeyFuncInvoked bool - SetDiskEncryptionResetStatusFunc SetDiskEncryptionResetStatusFunc - SetDiskEncryptionResetStatusFuncInvoked bool - GetHostCertAssociationsToExpireFunc GetHostCertAssociationsToExpireFunc GetHostCertAssociationsToExpireFuncInvoked bool @@ -4597,13 +4592,6 @@ func (s *DataStore) GetHostDiskEncryptionKey(ctx context.Context, hostID uint) ( return s.GetHostDiskEncryptionKeyFunc(ctx, hostID) } -func (s *DataStore) SetDiskEncryptionResetStatus(ctx context.Context, hostID uint, status bool) error { - s.mu.Lock() - s.SetDiskEncryptionResetStatusFuncInvoked = true - s.mu.Unlock() - return s.SetDiskEncryptionResetStatusFunc(ctx, hostID, status) -} - func (s *DataStore) GetHostCertAssociationsToExpire(ctx context.Context, expiryDays int, limit int) ([]fleet.SCEPIdentityAssociation, error) { s.mu.Lock() s.GetHostCertAssociationsToExpireFuncInvoked = true diff --git a/server/service/devices.go b/server/service/devices.go index 31e9889cb5..288fbb304e 100644 --- a/server/service/devices.go +++ b/server/service/devices.go @@ -564,41 +564,6 @@ func (svc *Service) GetDeviceMDMAppleEnrollmentProfile(ctx context.Context) ([]b return signed, nil } -//////////////////////////////////////////////////////////////////////////////// -// Request a disk encryption reset -//////////////////////////////////////////////////////////////////////////////// - -type rotateEncryptionKeyRequest struct { - Token string `url:"token"` -} - -func (r *rotateEncryptionKeyRequest) deviceAuthToken() string { - return r.Token -} - -type rotateEncryptionKeyResponse struct { - Err error `json:"error,omitempty"` -} - -func (r rotateEncryptionKeyResponse) error() error { return r.Err } - -func rotateEncryptionKeyEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (errorer, error) { - host, ok := hostctx.FromContext(ctx) - if !ok { - err := ctxerr.Wrap(ctx, fleet.NewAuthRequiredError("internal error: missing host from request context")) - return rotateEncryptionKeyResponse{Err: err}, nil - } - - if err := svc.RequestEncryptionKeyRotation(ctx, host.ID); err != nil { - return rotateEncryptionKeyResponse{Err: err}, nil - } - return rotateEncryptionKeyResponse{}, nil -} - -func (svc *Service) RequestEncryptionKeyRotation(ctx context.Context, hostID uint) error { - return fleet.ErrMissingLicense -} - //////////////////////////////////////////////////////////////////////////////// // Signal start of mdm migration on a device //////////////////////////////////////////////////////////////////////////////// diff --git a/server/service/handler.go b/server/service/handler.go index caaf16ddb4..3d606bd159 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -799,10 +799,6 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC errorLimiter.Limit("get_device_mdm", desktopQuota), ).GET("/api/_version_/fleet/device/{token}/mdm/apple/manual_enrollment_profile", getDeviceMDMManualEnrollProfileEndpoint, getDeviceMDMManualEnrollProfileRequest{}) - demdm.WithCustomMiddleware( - errorLimiter.Limit("post_device_rotate_encryption_key", desktopQuota), - ).POST("/api/_version_/fleet/device/{token}/rotate_encryption_key", rotateEncryptionKeyEndpoint, rotateEncryptionKeyRequest{}) - demdm.WithCustomMiddleware( errorLimiter.Limit("post_device_migrate_mdm", desktopQuota), ).POST("/api/_version_/fleet/device/{token}/migrate_mdm", migrateMDMDeviceEndpoint, deviceMigrateMDMRequest{}) diff --git a/server/service/hosts_test.go b/server/service/hosts_test.go index 67492d1c4d..b0f6dc7529 100644 --- a/server/service/hosts_test.go +++ b/server/service/hosts_test.go @@ -137,7 +137,7 @@ func TestHostDetailsMDMAppleDiskEncryption(t *testing.T) { OperationType: fleet.MDMOperationTypeInstall, }, fleet.DiskEncryptionActionRequired, - fleet.ActionRequiredLogOut, + fleet.ActionRequiredRotateKey, &fleet.MDMDeliveryPending, }, { @@ -1857,3 +1857,196 @@ func TestBulkOperationFilterValidation(t *testing.T) { }) } } + +func TestSetDiskEncryptionNotifications(t *testing.T) { + ds := new(mock.Store) + ctx := context.Background() + svc := &Service{ds: ds} + + tests := []struct { + name string + host *fleet.Host + appConfig *fleet.AppConfig + diskEncryptionConfigured bool + isConnectedToFleetMDM bool + mdmInfo *fleet.HostMDM + getHostDiskEncryptionKey func(context.Context, uint) (*fleet.HostDiskEncryptionKey, error) + expectedNotifications *fleet.OrbitConfigNotifications + expectedError bool + }{ + { + name: "no MDM configured", + host: &fleet.Host{ID: 1, Platform: "darwin"}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: false}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: nil, + getHostDiskEncryptionKey: nil, + expectedNotifications: &fleet.OrbitConfigNotifications{}, + expectedError: false, + }, + { + name: "not connected to Fleet MDM", + host: &fleet.Host{ID: 1, Platform: "darwin"}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: false, + mdmInfo: nil, + getHostDiskEncryptionKey: nil, + expectedNotifications: &fleet.OrbitConfigNotifications{}, + expectedError: false, + }, + { + name: "host not enrolled in osquery", + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: nil}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: nil, + getHostDiskEncryptionKey: nil, + expectedNotifications: &fleet.OrbitConfigNotifications{}, + expectedError: false, + }, + { + name: "disk encryption not configured", + host: &fleet.Host{ID: 1, Platform: "darwin"}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: false, + isConnectedToFleetMDM: true, + mdmInfo: nil, + getHostDiskEncryptionKey: nil, + expectedNotifications: &fleet.OrbitConfigNotifications{}, + expectedError: false, + }, + { + name: "darwin with decryptable key", + host: &fleet.Host{ID: 1, Platform: "darwin"}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: nil, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return &fleet.HostDiskEncryptionKey{Decryptable: ptr.Bool(true)}, nil + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + RotateDiskEncryptionKey: false, + }, + expectedError: false, + }, + { + name: "windows server with no encryption needed", + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true)}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: &fleet.HostMDM{IsServer: true}, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return nil, newNotFoundError() + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + EnforceBitLockerEncryption: false, + }, + expectedError: false, + }, + { + name: "windows with encryption enabled but key missing", + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true)}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: &fleet.HostMDM{IsServer: false}, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return nil, newNotFoundError() + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + EnforceBitLockerEncryption: true, + }, + expectedError: false, + }, + { + name: "darwin with missing encryption key", + host: &fleet.Host{ID: 1, Platform: "darwin"}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: nil, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return nil, newNotFoundError() + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + RotateDiskEncryptionKey: false, + }, + expectedError: false, + }, + { + name: "windows with encryption key and not decryptable", + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true)}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: &fleet.HostMDM{IsServer: false}, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return &fleet.HostDiskEncryptionKey{Decryptable: ptr.Bool(false)}, nil + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + EnforceBitLockerEncryption: true, + }, + expectedError: false, + }, + { + name: "windows with enforce BitLocker", + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(false)}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: &fleet.HostMDM{IsServer: false}, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return nil, newNotFoundError() + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + EnforceBitLockerEncryption: true, + }, + expectedError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.getHostDiskEncryptionKey != nil { + ds.GetHostDiskEncryptionKeyFunc = tt.getHostDiskEncryptionKey + } + ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) { + return tt.appConfig, nil + } + + notifs := &fleet.OrbitConfigNotifications{} + err := svc.setDiskEncryptionNotifications(ctx, notifs, tt.host, tt.appConfig, tt.diskEncryptionConfigured, tt.isConnectedToFleetMDM, tt.mdmInfo) + if tt.expectedError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Equal(t, tt.expectedNotifications.RotateDiskEncryptionKey, notifs.RotateDiskEncryptionKey) + }) + } +} diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index 647f298c29..44b1e95271 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -1729,7 +1729,7 @@ func (s *integrationMDMTestSuite) TestMDMAppleHostDiskEncryption() { require.NotNil(t, getHostResp.Host.MDM.MacOSSettings.DiskEncryption) require.Equal(t, fleet.DiskEncryptionActionRequired, *getHostResp.Host.MDM.MacOSSettings.DiskEncryption) require.NotNil(t, getHostResp.Host.MDM.MacOSSettings.ActionRequired) - require.Equal(t, fleet.ActionRequiredLogOut, *getHostResp.Host.MDM.MacOSSettings.ActionRequired) + require.Equal(t, fleet.ActionRequiredRotateKey, *getHostResp.Host.MDM.MacOSSettings.ActionRequired) require.NotNil(t, getHostResp.Host.MDM.OSSettings) require.NotNil(t, getHostResp.Host.MDM.OSSettings.DiskEncryption.Status) require.Equal(t, fleet.DiskEncryptionActionRequired, *getHostResp.Host.MDM.OSSettings.DiskEncryption.Status) @@ -2521,36 +2521,6 @@ func (s *integrationMDMTestSuite) TestEnrollOrbitAfterDEPSync() { require.Equal(t, h.ID, got.ID) } -func (s *integrationMDMTestSuite) TestDiskEncryptionRotation() { - t := s.T() - h := createOrbitEnrolledHost(t, "darwin", "h", s.ds) - - // false by default - resp := orbitGetConfigResponse{} - s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp) - require.False(t, resp.Notifications.RotateDiskEncryptionKey) - - // create an auth token for h - token := "much_valid" - mysql.ExecAdhocSQL(t, s.ds, func(db sqlx.ExtContext) error { - _, err := db.ExecContext(context.Background(), `INSERT INTO host_device_auth (host_id, token) VALUES (?, ?)`, h.ID, token) - return err - }) - - tokRes := s.DoRawNoAuth("POST", "/api/latest/fleet/device/"+token+"/rotate_encryption_key", nil, http.StatusOK) - tokRes.Body.Close() - - // true after the POST request - resp = orbitGetConfigResponse{} - s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp) - require.True(t, resp.Notifications.RotateDiskEncryptionKey) - - // false on following requests - resp = orbitGetConfigResponse{} - s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp) - require.False(t, resp.Notifications.RotateDiskEncryptionKey) -} - func (s *integrationMDMTestSuite) TestFleetdConfiguration() { t := s.T() s.assertConfigProfilesByIdentifier(nil, mobileconfig.FleetdConfigPayloadIdentifier, false) diff --git a/server/service/orbit.go b/server/service/orbit.go index 0afa2631e4..40f64ef2d3 100644 --- a/server/service/orbit.go +++ b/server/service/orbit.go @@ -207,15 +207,6 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro notifs.NeedsMDMMigration = true } - if host.DiskEncryptionResetRequested != nil && *host.DiskEncryptionResetRequested { - notifs.RotateDiskEncryptionKey = true - - // Since this is an user initiated action, we disable - // the flag when we deliver the notification to Orbit - if err := svc.ds.SetDiskEncryptionResetStatus(ctx, host.ID, false); err != nil { - return fleet.OrbitConfig{}, err - } - } } // set the host's orbit notifications for Windows MDM @@ -309,9 +300,17 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro } } - if mdmConfig.EnableDiskEncryption && - fleet.IsEligibleForBitLockerEncryption(host, mdmInfo, isConnectedToFleetMDM) { - notifs.EnforceBitLockerEncryption = true + err = svc.setDiskEncryptionNotifications( + ctx, + ¬ifs, + host, + appConfig, + mdmConfig.EnableDiskEncryption, + isConnectedToFleetMDM, + mdmInfo, + ) + if err != nil { + return fleet.OrbitConfig{}, ctxerr.Wrap(ctx, err, "setting team disk encryption notifications") } var updateChannels *fleet.OrbitUpdateChannels @@ -371,10 +370,17 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro } } - if appConfig.MDM.WindowsEnabledAndConfigured && - appConfig.MDM.EnableDiskEncryption.Value && - fleet.IsEligibleForBitLockerEncryption(host, mdmInfo, isConnectedToFleetMDM) { - notifs.EnforceBitLockerEncryption = true + err = svc.setDiskEncryptionNotifications( + ctx, + ¬ifs, + host, + appConfig, + appConfig.MDM.EnableDiskEncryption.Value, + isConnectedToFleetMDM, + mdmInfo, + ) + if err != nil { + return fleet.OrbitConfig{}, ctxerr.Wrap(ctx, err, "setting no-team disk encryption notifications") } var updateChannels *fleet.OrbitUpdateChannels @@ -396,6 +402,46 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro }, nil } +func (svc *Service) setDiskEncryptionNotifications( + ctx context.Context, + notifs *fleet.OrbitConfigNotifications, + host *fleet.Host, + appConfig *fleet.AppConfig, + diskEncryptionConfigured bool, + isConnectedToFleetMDM bool, + mdmInfo *fleet.HostMDM, +) error { + anyMDMConfigured := appConfig.MDM.EnabledAndConfigured || appConfig.MDM.WindowsEnabledAndConfigured + if !anyMDMConfigured || + !isConnectedToFleetMDM || + !host.IsOsqueryEnrolled() || + !diskEncryptionConfigured { + return nil + } + + encryptionKey, err := svc.ds.GetHostDiskEncryptionKey(ctx, host.ID) + if err != nil { + if !fleet.IsNotFound(err) { + return ctxerr.Wrap(ctx, err, "fetching host disk encryption key") + } + } + + switch host.FleetPlatform() { + case "darwin": + notifs.RotateDiskEncryptionKey = encryptionKey.Decryptable != nil && !*encryptionKey.Decryptable + case "windows": + isServer := mdmInfo != nil && mdmInfo.IsServer + needsEncryption := host.DiskEncryptionEnabled != nil && !*host.DiskEncryptionEnabled + keyWasDecrypted := encryptionKey != nil && encryptionKey.Decryptable != nil && *encryptionKey.Decryptable + encryptedWithoutKey := host.DiskEncryptionEnabled != nil && *host.DiskEncryptionEnabled && !keyWasDecrypted + notifs.EnforceBitLockerEncryption = !isServer && + mdmInfo != nil && + (needsEncryption || encryptedWithoutKey) + } + + return nil +} + // filterExtensionsForHost filters a extensions configuration depending on the host platform and label membership. // // If all extensions are filtered, then it returns (nil, nil) (Orbit expects empty extensions if there diff --git a/tools/tuf/README.md b/tools/tuf/README.md index 9f30f296f2..3915fdb892 100644 --- a/tools/tuf/README.md +++ b/tools/tuf/README.md @@ -225,6 +225,19 @@ make nudge-app-tar-gz version=1.1.10.81462 out-path=. fleetctl updates add --target /path/to/macos/nudge.app.tar.gz --platform macos --name nudge --version 1.1.10.81462 -t edge ``` +#### Releasing `Escrow Buddy` to `stable` + +> `releaser.sh` doesn't support `Escrow Buddy` yet. +> macOS only component + +The `Escrow Buddy` pkg installer can be generated by running: +```sh +make escrow-buddy-pkg version=1.0.0 out-path=. +``` +```sh +fleetctl updates add --target /path/to/escrowBuddy.pkg --platform macos --name escrowBuddy --version 1.0.0 -t stable +``` + #### Updating timestamp ```sh diff --git a/tools/tuf/test/create_repository.sh b/tools/tuf/test/create_repository.sh index 86fa0f5e17..0f13a21357 100755 --- a/tools/tuf/test/create_repository.sh +++ b/tools/tuf/test/create_repository.sh @@ -28,8 +28,7 @@ SYSTEMS=${SYSTEMS:-macos linux linux-arm64 windows} echo "Generating packages for $SYSTEMS" NUDGE_VERSION=stable -SWIFT_DIALOG_MACOS_APP_VERSION=2.2.1 -SWIFT_DIALOG_MACOS_APP_BUILD_VERSION=4591 +ESCROW_BUDDY_PKG_VERSION=1.0.0 if [[ -z "$OSQUERY_VERSION" ]]; then OSQUERY_VERSION=5.12.2 @@ -168,6 +167,20 @@ for system in $SYSTEMS; do rm swiftDialog.app.tar.gz fi + # Add Escrow Buddy on macos (if enabled). + if [[ $system == "macos" && -n "$ESCROW_BUDDY" ]]; then + make escrow-buddy-pkg version=$ESCROW_BUDDY_PKG_VERSION out-path=. + + ./build/fleetctl updates add \ + --path $TUF_PATH \ + --target escrowBuddy.pkg \ + --platform macos \ + --name escrowBuddy \ + --version 42.0.0 -t 42.0 -t 42 -t stable + rm escrowBuddy.pkg + fi + + # Add Fleet Desktop application on windows (if enabled). if [[ $system == "windows" && -n "$FLEET_DESKTOP" ]]; then FLEET_DESKTOP_VERSION=42.0.0 \ From 8b5094ff3787984789666f734b660df03e70c553 Mon Sep 17 00:00:00 2001 From: Grant Bilstad <82750216+pacamaster@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:10:46 -0600 Subject: [PATCH 12/88] Fix link for fleetctl install (#20835) --- docs/Using Fleet/enroll-hosts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Using Fleet/enroll-hosts.md b/docs/Using Fleet/enroll-hosts.md index 952383ec57..6112eec51e 100644 --- a/docs/Using Fleet/enroll-hosts.md +++ b/docs/Using Fleet/enroll-hosts.md @@ -12,7 +12,7 @@ Fleet supports the [latest version of osquery](https://github.com/osquery/osquer ## CLI -> You must have `fleetctl` installed. [Learn how to install `fleetctl`](https://fleetdm.com/fleetctl-preview). +> You must have `fleetctl` installed. [Learn how to install `fleetctl`](https://fleetdm.com/docs/using-fleet/fleetctl-cli#installing-fleetctl). The `fleetctl package` command is used to generate Fleet's agent (fleetd). From 6fd628463dbf5306cbddc77b407b0a79715d2dda Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 31 Jul 2024 17:25:18 -0500 Subject: [PATCH 13/88] Website: fix pricing table filtering (#20912) Changes: - Fixed the IT and Security filtering on the pricing features table. --- website/api/controllers/view-pricing.js | 53 +++++++++++++------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/website/api/controllers/view-pricing.js b/website/api/controllers/view-pricing.js index e3c914e0ae..7d07b6b770 100644 --- a/website/api/controllers/view-pricing.js +++ b/website/api/controllers/view-pricing.js @@ -44,36 +44,39 @@ module.exports = { pricingTable.push(allFeaturesInThisCategory); } - let pricingTableForSecurity = _.filter(pricingTable, (category)=>{ - return category.categoryName !== 'Device management' && (category.usualDepartment === 'Security' || category.usualDepartment === undefined); - }); + let pricingTableForSecurity = []; let categoryOrderForSecurityPricingTable = ['Support', 'Deployment', 'Integrations', 'Endpoint operations', 'Vulnerability management']; - // Sort the security-focused pricing table from the order of the elements in the categoryOrderForSecurityPricingTable array. - pricingTableForSecurity.sort((a, b)=>{ - // If there is a category that is not in the list above, sort it to the end of the list. - if(categoryOrderForSecurityPricingTable.indexOf(a.categoryName) === -1){ - return 1; - } else if(categoryOrderForSecurityPricingTable.indexOf(b.categoryName) === -1) { - return -1; - } - return categoryOrderForSecurityPricingTable.indexOf(a.categoryName) - categoryOrderForSecurityPricingTable.indexOf(b.categoryName); - }); + for(let category of categoryOrderForSecurityPricingTable) { + // Get all the features in that have a pricingTableFeatures array that contains this category. + let featuresInThisCategory = _.filter(pricingTableFeatures, (feature)=>{ + return _.contains(feature.pricingTableCategories, category) && (feature.usualDepartment === 'Security' || feature.usualDepartment === undefined); + }); + // Build a dictionary containing the category name, and all features in the category + let allSecurityFeaturesInThisCategory = { + categoryName: category, + features: featuresInThisCategory, + }; + // Add the dictionaries to the arrays that we'll use to build the features table. + pricingTableForSecurity.push(allSecurityFeaturesInThisCategory); + } - let pricingTableForIt = _.filter(pricingTable, (category)=>{ - return category.categoryName !== 'Vulnerability management' && (category.usualDepartment === 'Security' || category.usualDepartment === undefined); - }); let categoryOrderForITPricingTable = [ 'Deployment','Device management', 'Endpoint operations', 'Integrations', 'Support']; + let pricingTableForIt = []; // Sort the IT-focused pricing table from the order of the elements in the categoryOrderForITPricingTable array. - pricingTableForIt.sort((a, b)=>{ - // If there is a category that is not in the list above, sort it to the end of the list. - if(categoryOrderForITPricingTable.indexOf(a.categoryName) === -1){ - return 1; - } else if(categoryOrderForITPricingTable.indexOf(b.categoryName) === -1) { - return -1; - } - return categoryOrderForITPricingTable.indexOf(a.categoryName) - categoryOrderForITPricingTable.indexOf(b.categoryName); - }); + for(let category of categoryOrderForITPricingTable) { + // Get all the features in that have a pricingTableFeatures array that contains this category. + let featuresInThisCategory = _.filter(pricingTableFeatures, (feature)=>{ + return _.contains(feature.pricingTableCategories, category) && (feature.usualDepartment === 'IT' || feature.usualDepartment === undefined); + }); + // Build a dictionary containing the category name, and all features in the category, sorting premium features to the bottom of the list. + let allItFeaturesInThisCategory = { + categoryName: category, + features: featuresInThisCategory, + }; + // Add the dictionaries to the arrays that we'll use to build the features table. + pricingTableForIt.push(allItFeaturesInThisCategory); + } // Respond with view. From ba2f79e1c4f5bb2d47aca419fd854ebb22ea35f3 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 31 Jul 2024 17:40:41 -0500 Subject: [PATCH 14/88] Website: personalize /better page for Secure Frame users (#20890) Related to: https://github.com/fleetdm/confidential/issues/7227 Changes: - Added a banner to the /better page that is visible to users who visit it with a `?utm_content=secureframe` query param. - Updated the `` component to support customizing text and arrow color. --- website/api/controllers/view-transparency.js | 4 +-- .../images/logo-secureframe-46x48@2x.png | Bin 0 -> 2053 bytes .../animated-arrow-button.component.js | 8 +++-- website/assets/js/pages/transparency.page.js | 1 + .../animated-arrow-button.component.less | 2 +- website/assets/styles/pages/transparency.less | 31 ++++++++++++++++++ website/views/pages/transparency.ejs | 9 ++++- 7 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 website/assets/images/logo-secureframe-46x48@2x.png diff --git a/website/api/controllers/view-transparency.js b/website/api/controllers/view-transparency.js index c079ed5300..7267792026 100644 --- a/website/api/controllers/view-transparency.js +++ b/website/api/controllers/view-transparency.js @@ -6,7 +6,6 @@ module.exports = { description: 'Display "Transparency" page.', - exits: { success: { @@ -17,9 +16,8 @@ module.exports = { fn: async function () { - // Respond with view. - return {}; + return {showSecureframeBanner: this.req.param('utm_content') === 'secureframe'}; } diff --git a/website/assets/images/logo-secureframe-46x48@2x.png b/website/assets/images/logo-secureframe-46x48@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..86107888f9aa26af557972d36d6d9b5ddad47c98 GIT binary patch literal 2053 zcmV+g2>SPlP)0D|OQzr+NiI7HK&=IkH*!^b zq9AYax7|nSQK$~;uwmG8bA5ZH5LyV>0zf`B{mY?>Y(#Kt$-0e79U^>dDTIh)t%9@A zxvo7&#A7gSA}T%2+5~@m^_GS1D8x$m87~ z;HKYicKT2OM1rqFY%4PUL23O(Rm7c#SMXKEwnD?}e)ClqB7PrE(a3qh8)QbsnrBhy zN%XQGQk;DX5FYwbw)sI}-i%_;ve2bCSMn!>(WgSyi+=Ou0wQx+=u({D4uM=q?P=aR?Acw@>JKz}&h%9Bsr4)!t$c^kZqu4TLES&1uG&>`=ZX1ad6WdL> zHOPU{l$+jHfTf;pQ#g1rA-J(_#5M?_3q$es$!7>8xqRC~1*bIS#$p?Rt1;zPOQtMb zw?OVnvVQZl0|DIC&Jn6xWtS8?ljH?ljG}6vD7oR%KooltBREGVU?K(q zh#w`x_?YBIIuMz_S$It*wjme!?gFKOO5g-HJ$_!CJMm5)&<&XH2Ps5mFkvBC*K}@z9kl1kToGwwPD${P(!o_d@fxrSy zZ3HCP(m+_Yy6b2gp~#R~q3nJD1xf>DKnIM?M5B~`A{r*VACwIeyq3ZmL2-Fi2Ui)( zK!}A$)&L1U$lyV!W^ZChZ=uLlD9ryt&>Og$ zrpiEs_7=I^)fHbrRNuaoO!PF@df_|62(C=)u%BF7GdJnFn9_;Pa{z7zZT5F?Lqu*s ziD!k(bXrJlq;#S$nja1loJba3xpDZu5NPGhE{GoRH(_g@R@xpc#P7fWmfeNNQ8;)C;bLsH={1$Q?(X*QNDi#4Yyo9I?62#8vA zd-&DV55zTxWwGWwc0}|u?thewbx(OnJ;LGe9Fqs(XhnAOv_uidD0NXCQb(j8g znB&WDp7RB_CmcM3fYh8){3pBg*FrmBzpiMPeFuDBJ0Kb=yn9HzDHDz(c0xQ_-X6w=85nD z1mzv2Tmo6=M1$(u!98?40}lTSLSs!-rj|dDmVY(Jg~$wcEdl=;Fz$ik7KqTsr9{DJ z$)wipmOBwL=$cnRWCC86M7qL}bh(r92a2QMW7x+SWzGBc0RdrnIW|dAnXu4@U2pO9 zOgcVfF&}`v;YEys7g(~Dty`L1T6Z#XQB@Y)b@<|0$YbX=feNthsphK63GUV|{~9Xv z=m4gLA{CC#rk91S^J9bbmI~=b*+Ep_*1!kd{tAmI@YG@0GJ~@{KK`6EV&J|*?mrB8 zNp{^h`EmN2F)S2NKpB*YTcuE5?4xfXoou3!k z7)qJ_E*6&tqTpjp?v@z7i66)Hl&xMY9Rrb}&}z6XWf4^Gy78*%8&z2gAFf@l@emQ( zD{f0kxy(S+LRYsZe)M2{8u!O-YL@@du@8ZaW51Ld8>T4Q_~ps!(vs zZ9b}}u>Le;hkzIs7KCdu>_$SjV~9~o0o+y$9VkE)JPcPmKj}h2qDv97uI>ka77o7yR{@`9TOTTL4SuQM>{ZF*VlI;EoUJ - - + + diff --git a/website/assets/js/pages/transparency.page.js b/website/assets/js/pages/transparency.page.js index 211b9f441f..be7cfde1f3 100644 --- a/website/assets/js/pages/transparency.page.js +++ b/website/assets/js/pages/transparency.page.js @@ -4,6 +4,7 @@ parasails.registerPage('transparency', { // ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝ data: { //… + showSecureframeBanner: false, }, // ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗ diff --git a/website/assets/styles/components/animated-arrow-button.component.less b/website/assets/styles/components/animated-arrow-button.component.less index 60102c4d7b..61d9b459b8 100644 --- a/website/assets/styles/components/animated-arrow-button.component.less +++ b/website/assets/styles/components/animated-arrow-button.component.less @@ -21,7 +21,7 @@ height: 12px; width: 12px; fill: none; - stroke: #FF5C83; + // stroke: #FF5C83; « Note: this is overridden by the arrow-color prop; } [purpose='arrow-line'] { opacity: 0; diff --git a/website/assets/styles/pages/transparency.less b/website/assets/styles/pages/transparency.less index ac5831ccf0..4e787318f6 100644 --- a/website/assets/styles/pages/transparency.less +++ b/website/assets/styles/pages/transparency.less @@ -128,6 +128,31 @@ } } } + [purpose='secureframe-banner'] { + width: 100%; + text-align: center; + color: #FFF; + h2, p { + color: #FFF; + } + h2 { + margin-bottom: 16px; + } + [parasails-component='animated-arrow-button'] { + font-weight: 600; + } + border-radius: 16px; + background: #091922; + padding: 32px; + img { + height: 48px; + width: 45.474px; + margin-bottom: 16px; + margin-left: auto; + margin-right: auto; + } + } + [purpose='feature-headline'] { max-width: 510px; margin-bottom: 80px; @@ -332,6 +357,12 @@ margin-right: auto; } } + [purpose='secureframe-banner'] { + padding: 32px 16px; + h2 { + font-size: 24px; + } + } } @media (max-width: 375px) { diff --git a/website/views/pages/transparency.ejs b/website/views/pages/transparency.ejs index 12f255e580..4e478e147c 100644 --- a/website/views/pages/transparency.ejs +++ b/website/views/pages/transparency.ejs @@ -25,7 +25,14 @@
- +
+
+ Secureframe logo +

Automate compliance.
Improve security. Reduce risk.

+

Build trust with customers using automation backed by world-class experts

+ Learn more +
+

Don’t make me think about IT

From 68f2f58ebefc34f1854f470fe9487156cdfb8ae1 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Wed, 31 Jul 2024 18:24:31 -0500 Subject: [PATCH 15/88] Website: test bringing below-the-fold content higher (#20913) Co-authored-by: Eric --- website/assets/styles/pages/transparency.less | 6 +- website/views/pages/device-management.ejs | 11 ++- website/views/pages/endpoint-ops.ejs | 5 +- website/views/pages/homepage.ejs | 3 - website/views/pages/transparency.ejs | 70 ++++--------------- .../views/pages/vulnerability-management.ejs | 1 - .../partials/calendar-banner.partial.ejs | 2 +- 7 files changed, 24 insertions(+), 74 deletions(-) diff --git a/website/assets/styles/pages/transparency.less b/website/assets/styles/pages/transparency.less index 4e787318f6..15334ab0a9 100644 --- a/website/assets/styles/pages/transparency.less +++ b/website/assets/styles/pages/transparency.less @@ -54,7 +54,7 @@ } [purpose='hero-text'] { text-align: center; - margin-bottom: 40px; + margin-bottom: 80px; h1 { font-size: 48px; font-weight: 800; @@ -193,13 +193,13 @@ [purpose='accordion'] { - padding-top: 64px; + h2 { padding-bottom: 16px; } [purpose='accordion-body'] { width: 100%; - padding-top: 64px; + [purpose='accordion-item'] { border-bottom: 1px solid #E2E4EA; padding-bottom: ; diff --git a/website/views/pages/device-management.ejs b/website/views/pages/device-management.ejs index 93215dc33a..f7b0f37a84 100644 --- a/website/views/pages/device-management.ejs +++ b/website/views/pages/device-management.ejs @@ -416,7 +416,10 @@
<%/* Shorten the feedback loop section */%>
-
+
+
+ A laptop using Fleet to accurately display the status of MDM configurations +

Shorten the feedback loop

Spend less time debugging whether changes actually happened.

@@ -426,14 +429,8 @@

Every change to a policy or security control is tracked and auditable in Fleet’s UI, or in your logs.

-
- A laptop using Fleet to accurately display the status of MDM configurations -
-
- <%- partial('../partials/calendar-banner.partial.ejs') %> -
<%/* Scope transparency section */%>
diff --git a/website/views/pages/endpoint-ops.ejs b/website/views/pages/endpoint-ops.ejs index fa80f91e7d..dc107d725d 100644 --- a/website/views/pages/endpoint-ops.ejs +++ b/website/views/pages/endpoint-ops.ejs @@ -123,10 +123,8 @@

Remote-control IT tasks on every kind of computer – even you, Linux.

Write and run scripts remotely, report progress, and replay queued up tasks on computers that went offline.

-

Integrate Google Calendar to install updates and force restarts when your users’ computers are actually free.

-

Reduce human error by automating click-tastic tasks directly on the host with Open Interpreter.*

+

Optionally integrate Google Calendar to make changes when certain users’ devices are actually free.

-

*Coming soon

Ship data to any platform @@ -228,7 +226,6 @@
- <%- partial('../partials/calendar-banner.partial.ejs') %>
Ship data to any platform diff --git a/website/views/pages/homepage.ejs b/website/views/pages/homepage.ejs index f46f1b6c48..e068fde91b 100644 --- a/website/views/pages/homepage.ejs +++ b/website/views/pages/homepage.ejs @@ -180,9 +180,6 @@
<% } %> -
- <%- partial('../partials/calendar-banner.partial.ejs') %> -
<%/* Integration cards */%>

Connect your favorite tools

diff --git a/website/views/pages/transparency.ejs b/website/views/pages/transparency.ejs index 4e478e147c..fd94fc5f32 100644 --- a/website/views/pages/transparency.ejs +++ b/website/views/pages/transparency.ejs @@ -2,63 +2,12 @@
-

A better employee experience

-

What if the way your employer maintained your computer was more transparent? What if it helped you get more done?

+

What can Fleet access on my device?

+

End users deserve to know what their employer can see and do on their laptops. Here’s what Fleet can manage on your device:

+
-
-
-

Tell me when and why

-

Fleet installs updates and forces restarts when you and your computer are actually free.

-
-

No more restarts blocking you from important meetings

-

See what's getting changed on your work computer

-

Avoid losing unsaved work

-
- - I wish my company did this - -
-
- Schedule maintenance with Fleet -
-
-
- -
-
-
- Secureframe logo -

Automate compliance.
Improve security. Reduce risk.

-

Build trust with customers using automation backed by world-class experts

- Learn more -
-
-
-
-

Don’t make me think about IT

-

Stop distracting employees with computer maintenance tasks and reclaim countless hours of lost time across your organization.

-
- -
-
- -
- A secure laptop -

Get your team’s laptops secure with as little thought as possible. Minimize employee interaction required for security updates.

-
- -
- Automatically fix vulnerabilities -

Give people a reliable digital experience at work. Automatically fix laptop vulnerabilities so security doesn’t have to chase your staff.

-
- -
-
- -
-

What can Fleet access on my device?

-

End users deserve to know what their employer can see and do on their laptops. Here’s what Fleet can manage on your device:

@@ -163,6 +112,17 @@

+
+ +
+
+
+ Secureframe logo +

Automate compliance.
Improve security. Reduce risk.

+

Build trust with customers using automation backed by world-class experts

+ Learn more +
+
diff --git a/website/views/pages/vulnerability-management.ejs b/website/views/pages/vulnerability-management.ejs index 833a0abe04..bf571b88ac 100644 --- a/website/views/pages/vulnerability-management.ejs +++ b/website/views/pages/vulnerability-management.ejs @@ -110,7 +110,6 @@ Mitigate CVEs automatically
- <%- partial('../partials/calendar-banner.partial.ejs') %>
Up-to-date data without scans diff --git a/website/views/partials/calendar-banner.partial.ejs b/website/views/partials/calendar-banner.partial.ejs index 7da1b7e7e8..e3c91817fc 100644 --- a/website/views/partials/calendar-banner.partial.ejs +++ b/website/views/partials/calendar-banner.partial.ejs @@ -2,7 +2,7 @@
NEW
<% if(!primaryBuyingSituation) {%> -

"This is a terrible time to mess with my computer."

+

"This is a terrible time to mess with my computer."

Install updates and force restarts when your users’ computers are actually free.

<%} else if(['eo-it', 'mdm'].includes(primaryBuyingSituation)) {%>

Patch your C-suite with confidence

From bcc723cabcd15738679d81070edf1c177d994a07 Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Thu, 1 Aug 2024 12:01:51 +0900 Subject: [PATCH 16/88] Maintenance windows article update (#20926) - added a note about DDM and updated graphics (as part of https://github.com/fleetdm/fleet/issues/20680). cc @noahtalerman --- ...alendar-introducing-maintenance-windows.md | 2 ++ ...ucing-maintenance-windows-2-900x450@2x.png | Bin 197115 -> 92420 bytes ...g-maintenance-windows-cover-900x450@2x.png | Bin 272988 -> 78778 bytes 3 files changed, 2 insertions(+) diff --git a/articles/fleet-in-your-calendar-introducing-maintenance-windows.md b/articles/fleet-in-your-calendar-introducing-maintenance-windows.md index 5f23f9bbce..534b993835 100644 --- a/articles/fleet-in-your-calendar-introducing-maintenance-windows.md +++ b/articles/fleet-in-your-calendar-introducing-maintenance-windows.md @@ -1,5 +1,7 @@ # Fleet in your calendar: introducing maintenance windows +> Unlike other Fleet features which take advantage of declarative device management (DDM), the approach described in this article still uses traditional MDM commands. (More to come.) + ![Fleet in your calendar: introducing maintenance windows](../website/assets/images/articles/fleet-in-your-calendar-introducing-maintenance-windows-cover-900x450@2x.png) Fleet is excited to announce the release of "maintenance windows", a new feature in Fleet v4.48 that helps make sure OS updates occur during times that disrupt your users the least. Now, just like any good colleague, when Fleet needs some of your time, it puts it on your calendar. This approach avoids interrupting your key activities or important meetings, whether in the office, on the road, or working remotely. diff --git a/website/assets/images/articles/fleet-in-your-calendar-introducing-maintenance-windows-2-900x450@2x.png b/website/assets/images/articles/fleet-in-your-calendar-introducing-maintenance-windows-2-900x450@2x.png index 8405577e42fd876bd0965c1e75f758999beed753..468a372a38ae6ecba8150b5aaee657bb1079e803 100644 GIT binary patch literal 92420 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�Z`vjaJ|>7jvv_^hQHoR?++YUmr&_T$NdmR}Q7m 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
kF2{o zu4rA8l~J2286<9${eo1vr(6{@I+SSWN^UNflN2aSq}3>F?j4+@AaIHM+@v{Y0+XzF ze(2Eq!+Ssw;-Mxj)UQmw%xLUxnm@y#37V6}pc+4||IE1|M8&G8WZC9&gY#Ip>|QG3 zAE3Py&tI-|2m%0d&cE;Y2f*)=sZ;D|l;ErKq4~Xy$R*JeBctyVd~mJ0_3{;8Yg&6a zmA3}5a#>k3^4B@x)vE4nQyHz2$(5azdoACnDf}~Ix~uXMDWA!v)7AnG9)&hS5-QE# zx2+;YQf~xPBg}AqFMSX|l3ncJ!P~%SD?NA-RyH8*gdqM+MD+Vd%h3lWd67BC8%^zf z>OYmE9~PQH8W&@+T6yLwNd|*isPkh=MaJuq9NF#Jo|UW5S@%L@9b;p4KytCSUGRx@ zoL>+k4|Id62b8=2O7k;JodVj3)G7KO&EiV|H*?j6^oXC;+4TC=FLn1qw)dn!VPAn6XzS!6L#Umgt+&>?Ud&x;Q&ZSWw(+%ex3PvTKus6~0pH{7G5)4cvRBGqbOKV0mCF zP_b!Ov#eG5V+A|gv8+f|#y@(7y%^>|*1FUGMLWiY*oi89Q@v4hnGtx0-uBn>>(ckA zqdq!xd_YgT#0MD;QhVT;!#1o9u+@a@uJzWHt3O0U=BuHnHW8)$Zc;B*6<9rk)U z{=Ff0QIbcgqB$W!Md{rDqOipgTwqVL%;i_=6QM&&ojo6a_n#nPC2C(xEh`o%aI*%z zD2dro^CD=}fLz4`bR$2xiU|-t15qe399A;FCc7q~B3sg>U~7UMZfok17F|PuSBfP! zOZ#5e?JNF~Ro{cWS!(xHL~PF6)UmRbKn#hCbSs+dhWP}|V0Uvr$1U>Fl#2u`WUtxz z7f0b7vMWE?MlOei?(;60FjR=ZFMiakGcumIm5>jly*9apysVS3tVprs_4N8-H&VG| zs7k{AQk+cWU!}p2RQTJf!G~H>mrf=be6dT~#~-EbNG9)VAd_RL?itd}E%6Y#Zi}JSPSI(|t#cg*Jf|Oq9z{mGB(LtwcfaTVc!R46o zZjEU~*oPf_jw8c|T8RjksFUR5*k*%w4{wcbPs057>M6O_?au82@5}mgPQ2OO+^1j= zP^s1$zt{lWj-i0(+x-_U1NV9jlG>eaENiZ-V!IEsJGG!5DCqE)I4D6|Pxq(x9S)N< z=4NFuTOXOqm~Ia%_T2kNj#`#sM2%ZGMI|Wh6gK( zEm-XN5X%*wbA*Jev9fxbZRBcp!=yPG2ZOGq)LXq7SMPWj*!7p+z;dyCy~8StXq!|m z?OW=#v767?lkl-U;i~e`;)51pxHj`9YR)?d+zG2GK0-F1BGP)p1+)@hrkg(06dr`J zIB|m8La1!h2ag(=y<)#;cRY#;{Mr_0koln0P?M~TBbqb^9JzM`Jy{`{t)hw|bMLCE zqLh&>D-%D@mdBOtx>a zeXq9Ge{!NJ0*4OkjRSrDplY!f`L^J&HP-2*K?P1w=3btptrKO>ANJ71ecPSwN=_CU z!i7!^9gH=F-=4hL=SLD{eL*FJ4-m=giQ~W?4ZghRCB3z7?N`Nmp)PR}1mI|!88LtC z2q0dG4q(-4)}|Ve!?@V>7!&0wT|s&?Hw4Y07I<%Em#HPlxhPlr8aUYz+{t z{4m-p)fSd-hm9fMKu(G*l6_uJa!)-JXT;^>KW~SR=WZ3HCDufNQ=UB}3hIHL;11GZ0!e}B zL1jAg1Qv=5(E(L+(wmQ<^*OU~4THZQcxU9gDcxbH9;@FXgB}p0f|!giad@O-!^5-x zs;{FbTKy>hr40@a02R=5K4QaOCb@~F)6sfP@YJ&%ng`|ed!ry+M@vnjncw`aXQLf& z^U@X?1un&t|AbE@dMB4SDSiBz=+^{2m^O-B?TF4|??Xnz=FK63GeSU+1G*(8|3-0M zDTlvSV?ffgIXpkLP%)`sX#%X9-Zp?eaDYCXaAQq+X1$ z)#W!!oD*HPCx5u-o$gu`;rmo2U{S2M9ThdgMiF|%?cU+jYwk{$>&_a3wBUqV`ltY{@`6jH=$B;`i~V%8zl<0^Zf zN7Bu{Xl;37v5*&!-m$a!sn+0X?iKnheS*GL!vcu+#XPt*s*l-X`q?SwoX6bXr zbHj4_vmA5!O6Wc|w9Ksftw*3EwW}y?V4QXYaF_M3+2zzIhugvOR^g8disJt)zLuDy zDz@s1poVwPl>t4pC7|*jtxxc1p8f?X{mPGfsgm$z_HGmJbF%!>J0KM(=YjKN%M*>o zh-GUz)LG+YU^NQM<}5*zwk{a9Ru8wbb;5|hhI-(&RU0w(aC&13)!n`{b3THWN8c*@ zI{Ue5FCRIA82%#}zz)iM;FR(hFKV#aceE>acd^l&n|EqGRwiK(51}O*s=$@S&bK&u zqO~f4YvI_@@=6tnZh6#=#TE^ylV@SknjF@`EPRMK)Ihi1jmLEU!TuUuMXi&M0fR`j z1TlBqrHpQyxxhXUoNn%XnGwMAWAxA_~ANqsUI#tHYHV#mMkBf2J00PmZ0pH8aZdS=1hq+wq9j66uC z_`(gPwaR6p;SNT%wl6YH=ROJ%)IdFgUit;u>9MUSeP``O88kS}cIcgNer8r^4T4Q+x58=xh%S1RQn})Gf&ImP{=+K|-KSpH z3stm~Wt(}en8fY|ED=Ia^9W0Y()N&nR&$so^VrMGqRS3-R7R&k!AwxM+b%FY{?PHm zbXkpyd8&}Xz-^}7oZ~QBk@|67}yQ-5P6Ksvwv>G0;Or1A!u@t*C3WKUR7Ue}u z)SvyV)EQM9{?&uo?MjX^5A-{xKYxTxa{Txu43^@XMxH4^rm-&RVs9q0KJ*-3E8w}` z5@!1KNu8xGYwRpuWWmVhnR#Vv8DO!^)*~dULmH-_*;8bF(TL?1YDGDCV=4dG0L!l; zT9T1f#6P7ss9Cl0ImAt)J4AyIf{yu*8f;5`rm=F6R)3MMJq>PY&1jq)xK*vOb&!$G zW4&`O${oKAQ6GaPw47243Q6WkkP1dhFE{V3WZ?~0YqnB?Cb_e1+AAi@RYrOPrW#XT z7?wZHw}}j+Q)L<)S@S(Z=WB4mCFmK`_6SXyN_e=nCbQmW(vu`&O}a;X(DxOKWn1)I zeycerC;WwUMfkrKiP=Dyse?3a$9+Ary2=o9w#|oH!i^hKx{$4#DfRAQV{%^?NHRc* zSUy+xc>h5)W&8Tvd6xP`##xoNB(H~MJCb5Y03Ak$qYrW_9!KU(_*gTKVQG=xwg#Yr zR}Jd52_5v;5Y`p9w&LJq4Qhk^Wt?C=AwkP)E_!Y*nDC+oKQ!X8V>MAhD79@yxbSiJ zYn-WO`&pe-MZ))~%q$%N(tab+Dish|!u~1ig-;}cDjGOWtCRJ4s4%iohK({06cb>I zPwvWEgO){}5AzqUU4@xmQ9qJJsV}PV+mjD;!mqADpvm9E5i39NAkVeTt@5G|YYeoR zqIpEFbzVgEC*$1EqU7GnpbM?CjJUg>Bm&-SWyG`$PHkWjsaXucl&`mBn_gxx%m^4; z+qMnM9d)0?X~d6)nl%_iom7j|I3$PvG$n>!R2uZW;9*VmDRXY+Gh2H$&H3z+%bA3W z@g;GWg=4&g>L4Jb2ywagtvGDd}lcLc-8hiU7EmRGe*G71C-H2(&pY8n$h}K}1 z)^U_YC|sYz&3!|DThi4&K^xdidMi2Pd)E{9GU+#Kc%CCC+$(Z@0HyJ+2gVOeE8HH1 zscGK8u*Q@Xid3I#q+3QrQEo$=dbN^^Ww*x^(psmrTNk%hj$N@56KJaOYS#A&{PD}Z z=}Z%mw2Z(ZVHAm>-13=rdy}aK_sO(t@b0eltd^|Yf;bFaVc`2lqL{w-RFgvq^iOIYMYJYOxM{r$Ns|auy)33f7=$brJqYJn?~5u;lq59L*WE?9ZweTL#iF`%~HQv zV}63MXT<|6dZnA{607A%+dCr!@0{IMU;F6Pg%~$10AT+2yk-B-cIwW-M*|&Jsi?Ow zwi}WuJ08Sro>L2ZZnW=tG*x)ub1m16zMb%g7<`Xyfn>Z@oxZ+jyeNypR&$>UTm`in z8AO%BB0#PkqpZJVZ>{{avg9`vZ^ElO z#7+TA9B8~746yiO!6YG{%Dvhbr`H!0!zPUL78OdhP<`ichC|>L1w*dzK5xnvf^M=)wzKL2U7!vuWm!&E3sXZnp zB8~wzE?nLoZ|^9*ltkq{Z;sGhVNc1t+}3Lth0e2L?Ui)ex5#EzWRyn#6=o-$hh?C5EsP-_hf%+=Re5BbQ&J~b+7H{-}e2W>c{)h%lOi>@@@)3HJ9VvBY;H_&i=33rGldb*r}j_a)-=!E=tItQ^?Q)-?OSN0!Yae@4FeF84ZZy4?E~hMmsj?3p3!qTdHL zEwN#9!3tf5n+9A+@=)UtA#(VMeByhS02S+$;i5oAJ603uNMvQw4{Z$!VJq0g&D7z4`uoWB8l4rS_C!&-W1%lbRT~i+a)3yh}A;KT4HV9|EF(3H{+( zYDt{d0p_(~Ff0D?{?x-X=;M82X%5F{12EE&54` zQRB?1gOSG28r{iUV1O7b+OPpcvw5j$-DKRGR6f^O+NNPq0yTp{eWfpN&l#trG0tWk z|GROC|4B$dB*v{Ys8v@E4}tGw=p;O(L@E1%RPtbS3DW9_ID6)KXNct#ViH_ldjHa- za5)|+SvbZW0pT;4+zo9pFpmKM7LUlh1purzg5xdLpIEY-4Vd*C*m7FWd(yu=8VNu3 z)sJY7Hn?B-O!l{)z?M>oD7#VT#&*FQo-lZ+?WX&;)yjHgfX>#dQ3c~ZpbtNSrTcA}M#wd4q8ZUD zyE;<^eAzlSY$m+9R7NJ-?&)SrP;)^ekRaQFR6O}Y367Gra=d?twPvb^x@#LHYB^-n5O9s*Y$SOg+Tav7 z`+Fki>2ZR-(cI=hYXG57(@PYKte%u?vY`4Kx!kv2gtoMmN70?(UmzZ#Wefu$0was= zgk?ci8}Y+Y%XoKu&+6ew3-?XBsNDaODsvDlLTV_cn$*szn?PAdH;%RGP+9xN98$_{ z?*DOi5xaWktX`&2R2>40X|B2wXRlygYSZEbf0;LD+zxAwlSSI zKkZ$p2C)D-&K;)DIq|#(Qhu*K&Rm*ZL!?K?72Pxx82bYCtZOvD^Pt!$HK)u6ej_v} zm8@^hRw00ABdQAP%SMBkJDXe6I54gEz z%W|3IweBCQ3;iA~|DEJlVzFO9&O0&8SI(`ZmTL%o8|T@j1NmUHK&07*D<=H5i8jl< zyX~&i6fpQf66NSkXcKiYiX=)^R_?AKwQz3&*A2PTZ1U@IBkDMlOL@*+=(d%@dz}>U z!BE={b8u*0`(WjUQuSNvfemljDJEqyv<1lIe}$9rr5>oPCX)%;!@*0HYr1rzIbB~y z@>Rj=@T3~Drd9l*FTVu_G@-97oUMDHO|95H^K*MQ)$_G!m{8#->-CcrMe?a!t3U5~ zOC98O&vorE2o*tC$+(NKD(MEKVEYc_30mm9=lx17shKi%N})8R%)nW41Z+gPDhcD( zRFzAJT``sUngVK;ffBwoU(|!EfFnZE21$57plrhOij5yYb|e-8oGXWY&VCzCSBsrt zbthX>s{8J#!`s}H)|4XRgEA{ zhNR`sL%?w-2x)*hc&FoS5`WMU-xqThP4Dn>8Jntvzffn z7GeFp0-Y%1BvC_#SLS$ehZm|SpGFsgU`jv>+&A31)56hnKDDi+kOM_PRYdGGd-lAi}VY{mz_% zJ$C3tMCZHT%r7NfX7(y6ng;^3hQHWkGYKlqH|v60awUoo-Kbrnhl zvD*Z}FE~!#$Y=>ukLz-RcMX%g-~Limq#+BkkuH=*iZ%E#^$8eUkSJERx|?ALi-L`# z5vQqQdPem03E>We)o(G#k9sT`ogjIw(^D1k;-OP8rZe>?h| zEa@*zE1SNw;s;HR}sbvzcnh>;eFW|6$fiJKy*77($Wov5iwp?lg5#)T&h7 z^c^lguHN$>f;&p-Yc0#zLlr%0)HVXY4lm^mCUO%mKQ-sMg#Y#}_WrzWa-ygg&(A@5 zS7{&9x!WFnnsTZo(-9GJ0hDsqY3i*xlGVZ-y0gAFC2uk9*Yh_~GR6OJYSw)ZtCX+g zgRGy5H3r|Zf5}FDV!hLQhmGhM^V76L_kGF=`)vWUrhD(#P{bynF8T;L32S?qTK87M zc3HX4t>~UoZru(+39n)~hiu&6+1>s8MP#Z`w^l5+hRQEeRCtLz^St^jy79@rZDiA7 z)LAO>S5wYC``4_8y&|sn#F+9xCAw8a8fzH)k0klruiY{n$Cu`#xm~;n?U5In#;se)vb= zSw3X%f(E>EXE&Iv(MPfd-MfNXQF_ZT)4Zp7Jdjv1IE5_Cw?K_>ts2UTk4H@=`9(|O z<2XmXxj>F?`aU}MrevkQS@ZXrg20*|`N{|?_Fl^mt$s%su?*QQ;IaBFK17(HOKHij z__99V#ml>Fx-0BvQci_rl2$4Cu17i2Wof;~>}?FSHKbJ|J%9>pq5mxz;!q|9b=CXm z(xYjA15qenlv8heRO4+r`OX2*38bRWQU6J2z-zDC9*U~ZklbQ8Ck8j{b9ECDgj`T#z!%N0^~@!jXu z0R1bV_r`<7aDPsLJ%vY6=97G{lv%3|&h3(p)XI7UU9j*%_FbHG3GCOlH`StSS+MBV zMWb+Ew?C01#-92H9PwMUSn))^*-I6CNX)zP=FvyB-1_K)j}}Tip$GERKIcR!+O4M! zk$)l|BfYM0e0fc)Dk=_45UjawjsePrKO_X=fO(r#FM%f8u}5ChQ7%nhQn9vTC1pdl zu9of)vs#Z!lI=wnV>{$HT=ccg5RhNoqxYU|2K_VUg`O4{h_!+LoFyTAHAwAfh5t+0 zq%rPEGjL6Wt@^yH^}G01rvMwYPd=u8)f#+0+bfD&Y^z!${zrlpyU)DAJTU8Dtw z_S~QTSZlp5np~vgp0a%e0OVwX@BU*v-`z3pV^`2KF4V7fR)2b3#8y8prE!s*9noxx zqOWZiyqh!SVfj&KM^8G!dv_9_VeJ}!r(iw}-yPavJ%9l}B=-tW`1_Bn+?1VQpB5+B zCNs}dS`2?$+%U~e8(pZLa1v^GyT^)-$;CxOjmuMrr>iOdA{*H zc;#j?y)b&V0OYU*JcoK$rl zXEG0h(2ZN-gb&<4B85JbL=FdZ9D{|ORQ2G)NOqdHj2eS8sG-^C0dI3&9cPM`s|gi1 z?ntpb*+^mo`e<9UpOF9glgq9Ago-7N%I0@n7LBt|;BwMBpJn~fN*Upo&gL(X78~x) zioUjxm>XKo`(EREsbXpcTc8ZwY2k7}VgJo=-Os0-;MXfc_Smn6`-s&htT`@PgL}KP z^}ceKEs}tly$xIav|YVskH-*G*3bzN>p~$5&B)NQQxS@oJzq@nSLE|un9!A(T>nSU z#C)j2twlLwG~;&MM5%oLRxnz2LPOL=B_}Y*?P>s||B2&J2y*I`e}UevZXft8PiVNE z^?SpIq8DMiv4h}Jm;QD?WHsqy>x+Hcg8{-zF}3PqwTfto_^5B!X#aX>m!)G&f!%+s z2MY20*BAcduR$Bi#)V5U)HEt;&(kQ)41?1yIIG*i#cgPRR39`Gh7-XOH6jIsmmozL zGSM7fagA|ZA5F3pG-)5$wGk0rEu-pVRyCQU)`#a@k5L-JQuj6#Z&W%jv>_BP*(O8; zdn*aouvMX7 zpA|JT8wDuNVOWQ?z~X%!Gbu@X3A*6Yhfb31*>49I@|iiv?afSwuTl#cp<f+ardq(? zVt`NFF%1sQ(;E=SzVL{$IMJMzv3&L{#ZZ@>QEyZRif9*|ukX|){lU8EU9UAZF|*(% zy)y1li&yfcL1&2nT1{PgfRm2>rUD5umb_0Uz1laPH4-c+Dp`4MH}V>163~IEk#UHt zLHCwtK#5hCs9)y%Hiz!psk6IC2_O?H zn9~!iTQGdOiYv~2vIOphc2Fp=-`EhXstID)DfS_!(q5S4bf~7rr4Aivm*Sx{x(l_7 zyZG`2eNGkvEpH=vz1?#5iZwRx`O2VcJH#m~={wfS$Qz4bXSOEUAYq0m_zDxSuxp)bz^5v;-FbTKep)RCY+s0f+fy^)|s#P~xdjxjV*# ze5HcEzLKJ6E zHxplPHLUrF+%1bK<=2`sR4*9yljcgF@e^U`j1tM6FZ*iJqE%XS(wJs1U8_P{!aeH+ z_x9%>sRdSF>f0+Dy=w=q4Nwg&sSKHnLLaD$SUtBClnfW0iYnVzBgh43#QA(Mh_XWZ14rkbQD( zBd1y#j511r60BQL2_!U}i=wY(XlUL}p#vMCl0~r>yss@fN*=f1K{J zYgCgz806@OJH`L(Z(sH!{SVL&W4ps=f-q=Gye37O%gjzG-mgRxDC>l}?B+M2V`^3X z9E)2IZsoF7-Xg@b94}K?b!{=CatH^culMZe&6FA}ppa8xE>_^|e!oQq+9hv;04(V+ z7&6?olSOnzC-J?!Y@}CuE~Je)YuCYk;*g4-^JWr$K1#|Vj(z_%c#;Xa$oM6kaQ%DY zi{darnt(-vCQ$0)%8grg6KVR-v7`E_=E;J36flb~LhrNN7Ypf|=uf#8S9`t3JdHg7 zraq_3fX70lJYD^Mpidz+R9#(IH!K5JRVGUrF@Yz~XFp6lQ_=h438C4x?jJ*|qLQLl zk@B%RIPop6AWF8OO_2%d{<{K?hfXWLf{p9hs$;ziAsM{xOYHh)a}~Y9@TA7P<5`Uo zrgt$0&8r636UCGDicgK?z*ms@y)tG#{b&1Tn_$mzU}FR!;I^cuQlwud-dLcu=oehM zH`d5B(`n`(XVc;Z^(!a!axGWl#K6`lt51e}Vz!}buWWb9Gn-p2pZ~Bf^1Lk8U|~YE zqh+r%yOk}BUgrd=3(tRV zd7-M|J=|HP_}1crz^sZ^kz_QJ)9l6os|AU3g%hiCmA1r3LEGRHD3rTvFPo$ z65KZakm>c!G}6f_HF!LoZ^BD7wx@!o8*^3I9 zU#+Zo5IAhvKE7BA{b`u9{RoHXs~b=+Z}sJX*GRmKjF7hz!v`6uk7ys1f{=#!8PMK- znd3Bm8x#cm>`$bTfP(x@Bag2OmchvmkBqd8=%Oin@EcdG3T;oG7Y&s>$O}=UP27w+YMzW+HWE5RmYB(Tw?CUXlYVxqB|7&+%P6#3quH8M z_NGDX&<(0a+p_thdP$rr?82he81(n;mg|Y`;7;9+zBgm zUd_Wi7w8*FTE{=B$XS0$O*X-aRBPNBsyl%edx2cJh(9r=;C2({q!L!a1)q=BwA#4t z9C=~p{cd5=Z6qZ#hH}+VhV{LcW1Oa~6s&Ww{$A@spZ}w6_pjUUEmN&`YRJ}nR{RDJ zobo=K`>?`9?mTDIEZUfezVU$%im zgps)xdd{Ut$Yn{H=joQ25hK&l(dMf`(eGRuzZn!f9w&0(Bz0w=4&7OaL^57H#)LcM zsiWpc6DZ1NGeeY?#~Oc}IUyqjesMMM%bKF2_cNHP0l*yVzTp}iELSQfbIUjWb95O2!Yc%-TQk{`T`lzl(@z3AxF_sSP%yQXW7 z06GSL8(%o`!PrNQNBDu0;Apt~jrIAx{fUX24ms0lykA3`^-9Xc({G|t^63UoPknFW z-QX@wx)aqU-@6@*TL}H|UVeBdlVZ491%wt^x8Gm3OT_`K7A_C0j23|V7I6Tr)C~Q| zC74N|Dzq>)Q)P!JcV^RCkbgo8AHLlDnexB~cV$6V{q^?I>3wc7VQ14tU4FB~(Klb- z^OuyCZWkCeFEmHuv!y;(EQo{kTJya29EE~BqrYESUdq@DMv0kt-n=EKw|}x&ze3Xr zwAvzKw@k}^daRae&W)PxCa|Qj+yA`hB=O)U1`ReWY(-l1i&?CzOCX8Mx7qtnUX-sO zXW~PDj&XgvtoLFf8H--4? zbN>DQ>yjFtHJvd!*Om^&tb7ka$of>s!QB+JUXBtZs8U{Y+448=>jwRba4ZJvY#l?O z&%XSObaxt@`$j$An_yzFP8Oe?-N0to?i4vXUA$6qDP7L;m`dhlz_%x^%zqhScE_C} z%yJYVb|mV~T~Ifex~8Q5{9VF{x|hbLRqn$i(Wpzgnb9fF?q{Ue7zA}dvP<000G;x? z5|&|2L1nA?+1~v)@m85+;8Ww0?*&Zd|MwN2+(EgM8}idYzyC+`CcU%2erGs+BkKPC zMY#W)*7V$F$dl&;Bk-4WxDFO$)njAsA@Ew<g zRIS(+*Z@G@wYsL&M;w;`K>phj+VBc-eA9+E?EER}w=&-Q+jCOf_5oCj1&4E&sBJe| zS299G|M;6Ot9h(kV^I+NRoE8Imnrx^_oqF-7Mu99QIqZGx9?XomCn6*f975L$Lq7w z&Vn(GJnvp`a68W%jQc`M*fF1$qp8u5S25t9&D|8NEi0fS=?GKt6qNrIf|eea(6UUF zmJ&mXUQ)4b>)&j^_g!>(@hw^R+7{08ZMlxff_`80ev?Pg@(v$b~8ogQ;-1@z`aU^4&hN_=g|=01CYCLQcnX zpZnp9wu~eBSygMt;9uyXF!=4|4zAT51&^#3=9#iID=^LCX@6w&J?h7rnn6_`^}+4` z`I`W-`;#fx!YGXc+tqDsT`$sDf|+?Pko0Zu#*z?0rp8V99{ZI|oivH17~dTTEzi=~ z`Z7m@bLj&yiSw0k8HemsC^o{9jd`B;`DIknSn*1O zuifluLF47p`>MXSL*+u7x49Xkf6pMa+DR(dYoDq z@=iieS*Lfvb(_bpmKXv;Z)C`<@}TU_A<>a2(_+^%XH!{LG3wq6w}TxZmO<5Cqc%cj z0l%czi~j(=-MV*+$*89gY=H06ry45X#0l8MdC%ph%l)yC(T!bbGt!C_7~1p9(a0S6 z!RPX!iz4aIKke@n5;l_ip?Lp)>toX)G1WADjBC==A?so9@aCsS;Vzo=2dZEH4^v;^ z5cT%Fy^4T%nvh>mo`!4r;ufO;F1E1O1 z$>%&X2OhrT?|SZ1E87#&$)$N~_OvpovgDP5$`_zY=eEW6w`G=_1R8*s7%BqOm8A>8 zr+{xaB@mhzaH_)A-$*YlkiNNJld>S=%S$c2A`XW{xgCdL3)IgwngowPh34P7m;BWW zgFkedAl2oIGp5~L#cwK00sWYD;o;t@yywvZ=o%SqS?6Si6`8fGQJbkP3+2l{s>R3o z*#%0({4i7BVFTKAedC1@5)70E>i*1{#yLpCX*K$(!^B574sEEcwky&&p@PxNg(=PRYU}2K64p6ET5C#I!a&XPenVm<*}=>{eBQL z`0FbD6s=oZtc^H@)$JWGe?_SWU zfCd~g>^}d_z_P+3@oO`sq4|~3W6VjP{W6l2H)HQ%ffGUp2 zq(|?r(;D2=xHAzf=YNk`XK6`F&nfI+&0{f@?pJU<*;t-nN2r5;>RwW5C?(}`Y)uHs zU}Nc*J&d@{z18zM3dpBd6=XllYP?CGBWCpxQH+thb)F_Go@8FPlfh2j3XAQlbg*mt z*qe{WRbNZ&=|f(#ZeU~#YjrcmPoca7r54Azxws&}fHw`yo6p~}f>aGAip zcFDRMotmE4RT>p?GH=GEqS-JzV}=u~YN9hk+sq60+s_}$pJnt{@Ecl3Mgo+t{Zr9C z$@4QlbRSa$iXvH76hkCH%|rSd2Ul5n@1;tsQZIVCJw@HFe`-+8aVS=j5=!vjZdz2c z|Car$3GI@#>&s5Lm3To3r)dobj0q0G)X*3qW_`=a#|06rZ`z6%AG|v@EM|bGyekM|Obq0h}c0G-xv`$r((;3)Qc0MeLpU z--+NbI#|vp)eeUq9e;|7W+?DDQAyVvxm~>mfANd^9I0s$5myC@Sr=U^vIB|dC@jC< z2~$HO?xn9&_ctBZo7j>AvN|%68a0+LJDUMN02NAp!^Sl_0o#ALsj7pN+6r}$x#%=HH)bPjdOGP?dM4;8w6>(6;2?! z(KWmW~IOQOra;JCpvRT zN5QK{JM!?~w*e6Z2%EqvGoKdfSkDf`SL6lon(QVqiXL^&r)(L~j# znVfzD;{Gn}LjKy(yHI3gDAT7zbizw-Q`}S{KrWzgCEE!sWi; znp1QAwQ`mYj3@64DEE5Q|L^r-nU(MHWg@jU-9$M&Z;xr>=Zo1>Dg)d!u1M~@nZ;xx zWU*vo-|IeEKg-Oyx?F59VEfMl0IOG(F7&Qm*1MlZt1)c(XCp(fmXGS$(@#$g*x)R; zB$I*$m=sjZ4IXOrI_f&pid5l96T?Xb;in2I1^@u#vp=$!?b)4rPaKq$TNl{~YtSQZ zLYmo@i%%T1EMu^di2JFUT?YojjZfy|eP?B=t2=T?Lh=XukP2Vc>i)HX-Zat_E`!L| z#NvpT^?90OaEXx*?W*eFIBFE;zm)TufbDh_3q+9=20(n zB*bFBSS=43g~)Sq6P~Gk=U2Yc@G2uYzKydomNw}(TkIWOLx=xB>} zyVuNfthHn$7wq>~n_T+K_$G7XgaoD=tz`0+CZ2ilQ&GqNlrhln?tk^^<9{mg+Q1qe zHSo=m2?fY5D(+kh#$SUqzZ}J3izJ4}&Io+(?=AWq$HP?PN#QcnT4XqGU~CrWvi=0X ziH`^i<%PMvT{Y{SFK`Xz4Xc;=PC>bGjGsfL-eLRbzt@xC*~!JWP)v4m&uyC5NDM`f zDY~_M|Y0I~52rQ&IoNr5Q6eS7O>PdRS#kb0%6uy`nt3_tMk@5}WFMqig zslQA#Nss!o;+Dbu_umiCU^BPnUkgU_eB)PkiW*fUTh~l!0r}y$is&c9p}rF$y5F!c z)1tt3OWCTIoqpYnd2Ri9m)Cc9}*E zqD35oJelinD7YXM|08c>8}fehD`o{O>YPh39_J;6qQ_!CSW90kB$ed{iS4`+4D^<*BNc`|zI-Ugy4PO>QgY&D)LK@PgduDnyXZ@l)2P-!&N|ttN^YKgLjYD+p@R ze{IVB)~k>}an1PBy!F{X3lY8iMO4(T)-B&@#mXar-iKlqv6cR+q|BW$)YnoTZ|0z5 zm{=8ZbkxU)u}%+ELLynFn8;%TnS18E{}>~L83+7Ng!V?trkZU2NF&|@6Ut)3+-vyN z_c&k=hhrtK&54{U_SiC=bV7H$;`750wZrwS?5r+h70*J~AR2Ul_Az2Q!OLI&O2VzL zt4i5-6GMDKr*Rmr5KPb+IY3BmI;M{$VpV_qw@7HW z>5*{y&JT@DA*L@yE{90)j&>GYxA7pcrx6gv0X6qU2JYRtT{B^^!fw@l(oxP7fwtis z;WsUyxFx(mRRqcBDPsPtJgU&!Cubk@3o<*=P;2$+SBcn^Wr#8EJA5il)(_W?8uJ2K zPLA^Y&jfCvn;p?%))S%i&ANj)Ctscfe)zj3vOFCpG;($8o#w#I8_~J@ct<@*Jf-Li z(k5ecVW{=M@9cz%1^So=Y6KsrKJO(#rT3Ysx=eT;gWUJ5+rMm54P+O$CD^b=?r zrO?aYm(}rqH2|1-(v4YL+rP>KF4%(em%)DDfqCepcojbS8QVN$jN*)I(!}WILGbw) zw%Fnu9h)rZi20rXLLZR`MiPVeOmI()&+qR|wDbMnEX&kapoVveavx4RHoxPN zuF11yy91Kzn+HB{hZ%u0WsV29?+~l6c5b$7iwfo6s#W}Fmx#&s-zh`}4`uP_5&Lt* zHY07K>kx_zOd_PXa}*wcMv2&ws!%yfKQu_uK(ee&Lg zrvBrfC2d2BK?C2Xwbdcts;riT<~-toM`?s8!a8>!$jYg?RC!G2Av(Bh-|qYeYBK3; z*sM1HO40tIU4h5FITeZZ-7S4Qhriq&l1}N0f=yc9#GsM)kI__lkz)mxSGm>tNcmVf zqZigc`4w%xx(pTa>j40qoR9XfX1!H@a->Snt2zTbPM#!?#3F~GauuX>p9ROLF%a6< zYi|+tyxZ^=D~Kan3p!>0gVTILm>h%6ClDjW#E+n<|9kcVWpQ!WoUs#AB}I#HT2K_W z;0CQ)YC582ILyG?motl`bX%tU!zZfgvR$U4ZxE!a zRyY}bD*_ER9>jLe258%OJ?2emBJHy{)XKrE#wj8|^$7aT^(?j7yJS2v(Q9(Hf&3DK zOiIs>B4j5SR5g>o7bx|R9v9&LbIL8p29Ooy`?h-D-^zWxVb(|-j?9jWs_}|ZmYQrV zl;#q^vwA&sX})%zFUyj`>9ImAj!2v~9wB?FT~vVfe?Ucyz`d5qkg#+snHUYs)<({a zvKHcTTV6oR_Wz;@5ySrJ`VgKK}wuACz`F5{gfGl);Ddvvr0engp5Ifn;-UqFt{>c zRE!w9HrbB4i~XM<+V`umD&k4-h43E~pLqAaGJ?cS9)Rjvk?I$3#+jTHjyo=ceb#ei zG^x5g5>#7^<9Z+tSO;wbuN6vQeF^Ud9O~TzFf0N1*pKcZtl%go?{FBX7_hC>@;PU} zRT5s$UW}8dXv+qCHN%0)hG_Wr9|lf&D87w6=?_c|z5Ycf=gxm-?$W>}O^6nHPxzl$ z?KeJLjE*L9~^QRr|6|3X}id2@xn^Bzu z)f^J+3L1)rc{Wj%>|~4EzO$V=+dJ)c4|@|>QPFb_9T~yz|F6`UA>fxWO8jGB(cbOi zkqk$@{O-*TmoxI#SNcYk$Ryd!Be^nw4(1kiEw$e zaM{gS_vp#I@O|z7ZgTcI7fLU1Q&23l6N?qri5uDNOJShr?Ru4mqUIfzAnx*7U)^$h z!u6>^(JQI4V)`>Kcf-6;p23{&mMw~uWwPB42rR7p<6~zetWeB{*g+C)d)0td>N&=6 zA6UD6w42O{$@IX_08FbSJMZjW#_*p?v|Cnv z%!*7)C>TCW-3gYx7B$0BFtk6J55^OpmE?N6`SopgWmn@Jvp5Ap_t2NVpBj%N3t=?A zL8}48Uj9!QLJ;YHnT*KL38cLF(RPE1t>wnM!{-@BU_$(-X+SoEk@Hn4)Q}-9QFcDY zZ>1Y)A_OAg2sIf}`f&B12!I)kYjZ4Ed|B{1G9@8+^S#jV2UTh2O8p1e>5ZSG3C-*f ziX0XYO9Xg6avpUmtgEl|P-y-KR|c1K_WN4g+dzbU{F8-=q+N8dc;u>!dCwx79aSKx zF-}4{6i7dKMGZ`M)tA33Ow{^fmO0wkUwgdR88-U+{bJM;Lekyxi1}>Fbd}OYhf_l- zp3Oz4>*6t-(y!9EC98dV=wedq(>+oh#o!<`bb7H6^w<2#VdCN)x}4FvFP|b5@fhvU zT7{y6)pyc{1*qIMiV-uLr^sL=>oFrT=)Vu-RY zZpr(ORiyt!QDzB}2wayQQ2izfdkNtmT|Jp+kik?zB~KiANos9^x6)M;G~Txei$SVHWOx7rQ-Sr~= z{qBFt0L;8Lsmy>Lh(f$h>_rFCzF>P0XZiAZQsq;pP8WwVJ z3b6aDSb>Ha-^N=tb<@EHN)?`QJQiH`S7o?0y1pl>lA}*W6V-slr8A$zcbdNYRpuSN?o`RbW%`(%QnVhPEzPUJyhk#(=WmtRU7uDsBhrOecW$UqlJSkX5+Mcg zBiQwRleX~%`dbE}q4NOXrz*S7+5Bu=6o&3bkzN=uf()0iKkfVCbe6il0|+~=%Y0`4 z?2XRR-wLsqSigm0cqKL^(EdTfp1%94`sW7*#+XFZBzUN;=oWnL_L+iXEM$UWS3^~) zkV&kXHdLjUJD}NMiWu|+Kn#48;LX$pYTn&@>7W4C-18jRKp?+-@Id59I{X7!oV^Cm zH%4S>%gPXB$wi?L?|kFzBPZW9oN(Zx@W`5|RSI`sqHz5+TJDHVk;*ogoo<$+N4AT;y{kLURkEy3a|!3A4xBiuJCXkU_o&$t45+}8H7;{%pS zcD2!-wg)_3WpQ$=s=Q>01MbX=R+Hhpsa(&tLVgubYU4%Wi~qnjLn_++`THAlZilo< zSj0Mo&z{}ACaKK$G^jR`^n z=`Y&3-ZG1yv+&*>D?1!x@5Tv>sv9RwI932iAE#jdJ$ooN9!#Yro$PJtO>RvTU({T1 zA)*!g&(R}g)wNw9hJz3{iU3-@inU6S5Yu~+8KQUYlNhJ8a2C|bCEMv_#q#hwjre| zI#2BXy(>3G)DNK%{3rkXH*Z=3IN3_D0V%nnN06xFHzSP=C$?lRmAl$zVIzJl-ghUq z4W-3A?jydaywW@(aq4E>9SY@d`rlSJBju(TSEB!?7cV`z#H}j`2{vt@3$9GKKI!@d z0;5a}PqbmtR~o^J78$9E4K_!Onc*~L!IkzFo;)7V3m`A;Txh??1B5uuCCr1I}#1d8CgKfr<0e|`)OQ!6oMM;y`v4oQxMd~=;0gdAlsp*d& zg-?X^?@CXvZ|JUWb2UNNN38u4u=PFzLP*EBadmF3g|)!%HQ)dT9m-$wLc1#kUy}4; zsf0;VMSYX43+cy<@s2%Y(5H)7BeZzMAGd?o#0Y5DosVtHA8t$*u zU2VIJVo@K1AiLctb~5$~tuZN%zm;`+h4|Kio`v|7Lm2chr+WNDDO(qhC(p)Lexb16 zMi>77*lY1tIivYVHJ&LaHFu zzV6QWp|GgFd)N@p_>$214YCZxjg9V|Ixj6XrsbC@NSE0vy+3>YY#0jlDYua7^Kc?mFgFMoy9PC0%xUOFs>yn)RY zLEUqMmht&hIG&_5pR#cj>t~K@`*DthTC|t<($ciK9JVSOYo9ANBBEEXL)<}p)atTL zQh*=+EFL>DXS3k@*>Ozb_zv@Xl{Txi4{SS&NhNA^$)oc|#qKj(fB3Zptycj8w{xTU zq0Egz|5~7S&g&NLTn=w$V^GXj)Qo21NT1f6`rK^(I_R|ukLXf=5{* zQFkt)3TR)_o_w*o2&1t`0QWtmo|U_nB=Le&p`6K4 z>N*#Uf5Tt9D$bHxo&oaQHz{4xS4(-6>K&K9SYa~aQljs~5!wIv`$+80JHIIv0e5ugPyq~m@Ln&}SrydyF!5Nn zUK=*9`e1B@)KyoD@;M#m=Hx9j1!94BChd=YVMl6}WkIYw)9zYZjx#@cL;-Rra0TyVx+^g1elRU`jCt$sTE})|LJU%nxecebETppTX017;$3W z_d^Sm!Om(l%Bem{bCm`%<+aK(mW?}ad11|`TOplL@Q@it_OV{~AQJc_r5fJ$0AgBs z_$+J9NG!7{E0D%1xYf_jdoQ$E3k!K2bgO2+nNT*KWd@Q81le&Mc=Qq*Pg1dD zYY0A=&fg4yWi2NS|Mfqw`1Q`W#p@iuY3r26@8f06o@;>ia!53O;gM3|392|3-d4t} z#Wh)05TWg%S0<1f3|R5+RDC%|56t~u<{B0wOskeA-^uz6!4>!i`Tl5O_QU$hWd$$c zNA5ee3GwDD7hDvA^@1uW8e2+HeupH{C()HOmp;}R&ntCt7Cr%YTmN_z*>TVBi+Vf6 zfKP$(FK9E|Sxabik!=qfpjhd6UtrX#6;Jhx)fX?lR|;-dZWu)Mx=}2ag;SW_pIX36 z;Xn(|le}vC3lX|B97%{9xr#4|Nu>i&}AzS)cJt`7f_D#Prn^?z`9ZN@G8jFO$<;sS{zN+4}(R~rusgp46mb5*9WAezm`8Do6pyiDx@?d4r2!XfgciVQ99C|`xyRh0Z4XlO?)^?ZOR}igC}zKI zt=jw#?-m`ZFB4L>$I@1^$2&ZPe%3?czM3qkKqn3*G(-#dw~nh#PU{7F2BJP=3r0G& zoDpn~aVSk9!Q5yM+~9oMN0?f2{8K;*4e5Q%}WQwBbvux2WhuJO-=k-f2!%Fig#c)5ca*T8}R*6v_D z3`hN^<UL3)ik3lgr4KnAhZOm!7=to6na{8qBsE1zl)Kn>Q5aD;?MlxX)kA zJ6!Nod-RS}G?QfC&w{;M&->wlSSwB};RqHQTlz`b*%9nosd{fQFbdeaa`%UJ@-UD; zRk`hKGo}O2qRbgVU5XUQ46)ET%9q#kuhn&)lmi|ejWP@CMNvGd z_;Hj?_J^PAJJc;MR#+sHm!j8e@e@8FkRmd9{aJOX@wLq`Y*N`>D&H6^eDdEdsC+k_ zW&2r?OSWF6O?x;c__S7p<5Z4T*)W$)EZ3ffh0fdX=L~|52lHaRPip}Um&x55D2bvGlU9HJ-pr;K3j#=r!u>A zw-r=nxbhtEUuJFAnt!)l9*@3-<#=edd0WDdP`48`RSrxqh+J$SKj(dl8l5I4xpb+O3RcV_v=t3iaEz(3%%b zF5k)w3bUUgdd|m65U^RredTMFmM3(5`tj-865Phz1A0=!nWR&pGu@)D_xN<{b!-id zF*4)xBHc2+_-TrqZln#>v3~78>O2oYH|KIo#Btc(=&&I^C8IeUYXktHwNH5)hL1wW<09^P8;!fmS0E1@xh zwm-JL1?;V1WQ`YcD?%widrpthj5`j2t4dftMaOD?_g1W2UTntI!5Zu(%RPLO33#X1 zc+3TNLZreQJYKlg9U#qhS!~Vg++x(_<+VuQcHitn^r6c^fw^&~fMr5XdR z*^``HQS0NO$lR!)z2`a2Suw%OR6$)doNbYNNZA8)_*67`$=OeWOY1@qj|=9qvx8$e zBGx^A8#$?uClcUOBYK)4M_UGf_EJmVl zWDzWCs_*!OnPC$hLnS^5C z3YCJZ#J&$zo{-HCZN0fbArLYp46 zf1UWQb*~V#ZKCd6dcv_0=C6njzBGme9?81bJ?d8?vY0KG#*cf29v!J=DvImtTWlP6 zPYJ~+{kkQ3Q{L*uqREeD3^+F9pKqGSopa#HvrP8yjWo}1v+t}2Y>@%w3f{O#c#eMM^yUL> z>X+jg1us~KuBm9>w;csHZNpk!ydpTvF@L*Qv5#)pyd?bt#3f&971(Gy-dn!isjfI#&ys72YrSI-{Cuf(37=@* zcizs~rib0&q@A)n;Ay}U!QxJyhin`C7dWImpBB4v)(vf@0Z# zIOfFyInecH$Cc;x^QF5RrEx{5$te{x<$R?@@egM&%ZHoK_A|b~Pil_)FIue zm7khi=a-G$w_Tgr&zH4^DqB~}i?AK{*i0y5;>n>IPGlOMb9o4W_Vj&!`0}wM z{Y7Zo+2B@F39 zpl^4rPk2Y@RP_2RF*C4fXOAJNQT2M+ul<8V`FQo;zd~WW8N%ja6tJp%6AjYJeLbs2 z`yPHU@O6iEZO3=u zJ+Uiv0i2i)Uxczxx-9L%CqI=|0RSI6S2*sJI#IJ8%lg%Aw9`8XvxS$v%LA~4&wcSu z(quz_RteO{E27M|y-ALJtoTyHG<02LeNzcG{dO#s4jB@9?j-j5XB^!eFZDeJf~NXE z@cG%>#)j;E!5JwX1(@krS(;Y9yJjEv3z(tPX5~aK)affMSyC0p!ZdlwwBL=ElNvE} zFl6Xq6Y1cC#SOX`MzWtwr?PKuI2;k_?M9xJUOVN?Cq;0&7ZEmUzde?d zfyI(A{OkfQdfR$qkeoPNkSa^idU9^RVo^7tq18n3PADOS+s_g8jD@O zJjPKp>Lhk&8VghFlc)q$A~yHyjPyBMYB74+;5c@EJhtg=hHpuO>0ativqGvY?iVAz zXG3<8C0}&%$}4qZy1P}|Lm~v+F4#|(8XXucR$5yKBk_nYJx;84a&6!%)wk3qsAQS9 z7l&CbdSbm_wNCBM`k)>x8gOvBw3aIzIEI|)PHeH<$OH?R?QL)}N)vQyyuZDS=`%>lA=0*azxc;q=6vCBo`n~YH} z!>4Y1SoV;!pMN;4|7q?z1-0t(75?2!t4OX==3i1z(8>Ps%YJ&B*LYVJUFU69+0G}r~8C>xn(HUle2(n^lnSXI- z!-o}QB?7Qm+qL&%qSc7@lm|MD$CE{|gjx7RWJM1J>OFToU|Hd(FO=ur=UOYv{E^Or zxQ3P}1Ps_g13@3{tyh#QK0HWif=I9g+wRkEO`wEE<0A06QxlV0S=TeO714|~IH>X1 z3LZ1!Hnd?pnZV@or957l-zsMTes^F$(snI1|4P{WwPk3a+FSZ5oRx zi-TT(8b%V3ga%PYMjDGJLZWa-l>%dX>vEiNf}HaUXFhHM9KLAMoy`Y1y5$k(aYVi% z0Q|2P^QU;Ai=61tzW#MnVM#BPI&YHY#Dn`<9xc()KGz$d=4>AimsQA)OM7kJNVH@W zUwnOZs&I_Ki#5r_Qowgo#-J1HAKV#%@g7yJ2i-@CxnKs}(c59Q-8=o2Ux{%2C#J)D zAQ0oQOk74!Y?a%x&V*s9&Imj0ejhBQCI{j`AsU?AfN#LXGQh)d=~?*s?aprrLC*T0 zuZT}9P_d)bK*DuxmudDR*sZCx>9_BbxmK??m(u=UmH$6U$NrsZJmb+vC@?WKsOs<6^VZ6d5g2$95Mg zM#y!VHAQ9dW4{7(N5Mr3k$b&6T6`k~BYN8}{Kc}*@9HyB?PliekLwQ?d(7f{Y2;id zehG9=Gp``)`9mOy9?-7J&%b8J&+aMaAV#*HF-055iQ#a|ruz%^(&-0T6|~-LpxLfb zHPOM?FQlsZ6(`;{2Ensvj_c)(>T9>}mv~ZO#4fg-IvoyAH$=ICe{u(=CZp1SZIC=y za1HMAKNU_TxmjCR7c2vGiJ_tW;?x$;d)ApkCDFewl4`kQoNq1~|0-9@vBP=t$0`WH z(*K8ziTqnha91&UT#@{W{auni`ELc6CkspSkZa`5XE9NJS8U?uU~sCZVN{xILUj8iw39!mm&oPdYDNBssx% zfTQtn_WWs$Ra?7TTfWi3YS2mgu|oi!=l*Uu0pqOh_{j;(GvWH~4hl-tyxmp$#JCc_ z(N=divygmmmf$+Pa0!iGa!K#!TRBIa%S$JR;!LX_R|#6(_#Rfd-#e7Sw#6e2C9PTHO%)XCHGc{{68eDY-fFa6ux<%C3AXZYgs6BSehtK zWpEHZ!yrDg&9A@IK~vXu=Sj`{t1$It%q-uON{;J2m73QlhBjLdv6?-`mR8}mWYucz+8NqR=>Kq98Dkl&hfhrL}f(G?wWMP4}Ej2mSX=sPTNSp6x*poHig0IL) z`JJQ0Q#dE3BDvcL+)Zw=T+diqqereIa@gQoyL9E! zcpw1F^x$&$HiT@_stey<91s`S`7z*#+3>&Qao-!ZXFu|hX^9#PhcYnI@IbK%M)O$D zc`1PlZO2ZlgF4K$!>N#;#4`PCmQOuVWp|{jdxFdF==4lO)@|mYPvn%C^RBcJ7fK{lLn^Vp621@K&R=X1|xA-)hG32h>ec z8zb7K4aV*c!n<5S{JEl1JQ&688`UdpzP3I|b<7O+7C#EG5KnJo>sYRwk1jqZE9Fhv zxZUSmFro>r!HssC2a2i_Z2#sJDJW(gn)f4VF2yChcK@n0!b)ndm!}TiJC#kDp?n7T zQ}~D@JzYJiSlg9QK|vLDl<@6BgZhO@E5nAdT^aacm19QE@2xi0xaE5A#Bo!W>Op~7(CUM7og(a_fx0Sr-~@Sy|Ingh@NP2sSF z%Js{Qc%iT#zWRGud7JXRe!1)Q_L+pyy`G4STx`yru1NmkHZT0OH?y)|`Ir2jNIZgK zIvx5o!Som9y4JlTX`4iA$e=g(AKLCRc5c#|wr?)sptQ?XI}^4*Ck3&7X`I^U4Uo&r z$p*nI+xdq+3|c&nT&1@d5c1y;-`jr6&SW5{>rQ0De^reb!=e~xRnYN??R8!v3fDIV zhx^W*PpUr_NEgw&HO@ttjh&tNSYBxypCpb?-GT1bI{5!s-KTpazt?=W)ri&bEvdSG zs5FDQ^=f@}C5_;ZW&Lr_RyIi;l3L*>Tf0sSoml+wuHkP*%%`e@#a#7=;Pb4=v(nSk z4ZBzM9t}X-+e)kZMp(!miDMp{=<`!xAORcgxkQ8;@J$mtL2PJvZ$rqZ2(s7Y?Hte%KnH;UQncIg@Tcyn|c+ z&wY$M3bK!a-&EFcjqdW!lt;zBB*Aa*KAWSpY{Fl(5MMjoiM3l5v=~%D6YZDh`#ZeCTlGgd}NB;U@ctA z$%|n4eaG%b@$q`+!A|BRs^C?}*|3!-o1fdmX~v2p6PGGFSfiSR_Hdu-B7D%Ns+qqc zVw`j)#izSR34S8Ct+2ssK^A^u`D^%cN$jvlD_8B|sKovv)HBXe;9|X_Istn>6rGrC zo0brJAZd6ZLiNJ=$stqQv3R3yv$fq`dp0wRae&zHtOOY1&e_2an(cfFX&;$^3SRPT zbmtNzcY-%4nlheaC^{tN)6=P1D}y#Z_O7wEKk1>9?kM44f;m;bQkU^#F_ycB%<2gQJ?K&Z=Ai}SM|6F4U(KRpnBtwiYo|3AX-)I6 z3p!`jFye=z@Fa@LKJ7;KhA7^5>;6=9+#W4y<(azVS>~AataVz(0{2!8;NYHZ)M6h*5YXSFyqt7kFb?g@bbOx$O>+;w1?;IFeLH23ueOdm>s*c~f) z>I9&D^^@c&tbP1nd4M$-5r{-R9Wv&GW7jR$#(37BkoxJX?28XmFg2IHj!O{_TgmI= z3G1x^yYQ!eomE4pmmW-7A|b!0Z!A{LU>$4Q2$Y@L#rnCCo8xgYmPZxcOXq`365WwK zWL|xKYL9QFKOK;B?j$d5Idw|N8-^93&Yu=QJobWC&+r)HW6%&&YRrh&aNDz2ZwIi- z7PW)vjaXjc4MyV1tC&jCWq9cJjE-we(>0U~Ty`W*K8xef> zt@5@gm%4+HT$@a}zatbKe2e(aN*WG$9(NnSf>Dn{yS4jiB`wlr_|nR~M(aq~-R1Qt z7}V^!#g>7#M!nw)x~Q=zD7#ZxpVkq)8IKHb2i@<;1@b>^Sv|a^`*N{AH_1@2 z(3~W$XMoP|F~Oq}pwr!Z@{+d_y1au&I@s@Dc7<&}Z>J@x)pX9uJ7go~*;|%!*cMvr zaX)B(o6(kb;c-6b+fUNC!8u=PV#jM8<-<@)rPn=R4DGKb^7YVM)u(yRK$YJSDz}dw zsG&c+Yx=Y1eb>>`B{Qx2f#r1ymb;^;uM>9=#1>^uuO^G%6x|$&S~qFKopB8#%~5mn zCWE2bOwL)m1Evy}JUTMVIw z+a=!#e6as`U45p8-aD=P#Y4sNs(hcQ)^ZFTE20Q)dPO*;!)(H+Se6U4BZThsidgeC zpB}VLel3^gtG;;w2G$glZK~MLInf$iM?DQ(16_mJC!nwqmnGR_Sf_j&Fs7S=OSuHv zaSXOvlvM|o+-cV@FG8<9(*)t`n&3{QVUEMu-t{^JA4Acnn9aUb#_rBpKv{m1<0<+8 zcEt;YimyaDXA&--KTeFy?0lQyTEFpS5@`Ts-W}1jDU#Z2Oa$V}S*<<;nEx}BCyb*Z zhDYPAWXY;AN}ABEHYp#Yfz2~#z4cK$&Mww&Kn6`1q(4GNzoRgB{c`AAEKF`iYBMgs z&a%Fb!T0r#44=6*G*DB=%^L7wjbDDb!H)J|rA-hh{Sa5cPopk~=!&*&BHh%j6}l5h zR~`;l$TT73b`h7=1p-X_-`1VwJa)f|B)g~KF{#y>qwSO<_eGHMZSTl|UF%0fi4rwk zP2Swusc@TzFEsnt@^Ak?qP{Y$&1l&gC{`$5+#QM*ic5-9q)3aqySo>6cXueo-Cc_X zcemidHNcmi^WA&@9NN9Lunk>MJ<;Op3C@1MKNNdQ?Kk|$)`7tihTtZG#={Qa zjJXZ~37J`@yWcZ2X}ib2)m>g&o(YoeWc@7tc2RJ6T`r-)%6UJ{pSv(=p-Uj>6(Zp< z2^yTIqR_IQYp?R4tZd|cYtwt1*GJ=ezf9Yuq@#biW1<7a;_F)&b|fS>SSAIQgUzR> zHnBD|6%Qm{EFQxOYW58+E7Mf{s)$45`+;1uPjt;{o%-Wd9wEE}EET{{erg?%Qc4-s3~v}AW*8({LW9(b<>4qpBE6BVi@G7RpL_`vN`C$E6f(M8dZs*wLtEo zQ;c5zxC(_?m}otN6*KX1dPf5Xa8+*zroSy&22wLANLozv(z>Za^$d!n%b3~sw3Sql z|IFiPFp7@G6^bs%97h-J45{y@&BDQ0%l$*AC~IsBJV!Bt*PY^pkNO9nh)HL94Ugg+ zFHMp;z68QaEhv=CdME-}QaO<_ii`f1)r&7B(6qri%Cf7!tM6aHThw+!^SKBlA75-y zsEs|fs_x`wU?aPV3!O^shU{bl(N&zyuUT>?B5XKU7A$xJn3|HojfC#fX*|Qn>g|}gq7RFx+#~#NrA&01s!<|foqXV%$qQ?hoAKiAPknj@k|m_&m(boij#N1lFxcu&f;n{4c6Am#FK_>pKMU;fZ8QY)`zKRm z4KX9ZRYRq)bs^&zTQ)A5j{uPc=+T7N+lvR2Ah;h65djQE%!S z-rc9Sk(MytntoF=zpeCGc|_p!t`;_`kUL`hY6~87Jt4t6XRH5|^xz@)gl5U8&Ps6q z;^9lYq^#7=ZvDayh4&(`@E1fFu^{4#x(@cn+QtHnF_;A+SY_xM3tf*H!w_vZ_*5sNY=O;(K0B+R)!SlbAE7@v(L2b2tAR5+Z z^~Y_D)6#yal%ua8b5M)5Rj?~84s<()?HG;akCauM-urXGV}u#2s+0D)ZBFq6gJLtp z@wU}8{JW~$I?hg&`)i=zPetsB(G8?K?%DbFDlLIM(E9uF6b@n~*qJ|G4HTM>t;CDE zX1Ml^Cq$+TgHDt!cu$o&!viSBDZ*>YGTN?3H}2PS8vVEE5x`owHerg)SwTPM>eMLw zC68_Q`>O2W-`T90jBA=X0IG(huJZNR(6rl&(}lh#W?*=?ntJbO-5=cWHKfPoYo~7a znCo=S3-BbfkJG}d*O|);ShNW-BlO!#$?dAc-LhHL(?7(A1kIz8vek~k%t28}pQbYu zhi&a=64ibMhVmFr*J){yIp0iiBRm@(#iVBTN1afWhP}QyRjMK$vxL^%YXu&t#+1I% zKmH!7Ke%&t0k6Lu_mrZCCy8E|@iW8ePz`H&1QQcE68~P5-6Ste8I*A!lGYI7FSlST z&6n*MiyL`_G_DG3-is2-2^37sxr{Q~^BqnhI4wC&2YS=_>@(@Tcf1V1@A&n4N&fbk zfqh9daPyjpJj8cao@bgiRU3N}-12bfKGStr5GmRb zDtwc_EtE^$r%GEvg0(cEI);GfbbjBF)^!DbN3{g^hVa^*P-uluR@;B zne*cFg{hZxp}H$sxZRIj$8X>3umF{{s8VZ*RP|$#O(@3HRkLk=b>|WOQGB(x&{@aD zCf#uhUJBIDPQ+p)e9LSl75zSRBcCdgdB4PcfkJ8 zhQ1_X7Ms$IjJ&cE^3Jsl+ZFsI(zhcMe+7T)$|46l9E64AbBFiI{6t6A~G>P zjAOWZ41zWIu7cKNDar^~rrAASF6^iHRDk+n<76 zaWE%ef8E@WFZCXFn=VQGo}W$#dKp;k4y;=5N)&zpf%8fQw;dXS*9{(j7p!rq2Go?7 zSHBLcO;y>oXPv+Ly~U7S*Mus$>61TRZpQCZi@-XL?gR6uW7eISr$Ip%d^opoXzey- zz(aEuM6!v#^NQ0IE}gQ^7*>r0#j`fe^AOaG;Q}AE%vD>h$MXk|85^PDR78i zYcKE$B_H%@1CP{Mwnu=Ez2MSQ0R2uFbLa`k*SbEWRkV3+mQH8~ypc07FO-n&3?dT=1+3!xu(u{GL2YtLx6T0~Wk zT1gwPOKVF&n7*ys@@3xY0(^VyJx?k^+dqY?X(OqA9jclPNg{6#TrID6TwY>XAoEs$ zgXw7-C`Jfq3BeTN`^bc%r)?-O8k&8-W>Lxo-z6APTJ(ec{iV)E2jMN_hV_~p;eE&V zmX2X%*HC4JP^DB#uim@@>r3k0|Ju>IK3{SKr!D;W40H2oE8 zz9=nF=xW3U^+t@zB(_i*f5c1sF)FEqjn2nY@@GS{g7+j7=a)szEfTrh>&AT-kGhq% z>#~Wn3;)C8j4WGmtRG}I-%jYvLZPtx?YSGQVKt6=Z}T^B69D!A7RGwhwAp(;&E|fG z)`j$e9W|mR=JC&2;Fm?`mrUPu^mT_HHC;=BtoKb~Napw1%~L*a_PA%BR_C z2EgwCP?{nBsPRP`^5E@m{$kb$X`LFhuk{8CFOBEZPCnUOz zyZOzaK?Z!2`fFL#e4zLp1`QOMVxj5HDPtDRdZ`I7aj!OgRs+tSjR(Rh*|s#|iFm@*c^SkXhT2Z9hxDs0rNAp6;t)LU>0-EDTK3qS8}%6c0j zz46)+rTVO@!;123eszNuT_w{^XALK{__NwkV{S*8Z(*;)YH%8p0mi@IkjJNsPY}i zKf%bGVX9OtgP4BJRi;Ajl$E*_yAlH)xRSHz&U!4i?LN1zPfpJZE}NXHuNAI<_mK(n zgxpLTzdN^wjAn;U{JWnN-^R&xr_A=HP<>+@ZKp6g_WXqNnME}>ajd3eV-YGwe&gy@ zK-|adI-u3iWaJ%W7-g_f=-#+df6({L(w-~%qOxhJ)#_eUQxwYQWUz3;1wu)(h2w9G z-xN~*LzjTb}w}JH^pd8FnAR*8T(<693Jxr#v)R_r+XDSH=NkDrt+8#IeX(a zanU=YM?$yXQU2rBL-Iq%u+|r>`+2LGjI@V3twK(-Q0HZY6mEmFqW^7tDLLnpYU79+0)R`*!e6gjxsH4Wn>o;JU(~NGqx;C1g}4l9dTs zY%V$VnE79jw~y~Y)YE$&FS&ey7ltEKB8THgKzG)&u2T=^EgbTKVh5#^p#pXyCb=e` zvukJfF}$|x>J9l&a97}W-(yaT1{0=<@fKkP-!o{a>(a4 zf5CPwR?p{li|S%}uP|AL$$@D|0IW7Dn1WW`+1_2%-tvRr3>U*yHySju&#x*|vMYb0 zXr~LGTinTe9)5^k-V~*EhH!5rQ6AfU7`zEcOy2VJJg@lOeal@wU{t(e>EnjsQ`(_l z0Rs>7%SA+Z=Evl<^IxqXlpPuh6MQwt77usQ){fUa7s6hh6q2-@J{Qk=6B#pcpWu)V zAjl&u^Q`UR)-&9iL4}w{&B}-Xs&@4`RLlXU=c$-MVEjAMG26kNZ(H`50l&?5{>}*} zpZ1D_QUU%+tRt)RUq%Lr8Opcoh1k>f2D4)$Aj@T`rSZXZPY! zdXpjR?LJq0Gzj@<-3D0j`7uWH=8%)c4eAB`vM0OBxjq1>MqPMNh}9_XCh)w$vgAVY z?9q|i3;5Yp;aJIer8B#4ELLs+ujFlSM&$Vd8~3a$ezUhn-r36+NO!YGARTGh)#lmC zdoXRcANjQUS!#|(Bml~ee>=rYhh^TDOUs0MS;9cWpAz)t3pW2UE3?1d*{fa zW(&Dv87I8f?~dE%4Oi`TbO)j1wo59Ipvg{+cIr0=_u8tE6JZ51HE!2aU_Wz2bm2sy zMEN<`WAoXZtVKI<6!_A0O9E0l7^kKt&Q3YWt2g^8T}xacVT7k9Q|T*cmz%x-y?vG7 zGL3Z(oyYC@H(zx|v2Ky;mch0iGe2R$#C-0u?jM>9oQYdC*RQP5^jNX?*v*t1m|$2$ zcj4&+UF_QFQ#TJ|k(ObqHj3Iw&v)EljCV9lo=t8H_HWgxd(C?fitsd1Nm#dF1mjQn z|D#j>WpT_UVj99ZXWd~BSfH4OfS*|E{4ZBb;U?;puCA3y*g*O9@7Z%Y z23GFeI||P=V!vGUbN*y>cNC-qa)PnRtNg%*o8%Mo>(I9-bib!hPYZgG_v@FhZqx6e zA7CHuw#b- zVJ028GW!kMt;Qm-L?&x=c`dGrzV4^$tdx%lzWmS@zvA>bihVN%w+pm*YXxtH{2PPP zz5atQWa6CwV}cBtw&Kl8pQF+zkUB+Ec?=I;62(1qMEg!SMJG<>nHU63fH;lkV%qjr zwBMq21KEjXeh4Rlv7jV`f1PQhxJe^a3OpK{`=#(BmOO$uL3~p1`t*#nhNnC9^@aeK zuu~WZQ_Q(^=i7rw!4ajS5!e&ukd0qRzhECA7^z6JO#mw=bBDlUi@|9hrK;h;yAcMw zMk^MdYV={&+J~sPZ&{DP9EI2yjJM$P`$Bg*Bqq@mAyP6Xk;AH0^V!XgSZ<$-`@@UP zSA_N3&DX51M z9(r_c;`U$mh9YA3U!IS8^81}Pu?oC~M`Qa-b0iczfGQ1Vl(Bj9dr+>S#5F(LOt(qT zP5{1@yU1Z9lqK8gbxKs)DE2VO=4}8bVq>`6*(eGo)0N(pphRO6?gn*UYamqMvE1u- zP>e(xCLZ_RyBo;%g(VN+qL~a%84|JOeb*!?zfMaonIGh3d)1ooHZ}NtzNQc|N^PIJ z=gTDhX35B;yQbJ6-ASjxQbYTFogAN(FH@r5hRZ@Jr<+>$TDH3lGqQz+_G@KS#d?rK zCTXN^$3jEb7~p0bLqU5Ebai}Hjr2g+^$={ce_RCqSw%nAQH7xwxxkmpWf1C1T=FtB zas3|%RkA}VzT%xY2BwEsiFznO`+?6fwypvAlCUx z#H>I&-1LvDNP4A+G#K%6zXQ`qNYoR?#qg?#vuVn6`cuO-&}R;CY=p6%$FOP>#kn_iq}`Rf%ehmBqq4iE&;>hHTT1sx5}9 z?;YleD*PcGSo|Ab{*hD5<>Cc(QUI`rGpPn0i`O8}jfN&OUz5yrW!QVYjI_kKcsZmO zlcnlux)Ljtk69spR8)i9j2-@gj;152QSDN-Ap`n@6rmwbOHWzJ8XiL?o6F9%gD%Fh zm{mY#ph@Fao1WLYnHN%`lgGw{*<2Jp2T%dEUK?FF3SwkbJc!1#HYFR0pP#$A6bzAP4I=Ny<<%YdAiiZVW#&zX_oKC4`yQmHa3#$neC6Xmom7=;8)~rIq_)% zmHkSu+#t-|BDdEB&}k$j#Fv=P$FBQ)(JvVadd&aUR^6Y7wOB0F!nVS^Jc}#v==`p) zV@%s0bBY$Qh$3mAlgIF>VbvNtI8t}^Fx|RkL!c7A%whrrmD%_&GAf>_U&)~fSP{xi z!nsmAo zDYhH?kPu{Dcstp7zag-6PuRLqw{VgC;n0e|YlG6*xP&OKdFOI7Uo6xdj||fJmeG{! z!|JoW*_n0TeRfe1-xkW+G~x;@96Pv|@vTwsIY_puVUgZTA{*p6V$K=9-dnN2=2U#tUao@ig= z4trNCBmdazt_0K7?Qxkv4fJgtCb~wo-@{P?jjf#_=-eO)4qLVjA#EHtWCdYRApW6k zwgYU&Y63pL7OKN+&I%p*w*nuo0uASFabu?p^ zA`DO8WZnm_T5R{goN&|vY$|eTC?{BRJMd)Qa0U8L zXiE$)CUHMpmNi)X2UYw1bq_rxJ1sE&M^n_HS<6sh#g(fsP1P{l+vZ6$`%liq5>W zb`#h6SZ>g?#b2&?&PQgMK#|y1Os#Ky2=kl-o}8lI=(pT^>WT{53v}` zpujP50w$5AWZc|+hr=yces6uh2Z1lI0=%yse%@gJ{;|ufScj|&o*2KaBF@7OJ#S8* zRWISDl2MFpXxiA%yB%V-U$ampY@g|yt_VF`xaga;8rmmOCL)oA@*P=KOoQDb6|C5* z=-HMUwJ+oX@a01B4ntaY_5rv%6Ymz^2H7B~4S4qC9?-_g;+*6Cnk(4*87yZbFlj{l z694>so#S=twnxrp?DmXV@nD{fdNsT2JBhkSOn6St^kOUcua`F1UyO?iyOpgxL{{|# zK(F`IeWxS1LF=oG)8BE6Y z@bMjH&_0BUhIrdGH2fUZUmzVNlCJ$2f0mN6(8TAEoxJ%DhFkDoyM@_O@e?`skA#lo z31(DTY1GF*Iv0GEA03PE{jLjY24tZ-=0DtVOY0yM%19|nt@y5yid_0K?})+PvR+Po z7n}-$>14If4}_;e-dXqEUZZ6VSiI21Eg(l=nTaUV^1;g(Xqy2cqNogj@p5T6Srj;B z#hvSnB6Oa*DV^%`;N*Oa0jYK_-IQ}<8?F~PSCB#TT~AD+77?KW&vrh~fP7XJ@`VwoiaCfJ%5$Ye zaf2ejWX5ZF+tbmJ zuPlQ4MuV9%X7E4MQRpWETc}ivc+`+A1#%)_TcGmrr8`0YZ0n1L5;bJX6>%QbKlFFs zLmYqTVmB-hEAgRsZ-&?dN5JngA0K;L1`;eA6-L zN`tbCNq~ZXzfJ}bSCDxxjH9Ow7EW* zaQ?S9pYh!)GQL#!wyeSD*;VsB61XMV_NDxO+Q#oX^`-~(>YoDc4CQ9QvT;npc-htM zqjE8ZG~bRp9VLO?5woANfdx*lkCEmU_kW!`4BVtouMR?pZBJWK4cvI}^}HR_F$IXM zqTJ)I%=(upvVb`otUL9Gb+T+|GQTvgTCc>&xpO^WV|FL|8W(j}S9{4Io4}SZ{7Lwh zr(*~HMXr-tqO-ws*OnOa?k5~N3|(d+z?t&m(c)Pzs$YHMu2cr7apZanfnTYn0lnY0 zQH!^<$g!5o%7cbnSSt@|z+<2pR|7g#4(?mM? zUs-3rI$406$piFQ4bN?F!X%LK%i$-9?r3^Ct+1ip)L=eQrjK!hF43mfE7A>u-ZegU z#LgcMm#?E&RHQfb0Dx{&6=xj@j^;53UVyCr%S(kI(6XZ$H`q?G-P`KzUp+Vbu!pue z4suSK(4V%X?)cQau-8y0#zf3;UMdIjYk7<9~@$RTZLW|o(9`ma_H+)=zVKbca&pk>i z#ukBJe82r+43u7C-$7*qchV#VYPV}XMXN$4&!5ja7gwynPLre?ir@{cO@&Wg0$Gn) zUSQ!9trM*YFUFWSc)ZT}85zvf#c7qlmVvJ&)c5YYT$ELoHQ$k!(HVYW*2xDM6c7Al zZyJrmknm=o&#~YK&Bgver1oLeVZjL}O<^vykx^};HU3Q7b*eM@n;~;sTZgcKERXZ` z?k~={;lZ27Bd`$p%FfJ>4gNRe*MmdSJbn4EU(?-?)VGYL(2xAnK@(6@z7?*oiAx3^tC=eNz=*Wm|| zryMZgT=zB*u*cfEQ{AdINmhLgLk2=41H-s-hbAw3(-rCNe+j@5!+*k)(yw$aTgY!`T8sx^>JVsLoS(9!0zQz*O7K}BM-MvzO97aLY zNV-p~!J5-4usYYV-o$XJ2($Z$A1*>7Rx*!|h#`rPSbL95nTdgbDcTgk{Bh6U|0Um+ z9OED|iTw7{7E_-z`6uu=D+XeKhGYfI=bcd1d~tw+6<-owx&PtvvnFAttPw36O*m~Q z_gAlVT)<(NliuSZXwB>u3~&OzTslrPsO@(@`-8(L7N@<8ah`mULBL$M?pv+y{nu;1 zS72h`d>QO%?#ps+EBSLRxl^_0d^w{0=&FYzUw~yI;2{uTzj-aR$;ltx*jHCAlI7oX zRl?Kx_hqo#{U(_p2vZc9G6=IyO%awV2CeZSUiXy9frh}VT$vKA0;%~Vd5Vi&ml$+J zxI<(GE-D{yy(j+mG1;tFPAiU=i9sBX?d*w1E2)hwt zCo&UN!0E!BYTY@F<43F#=G7YnCDckqo93Uv`md3la775N>YI-WNb~_;Pu*{8)vS{a zl|JLpz6#zispBrG={WwioN(6jeKfK0?qW{EqZ(t&)Q=vN*7448|SINiPjWoeyl zuwbcX#A4R@vcrjuaL02J55dPap%i`K|D#d*jL%!U_+kD_XC*=WaU8QD{N=OU`eehU zM%jhEN+5@|I1e%AZJkbQz(A@J#^NGX;qGp<7sb`geL3&sDpnCL<{yEkPk^ohanyp_-&$<(Ms_9=?n zBFv3mR_4hmIH!N)luhekc~n)d7QGq|b!8y-E`s8VDk`ym3Y&Vrd>a4 z??{~g`?W!BauPuE)pPM~X(T*Jr>P^sV*lmTeZM|Xe6nkfhxW7br*A7{k!4qfV^w%Q z-!{Hz;k~U6h|ra#Rb9ye3^<*X~?NR=?Pexd}U3`4{9%=9XL=JQg> zpDc?$#pErh=QHw1gh<(a67^oro3mc8;6_VxY_%E|LHhr`!K`C7-&DXMR-EqJ7tSAA zr<_PiWPMK1Ke~=I6v9np=HxD$9m3h^X#GQzc63GM{G7$=B=~-gN_9gyKB2@RC=M+Y z4w-UQbbhr^u*r`ei&C`2tv`p772|8s=hlwRza6dlp6G;s|6P;DrLb+_7njv2Y*Ya~34eem zn3Cmm!urKOf5rV6GOY_*Ec>2TRQ9vCM$ zHFZ0Nt@T_U(h!{>wk;dzq(@X!${by?7ew`c9ueM)h=mO7hXvr&ir7>JsGF=pUqIPP zArO77W<#3`6i4rvEgGF%@g2Tzo8}GULC2vTQ6eZOx*Wn2Oj`;yqK1BAaTCQ&RHC zICWVjN&e4q;l6h&I9eyD6wnp8!Gmvg;m`1*5=CNlQ}15 zXRUOq?ij8Qd+qS*!HXZY5zBFjI`xZiP+O_Pq)r^^=DepK;k445?YS9 zrs7VkMb|-M;?bDe^O6IaYEc^YDs!qj`^gI%?ct?C+h3qQ350{*j{szh{0Ebg)R#QR z!jjtR1lSN#cXA`*WjG8w7}FqrNRxEbknQwO-nRRg1mYT@SWwA_L{$@5{h7Quj59r&ahr>^(L+uY z9Ww7@C>KIr=7$bAM^v|NrJ!qmB##0#<|a}eWsGRJR-Yy&<8Hr|Sxi;L@Lv2Cm98Li z(4|k7iKVjG!(Lu{M`IeZ=T;OkC;(Q6{NF+FmBW<;l=c?+SJ!`>zd31BsD*}o#RlCL zKlSZD4k(wOv+Qs^at>iD?<&g=Rd{*1Tb#z1q_4y(GItbR^{b6h23d1_{EED+|L0C; z1A_y1MVIWT(Uj8Q!O%Q)`fOnM<-Ceies4UAM%g?Ui#`);4(W?%Cmb#B>LkqT!iApYXPk z(1~^oMUa=R{}ttz?xX}u*b@f(QtNZ&f5;rZ`|yu_X>$fyhe+m*%2^o{bHaU78M2>Id^sdmQ`>YnFy-zV~aynj7M8r(t^wLX|x8&c1q-LMSOjRxenRCKg z>SV0_kD$R7>EB5>jDKwtP4}lbrRX_qCI#Tt=9|-AWkgwLU4lO>Ps;q^_iiMeTuzu- zqo#?ZWJE1;(`imbWF6u!x9K_WaIzNs-zZywVVTGR7xFFWCw*AetUG*0_C571O+eRy zJXJ}Hm~#o(+)SHMF30S3bpYq8n{nHy0blx-$OtRQn*ZN9Q0DCGeH$-pZZzX5e|+Sk z4r(L$5_D(Q)iiZH*N^k&I&)ROWe_P|{IgLr#@%-E_4cKTv$1x5t1OHM@`vjG>a#S4 zbRyRQ(1NYN=876z=nYzQ46Y7SfH9Lz^tZ6Q1S2FqSWaW;hh_2Y$F=G1=&rRt7q`x8 zht3Xzb3TQ!mwPa@g@GN^l!0*dOPdVGS?le0GRmXPD=0l%$9H*7q`QYyY|;gVK)MQ15h%6Z{cE56A!Akj(eY7;kE@nA zCO_jqF1vkFADK)8qioIS(YROS52KNPpm`^Rnl*H0yi{+lyZA8dNM(EL3~~iOsE3gCNodtTk}q{zJ-HZ52*QV`tE0bGlAblGpz#t>Jv+ZLZ#S@S)Rwe6Si z40oRlaO4X7dT}>)g^+te-V43*9;jt|PISd~TZ=un4w->NPBv=hpai_h|1=In6=O|2 zt}DwdR5!|l{(i-mt-RK<3eyDg$im;%JX874X#WI=vk$FyEm^0gLSN@rJ8iYuDvV|| z4=62zxg7cviCMR-2t#R1OaNiP7crm+;pI6+!j{7g(=cX4yex|+^yXHI_Wu-Td8>@N zQ+|p{_z-mJF>m&{$f@{>x{TVCy&y1Ean)YwjRLjhW{I}2x4*t#e=V{eW~I3P7k)rK z%Lm=}@ zEi(hsP1NV9lN_hjRWm~AJ9Tn&Nv>0$P zIdT)}721%5U&?wdmp4s z7tKF3`CYs#9P9B?M{h#NbA%1}#f-Gb*HudPckxLnf?{a_=zV@ItAVo9vb6-q_sTo8 zRL#lDT7Mn*5`YYgWr>SLql;7zwqpl7MVkN~2KC5wB)!h<*COVsdYzyPUC6pRMN=^l*I)lX3{DwRFO=@G`D(; z^wASzZR)L99UZ#Hku5nJWn8N4bZYZ?eFA2kLbRptXzQniBQ@}Yw0}~Vd)#;4Tl5h0 z&ZlNF+i&{=eJEcg;%@xuh)G0%OcXH_aBT^fownR!MZYXzf1XMY0pN~6bdz2Ul26KY zRGIwu&D}4R^)N3wL_vOg<=xw=uzf-BQ+8gfTDw=wH41&)`uy-S)h!U?iXHRbTl&ST zbb|6dE)hVafl?D;H<(-{b{B|JBlR%(n2+(@N?kHur10WH zsEO#WK9^ZlWEOrmOryQE{3pcW7reV~|5Ab~)yC%iKB4VyqnUXW*It~MtNY=fw7}Lk z;Gb`-G~uEV%m5ATM+db2a(}1_=3IDUAn!2z*_W#hYf4Jv#3K?)<3d6!O;*6dQRfqq zULAGA&xSvU@8`vGg}AOi@W;iwXi(DbX`?feN>E?(>ezjf^k)1KJ)8GFgBcCuiOTnP zY^mEIPf{EjEZGC{XgL0B9mN#WbxtOZb5@2M+sVhfwu#VS<1uQO$X}OSY6|y$aWeiV z)x>t@evuYGV|>=W+Tqw@GSaL$ zbGI5AvMJR!ywCi(^7U<00S#Sw%3DN4&*j2q7DWka3YUQ-{D#{BrprHk5C>$*C@6SL zixcab$w}dx8My`F76K`l0xGXDiPJ*seSifvk|hmcXpt2~ zrwuhJ8uNPOC%#ulrAA;F>;5CUp5=3-w8hPL{?2l4X|NK;aYmWb>_ok%jEZP5UU^Nh z_1d8=U6@Ox0z8pbwCt|(%mQE~IAVb%5(7U6$bk-Lnxr@a{1NCZ@h7Tydm(+!@0eEa zyBa}n-3kdD&rswau+Fg8!d_3HhUTEkjkr9(9cTyvt=WVRGccw=v+QL}=yC2x;%vl{ zQ-9C}0}1d>`ap8lC$}|Rb5EyVfzD2T4 zxZ>H-hN2r)8rCNN#&7U^%V=ek{4E{}H#m^H)Xx>*sqs4uvZetP}E$}mX?meXz zEYrV2Hi|{XQ?rhI2oY}Ij^R3(ov#uooHKnqn(Qx2e-d9}lCZO#s8_0*mjSC_8Kzsu zC-c|J75?^!>j($CUVV(J8{eK2l*#|M|) z+_{_GrfsaNXZZ(LA1TPs$oot8B4Qiu^W&WxUUmgTGzDKOf4kyT=H)Va`%3a$2RP8v~zh%{nO1+3Fqzl`~wU%XH*ZZ$4y@8VJR zC3wf8)Kn$x0$e+R?@m%p8bzo7fWCK&Wq`RJbG!$T;~jG(f~>mf5uQDU%$hn`6Sgid zTdW0#z8H10r6~-2{O7;3kzm4>HwELxuq=8;+>iUdU0rW(+y!mMlkSJ><_;u3I=^`_XzywuRAFe9D08JS3# zBXZTnd~rX#`byu-a;-b~f$`hCvU>e7Z!Wt1Xk5{l{EVy^r>S1tt;CZoj4?mpPGHks z;WctI@(oiiDeqZbpNQ;f;R=*l?{SIIiBiLi$@xTlLattM8p155yV>Fd@o(YbiUen}=03Z*9QR zF(#$TVHTB00gcw;j#1msm;I1s0j*dIG)hYg$W%;u&6h1QXKkPe+zDKy)$;b=wpOUG z_*Sjj#JPNJ&_VoZ1M77T(?!4kOt=~OV>3~CkONWJ4rB&ikMB17%$CtK2Exj9!{Ryv zhrXcoyjIlPe?z9+qoUJNw|M7R8)u$HCnHzD*|Y|g$i9391kHfny-(FC#R(dU5nx#* zezx=A{6NZ%x1^4CTKxxMVO0TnS zYi_+_a;c0Fbn)1_CV)9^?|PZuiWw}^?@EuS*@f z+liK0|Na&>@WiSR06Eso>B>&Cn$gjP+oYeS!be?dSB2Mx03At1r}{klYuk?JO4mxL zax+Z^F!Za%w2o+@qLH#}t*e`NfTNQIR-5HNlp3LEL8~&^yCr>=>H8J3fSk`2FpU-F zl-$mDX?Yy*qHsZ>T6Ry*PM~2kVpX*?J?jE{TWCG(Gym8KI*&-CU*{NcnNwBmMfs3h z?y;Hp`%jgE{sou9PM4^ z55h-vQ{o$J@Cy##S8jv=w;#RVI#}Vx2;6lzr{#yZ;Zo|xhspd5*>f9Y>No$*9^GptXQ5lVJ*cc2n=PQ(Z2l!kmBMzjz7R z^>g%BznnY0jslZd;RFL+1U7Xi*E?)+#I?KcU1b z1rXISU_J&t8iN>t^E?x6B$K1ok zX0(ck@);O@vYFS*DJVtp2zhime>$nsN}FfJ6JFHg0T2_MhzIU45;Ic>-(hQu^;`^? z3>!J=y?@H~DMKeHM1fy@Uc%Xo5D{p%Q_X5sM9Ufk=)tWjdj$B1DJp-mv-f5zVyIU; z$W~h|9Ypk;mZh8|E;lHt79$=RbZNFm7$j)1Rg{2Nw1FSXK^>&y4ic`gkqqt=l;yX- zM*`H;z&^J*UCZ+n18+{-M}4b+9rkpp@g#H)aw5NKHxt#geK}NrG1gx{ih7Tx}<){D+swC%=xpVI-g8|{o`U`y01-TZ#cU}DebllN5aa_qzSU`izI-(E`-E@dhfZsvI-jCURI<31LXNRFf8%^Y3eTUg>fckMGsdp_`!6{& z)dZr>h8m5dmk%0$Pm@4f{N*oE0gr_y=IOpCA^{aNuR_A|xT1pU=2Juj(z1l2dBo8K z=I>Dx)tTV2)Qq&f%Qsm5ReW14#g5lWNI@g`I)F1RgWL-lCIe)0oSOAEubLSKAX6fl zm;?@WD0BVVV*Dgw{0y872vHDzxhY~vtz;I#4TGmEe&h?NT+Aq$4GsT)OkD$GozK&a z8#Qcfr?H(I8%<-|Xl&cIZM$*O*tXF)y^Y*FNS%>J!r&P3~kvC#*qdnybv4DzeCka z#H5lsC(M*#p8{A-)1S=B{ENnr6h87yRCTX^UL?rp+>5+o`|;<9R0%GzJqfJr?6Ry*8l_K` z=l^1L@7U%!q&+#ub1 zSI2eigLtP7JmT3vV1D?;(Ak`z%(1IJcFP%iH2sp<*EwDVISzQ;aFmf_T>L`C_%{B8 zI~BdM!OxD4k%}6zpb8vAFd}KiI={q}>2X(Qz9p`{)IXzGG=I?6vuE+fB#sjUHy-WA z`2xu9M!skZ{7$p?!Q-gu2x%B5Ro|AUAOt`cW|e(XKI(m%6OI ziNZfcPa3lEhSx!BpGOTLo=evrAC@i#zfLuvcBfXO9G-T;F#l8$QB*aLj4lpGf(Q3L zb;W=pKpZd&jEH55hyH5DdQ99azuW9Dk)>C`s?0R|h8a(uW+DkKiK=fLDO~gG_aFkB zTC?T6^L8@(3`8V8vyog5svYBMui1u>pUF^3FVU0Wc{%awK}&2X6mXiZUVc=%Rg%d; zcVEZu*UMwu`e%Px^?{Ycqw5s+nXt6F5%|#vsB4xdBk{-OZa`~!D+bdYY0<>lY&{nF zK7k-t2XkAn>m`pN#(?o}Eo$ltbg9XhX{ z1Db}dLJ1dsL_}kvV2RTq;L*DYTA(Uoy??7gW4@`azfXaWJ!XgxM!i5VTw=Vw%dgrN z=c$@ZW>{a-UGzKwF=jr#L%tBXpwFi2rUfV)G+~gK23W4KMKdfW`w*36H8-ZCvoy{l zhRd^3W<}s$=CAS4Id zbxaSx?=?i-`)kc!kI?;QHhA3f!l8Jvw=cU+Z&T+{L{Wq^_QxZI$J%@*^pnbKhR zS&id(z$pZGX|4uJSkIeLZkX@zlYJOF`qXovV@C4&eSOp`TUigvNWCnE$^16PgKjb~ z-^3Gg*K6~!J2%qspc7bUmirt7Xc->Q=@9$4chT0ks8nn=`T`skgFtu(D;IC}0&Vu7 z7hgT$;oX+Y)8fBf%WNyOy z45fkKud5igZQHH0L190FS%&s)!iOvoRnDe6Lo+RYE1 ze`gVIucppjS?hs!$XkE`(roW=x9~)ua?5u%JKgDF=cMb@=$hBgT~S^ix3A_eAMl-i zzYRO~D#pC6T-C?M9#9S~_4^{CHrW9PaV)%|tVE}hp?09TF%`w;0`{MFQd6xIx@pjU z54OK!#I!o0nGs${y$gW-4S|PZQkteN7V;UNXI>u{lz~_bMezeXgra?HpBp2hW#?Gv zhidgeBY|f84&*v*O;cRK&kgGqw;dgLwew?V#**Wd?(}it-`V}lAr&89e94$oG4~)h($@HwB1^d zFxg;@CN%66ZP{_o!zWS-8V#NQHDh)5i?87Lz4rY=<#J*HVvdE$j-s&OZu*9Lbwq9m z7kLup>gmk%j3><=;NiJ;n$V3brp|m8PepRmPJd}&H^q7zfKLi5Px|mV;74`i5tW%g zzeN@S|1UG}wtCZ6*aecA5MlxdzcivgE+}9fpWBScPMkg~L?&992pE<(I1|y67vJ-S z#biawVKj=t`@|&%TO)AwN-Z= zCxUM@D}SB^t|Dppwysig!@*s$YU>?+r$1~9sKdmB%U<^$bu-mv3p3(pNo2Wd4_`iY zolIVOa6K!w=h%RGSKx5h@Orh7o7<*dznpKZj1kkBZB_~dIlTZQmia`Bs3Wv}6z^q% zdS%RxPW`|5Ixq2WSGB!z)y;ts3?Y3DA1e)?gJMMhu0mA&b{=yZjR3_0dUCqt3mHd{~ z3rmsY4GkLp07{2L&c*B>A>x|rz$I}ny6}I&3tHHg6LIS|b`y8@mwe9abZbNmQSCo{ zKr3GmS&+p=PDP?CCvE`YT7F`SX_0ITmbzuAf7sNN1df6sCKx|6FR>rW-wLiEQY;Rd z^v5ev8zao_(07UtH$)THM%>8WZ8CZ;@jNnHH z;ryt1u1W`K>FsXS0ZEaV&pPI4TKJaW@N_?Rdi>_Hrzm482U+%Q2Fusx*ZqE{N#NZ^ zw0EvtcE^p*@6WF}_`JY}oS;E0P<;VaeOm6PI1#iiR6thwR^9zuiKWOjbE1h#E;`SA zrw#_MBr~jrQ8`rK{t6<08az^mKaF*o&7G03jQjK~Ok`YjzwgoccoGZTD%x6tB5i=I zDSev5%*jNEf;bh!NAVd%9a{M-KQpGdu(y+WK}t{Wl2as9MF$v3pR5Q$X^cqKfP)h~ z*Fj`1Vbz~EC-e1JV0~3$a>0cvibzRPB>AN;%Y_jvq2+o%t<%g)*$KW>Fivab zxMr{Z+w1C7l$FHCx^J?P;@vBU^%d|P@?lsbk}1vw86t=1&nfkX$wZBr|dpXRVH8zne;VEx7WiMZKJIAu_ zZ(*-(0$9Z|j>%>77RA)j16wBvnCLvKJ zz&*xfwbG{+e%9xgj2=!_huC&43uA?tLZ49&)z8jxW}YqOUixeIoQzhTw*}XC7Kg)v z*YgC?V9#0_-}Z#-rhE?R!Lkxx{~to@TV#5Fzmj`#JDNz) zUEyws{%psf=6gU`#v%W8Rex|$4uROHXffI5y^%NVmj{5BTD%!iLKig8*j`c55(~r(#BklfG#-m|5 z4HrT!?AGnXaiB-S-|O?F4p9QAIFzaH%Cb7vx8mNdp-_c?(u2KqXigy4vMvvc-$MsP z61f!vMHcV-@1WwBDewE_ZK>-~BZ&U3W%@GW=*}3SdTsWpIyvep?(_E|i3|tex@U9x zX0ENvCMy^5gv4JD(&ReUfhpGUd}${-wK+KrTl&$$a3ofN4=087zmoq$vjqgKm>Q=;psdYzQ-_9?m5yo;pXE$wp1kNL5juJnu>7ixKq` zmKBeQRtS!XSoQy;vhKwR1u--7N)buc{Zz0zm%)R@e0I9rbIiitF1*Trmz_7xEv$Mp z&M!AODbn+HrI(yMlaB>$(DAFdezIx*;O)qwb;;tCNX zy!QNkOttFUBrulkW31iq7nOi!Ki0aMv+=};fLwryX2hu!}81r-atlGP-uWyZY6aKw(+C@dr zz5>T$mb6?=xn`Gz5nl{r4t~{GqOU3oM-xj!6fb`lvo6^(yEJN@zAkY&v*{Gs_&h;d z6HOO2S*UahsK*Y9lY6JvYWXi@jLq*@UkvbhR-R@n7{?aqx!I_1Sz@~Uad|Rdhnt?> z^w~Mm;Gi=962}%EYhocL3s+GTG{Xx5d+eUqw@?3J%waLFX29S70_ha%A+5{^fIoR{ z9XYP6G_XhKBOVOsTjvV`=4S+RZ5kEeAVT4Db*N+)gwC5~==!DhW8)|9A;;~kE-yMu zAB09Q1rg{#g#Y-YAnmKRy2my|s0k+$bpz1~=_jtb5eLzyT2tj98l{38GJn{H{URw1 zmDAG+o+7%XV1Fzs81^kG4Z6Rt4bWCC!PWmz{3>h+B{drcOzs?Z@YUOV8-HPui9x^N z#$mZba4wPV|E|4)En;<6jX-2T?el;uyz0!{(b6`fLbYC(HLb(+DCCpBM@k*bgsLWPNrm7kjQblKruNMUV*`A;{ zXHqRu$wjg4NXNkCqLJNKUxhw$e){+@U1-!=Z&B3tsL5$LJteDV4A11lgNaWG=0T`> zRLW~J!g#dhhgMG|Xu=#=@0kc)aujOycS5GAF|E-2hH2g<$%D(fSQ3j>*{QC3TIb*)# z-J05h#4{bO<)>w!!g*~*cM%8SUX)d^hIexo2WG)_2^PUSV(s5gQc7=fs?F7X9O|qD4INnYE0IK4&g4#GkzICdO?P`Pve+!F=EUbOs z7zHSBgF%6d7qd*cyPu9=w7`%e<`)J`uY&iEp){(mD4ch1YAJMr#e=2(S&qT0IL|T( zldjAapdmp2KfbFo>9Kc*y%Q5D6d`H4;y(0)FG1YM^{0Dyb=!4ODXLn|S_>~yDvOrL zs?=F^eRgkAQP}c~f=p-Be+cqimPS9%N{;S;PVAEASS83-%!Lv*<=wFf3jhQPDJEvZ z?5(PKHt|-gsPV)MltypEc#5;-A&aU%{}F$eV&XhQV9aRgi-yZ?pqcl=r1nG`jHIeQ z3H?a^8MM|8Kbq9vOJDgO{!~UcC!gDVkHzFbfWrDhZ0a4SCOAk&#uj{@7+y zCd3Lluk6P>Mo-S)XNdjhVQl5KVv)Ku;?g~_W4hzUfj6qeOcePnViQYYT>=iyVX(N^NnyRHr{d>|*rXIyONFfTnk8p* z1A(__pkx2*0y{XqEYEL~*$XOBvGk3dBWh}tN>2_9-T~Lr}>c7%YB96v8pMKdWW47|8Q3^k^qEH%ZMx$bWtwdNo!2oq~mG{5~r8(szq{>6oHVF(|bG}h87gw zQ%zNit~{`(?F42Ev7N77^;-_ys6itCWu&o=(`#^ zsqZ$!KTn}9o7d7w54OmdaU88XwC5GN7Ui-m)b=8wQ)@)13`r?T*1_JPrvMh}nUJFz z3+kNs^YDlYWQoVwIPbn2HD=LZ>~0B!mTqJ0?9G6Gdg~{FBm3QC#h6s_jzq5@+E_;8oOz z2*a?~pPpT39Nb1TXrUsBKc6NPh3k6AqGlXY)EAwJU-#eE9GHi_^7y+_>@pV{Atf+^ zzH+598a?;c7%Pvqgi9NOJ)_P4i3-lD7{dr%vh4i1vn5|PKOjU?pPe}dCR6g%32>Aa zE%o<`s)^Z}vkchB%Zy#PXRxhvku^d&Cx@y+&En=3vx@Wgg2w|B71Tm+yiX7mZ6v0^ z!UMC@*bQ6#|69wMUvqWJT+GxnWqkv==AE|*M*Q2zYY(c7>HJ`k4{t#Bei%DndV`EIPM+kz|NXE;(UeB_Bz3VUCa%n5 z99oI1XXYGzG}aFoM2js_Sw+^C{N9_ure>H@bZC-w@V{dBNurGa$~<{Uog&x*Q8hJc zO>v&jj#-7sSv9Cu^y4bb#HN*)9AzxR;x+Pea&w7_2AzD~mZm9#F@1+a zXd0X-Wr1z0g2oKp2$NXC#NK9SKbKxOW{Pi7VM(nw?w3Fl8!53Cthc2zc% zyyaUr9YvEn@B5QHJftuVDse=A^%=US?3JgnEo(;Vn79ju(v8e(=TQ%~RPxb%vSuFc z=0Fr3pWGv0v#rE7@bqwSi^#qEA>#(ZUiUULPXouoZlTMtbn1WdqY=%SP+d((R{erFuVyu;DCi}viRl65>0$ub&uH240f1fa%J#!ve=-0$8c36 zjD6C%?7w7v`h)G`1;;{6)(RMX44>bUPrglo{=|Xle06cdi!b#D&aG2TzkgbZ!-!;z zqHdHa7`2wYUF&czPX8M!pyos5IMOKaJMRIO;&zO=)uzd10jL{+^;313_|s$c!ALy!8`oWDKy% z2!LL`I0rEUu&S#&Q7Ny$D4m5}73V6hLlskSMWO7)%i=3g+^HB@1r|*${#%U(`qit) zOD<=9(BYq+Yv+QJO1iSn$}!HXR{=C?C2KMY166NH5sp<3dx#U0iqR}F?)dbZ9woRG z6o zW^LBQLn_8;Xm89_<-B)@?$bxVv?)TerQJJrHTuwGP>1>#Z6DJ(PM;{&nBDEj@>vEI z=lsU>_s(^mFbs@~;LfBVDUv9g2pQXYl8jO@wlT-di4ldAnu*CsuOwYVz^b^WKI*@n zf|aN;oA@3S2$3I*X4pD&-D1N^l|~(a29<|!8K*roa94yIn9=iJrr=@~A`S&5%26x2 zCG8m)iJ#ZiLl9If;7N={-k<**24n2iC?GFaq+6J;W-MpEq^yhmYdXD+T}Cpj#4njG-rK;Ol;-p)E!evZVK0 z?jGXpt8WZ?T23M09z%}#YLGQ!tzA%D^q{(#YPYJ; z2c(~m`dbekwFo%!iK)cWl2cW7@|#sr1ge@nY}^tsp*0=Ih3nZvth)5IRmCaYl&b1q zD~rMY-Ibs!1QePAj22Cu@EPLAB_W#{p3W583laGS(M~W`HPVnGY;e(JVh)Vtym+d4 zY2;iT3Yurzql$xZ(j>Z-R7&n72T$k6;}+T z9~vdItCYdubRo)j&VxrIT8e%`-6cDaMlM&F6*q6l|NqTwthrQkrX!^{MaV$wrNEQa2|&Jq@~UXrhByOU{?S% zv&nq;%-yKhWC8kKR8!eNo4?I>R?x^Ai^P~W4-_vgGwS*(1^s*tcDs~^sKBX*o*E_l z;sx&_z6h=_%N8mhwze;xHzWouZbPfkNF`EBQ*BaiRen}XsR7?dqJQPK@y9svqsF(3 z0{EgdEj)0DAA{e}ga&G~fRe^ihT zoXvlBfbb~}?X!}hG0{F)y_z|Zr5dc#BI=F6iNB_8#~xGsQ}o^7q@fd8wXc{E{dd`o zB587)LnC?0e;Swo1!>;R&V)&(r~O|Ou^p5aLA$Y?5oj&&qNUfCHb0xC+8_7NoI^@h zC9SizKA1(S2R@nABPRdbMrlwHTMGs$9EC&yDriLJ@YZ|_Yb!xt>-3}4iuk=N4V>vL zqs|entg7MCHoq#~9LrPreA2ZB=qzr4=DcR6N{pL)e}-xamH$8qs85;;*_&i^fqi|r znY!7NEXk^eFC6C=9LT6(T_hHQ!DtJ2*AljTN->G7vaU+T%W3sAdgV(!HTgGEg5nUw zWrIGEkS1Xk7JHE$Fa=NFzmf0=up#(o>^dluw27Eo7pxdqAr)8OprnT51F09uInw7- zPg2OS&*-EICA|2P4rH+sAP39lgAtNZ5@b8F?WgPlLyq$!{GsGv zDT1sy{-$$#b49qIR`l#+?~(`61<0lb8P@_|dziA9LQuY!7Q`lvIYgBtgWG&^f?FQ!Nqd)T-mR|Lfhz znIUwJN2~(OdtyOjf)u>ChCK7OWXCdrql0PlNnUH+c&eh|Z5Yh!!ZZNIx7avZ3565X zPB))B)9kh#j9T|)SVGD|$R84B4FaZT!cta@(X(kj|4%WRF@3CJg<{a34j}C7NLX39 zp%v>CtdNk-MNXf$GNcHz4*;y{-pUDlwIzf?N3VYs)(nkeK0?F;jm51$ydRcU9Jn~P zDYNqA4_UFWKQ?@<9dHPA1aU!e(D9-~PwlJfN);8}!ksvN4~G5}#dU=cvj1Q9pR=Re zQv)#@5p^z7tb%vgEl_3^ls<(;QmiS`v~sFQF?wEWyOo$VI{ImbdvfB#C2Dwj-BVy( zwf}oQ3GxcoO-`@-5E`X_9Qj^HQLM5Zd-#=|3*^CYyo>4p6B5r{;P+L{!>KKR9F9mA z{%e#Usjqj=a82sJiA`c9com*82${vfnJOLoz(=Xo{^0S6*ULx=Lt84si4r8(<@WiC zPZ?n0wiTK;nvidKx4U6Zw4hKS`BJcnGj;wigTn9TnSq~cg19$2)mBvlXD`(P8iu!; zl`yTul1$!|g>i4c29esjk$HVU_C@Hq^P@Lw8udC(6QdOFC;OTI9S8c>;}ZZd3}!fG zOq7h;^_B`Hk-hvZG*^u9l>4CBw9Ubx&Z1{?bOAG7{l_Jn)*_>(e#dekwE-o4?O(VF zTF7Tm#oYW&ZfeZZ*@guX>g zzwgN*;ivjQAqHo~%77#g8IL#KnF&c~#HE+=7=%FT`i>7nMcp-Dbw22;PWES#hz~Zkw`y!8DwM8d&NvcKdtB!*#{5qD9?w{8vQ<+}4KJG%M|@U-d6P{39@+ zY+7hyxW_+(P9RdbwjgU@`X+-huGTd#6v4)F)?bsD^>KT}tauDn$;6PZt>V`Bp5f(e z0Lc2rsOo38^S{$U?&cDcvW+FaQ^Pf5x_{eqB*?O_I-c;HxhN$AGpj#$}kL>F7d zm&;@0*mw%Tv_uAh(f`i4j?e+Nrvm=yURt3CXQb!zWN%`Hlvz zi~cca#XIg)ze(tnS&fqJIMANBdsVbmHVv)4P)> z$Q%G-rK0vJEvX8nkmo;RBTxxAD1#%_c0!XG2@uDm@RD~sZ-kw@A9DT?3GGsV9PJnc zi*A^@SPUiga^Waju*2@MGofde(OCL0aMOK!xAwUH6BN2=e?23G8u8bN4nIHB*1mmI zaS@#*iAqj+a)ZH;PpiMt#u_$TI6V@y&x28JJMgP5`_TO3r zLh_;ZcfcZSl4|i=l^UJWDSNg)IA${55(wo=BmU@MvMcLV)`?LXkq&U*maQ7M)uGTl zvpbO?t+g!gFjo z{9yI8&ehn7DMt>AVUuf;kyk1||F?{o9Dkc+Lz8&JWO^0i;x`FY>`uqUvoQ2Bl@{9i z0EX%LqwahVwMNt3(|&kl{)`P5qC7ZZsag0rj_H%o$j~)B2()wCL-yPrM<*i7wqop|(g_jDy?A z@b7x!oJqoQb#0%Ob|uh0FU$%h;0~&GFy1Y_ej`dGWcOFxLfaJD$77%{Y`0D}8A#kQ z8GLkB%c<<0)6`;ro&nsoH1Z}g!>zi#)1onnF>o(ppZ26Dhp<>$RXANA z)@@@)7~$PorB~f3>rhf0;fn2F@(L4oI z())cT$W(n893H_LlOmqQnR_0ExW{?HVl^Q$`X5&1Rj%D*BXx4qS1CN@=KsT}JQUFA zWxh-UZsdfEr!T>PYXAc0sDjQKN|fTS7QfyMGIB%rSn^*1R{<5+;u`(t>OvV6<238= zadj)2fhY}!@2s=_%jn;`L(<%tEK{fP7po*t^Snhm22Itcna=LlE`)r_ql5q?#VYDR zAq9NwUEemi_KU}SlS)z_yZ={}kOy~p1n7lBG5sb6Vi`0|ZdITq%3I72?yT-HRP6?7l6C%cLq@kb^{!2Ix-099c}HUdoUViIZ`ZjW~!x zgTbevTgq-wW)}@n%O#oy#Z8DfJ1Z8I)-esx8m@3xvZa&IjjLZPmq&GGJ~K*pU#`Dx z@ZV0fZhpP2csuN|_q~;|0BYiC^P3?ND#XI0D zTE3YLGba&_aMfvOV{weM^RGh6o`e_?;d>8!o9TL56gaMNe?7zhw~*~c{fYB%4I>k!77qSW55n&Uxmsp&@pZ&LkrC{f^lrFowbB+7+lcT+Tqv4n~tJ=1;_`pFzBYZu4 zGvTG=e-!$^6nc=235H{dTtTw_xeI8o8jybf?DF!$*7I!5y9OlaXI=01J*;WJl6LLC zwY3XUw|m`p1gqh4Z{u~pDk3w6k0FCy6>Nx2Vq^Z0JwzaDZFuMUfn$Z6c`gFgy}&Zw z{ufsd`1>ol2PYNp7hV(ZOnNyw!gh7)CxP z+mRUw-ic2y^RvR-8!&()&VAfC+Ke>Qi^vVGl=mLH2=@H-TIcy^0^wxzy!AIoGrL}m z0Q+s*8|ck!{2|#ya2fbPb`C7n5Z!BNk+e)J>l^tk{%O)QvFJ$<{Ay zXctWbP|Ur>Mlk<+xa1jsUb&jAIQfn$1XD&-LaXs0l!ArhuUH6K&PE(#Qg6 z7*g+^vm)Xi_%%&{C3`o}tz^pDUX1 zdrR`c570EJgjSiza`KTluhmYLwK!_Vm9Toy>A|dU4i(o1xw)3Of>=L|@3@`nPPUC{ zjW_qiCj(u$;8%lGaEZk)MT}Mn{sFEk0w}2RJG<#i7<2j~!InN4Mpur_V+nndiS?*Y ziun%p5WBl_0=KRNtGwTt6MHv`8;J=Ul5#zsEI{2r9KSy>X*fp`!z7g6ulMd0q+$p7 zxNd^zlWhpl1F;~Vi{yug5RmK|LlEUySXH2em)W!PV!Iqg@F0!rUiJMiL=vtLkAaAc z=%4+xy##OKwA^oQBtb4xIYi00*^E5GdXexf)vEF4da*U%wT%r#_YoiYwKl)rL?obS z&P$Sz@e595-Wo-KAXC2gY6s!fQk&ov!jUO7E|87at~-V>bf$<`)_Q`@tV4F7OT?l8 z8+hqIpRSOv% zm;#!acJ71|9PcuXYXfLd?>i9ooq6kFouie&O7y*E*7>^~X)HelzfJJoda20EptXMJ~!kcXioWc*Nf?bV^-{79aw zfC*1im#70TS%UHYAKwI~#?@IbUUNe0A7l4;%u@rsbzJaNi$NSf!Nnu0y3(<+@Wrd`I=n4>UeP_OyeYBhnODp9#aX*q|M9Z7%!tTBnl|8j#eUhcgiTa_L^#{J$Ul?lj|YE( zh}1YqtSCosIyy2ocN=w*5!n(H5`q#LID~-njz<-zpWMG_rb+@6R=DIcGn_}EoraG} zPVv3sx-LfwV~2W9V3;?}e>DDCofjwtk2U!wxNH9cqADwFc52%7-=%|?#&-L6@0ahp zhsndkZtb5EUf*9Pt{`WMXbyxB>_8hxb>u_5%wHjA+dJ=uCsctfdrFLx9>XmdT~MlR z_S=j`!@FvLyHPi7E%_Y26Tnma^WhfM{zLEB1PnVJm-unEodV|^7jkRoPqV%K4uJ>o z`!x-ap3bQDL)AFpyvbBQKatnl!ENXx@NH$-47|cjd|M)K=TGd*-T~m3+3Urla2&+C z1H%WJ-c=2z;~eC!?akjqoP*2u{D60DbmaGIZvm`WJU}9{?=5G=eO>LbEAyf(o~i;@ z?KMO~S}Q-NOYT=_%G^ek-mAI``sF_ZUsT6^i&m)&W*_TveIxm?kiDLi0FArU=}()zHxG!vetJsR@SY>kjr?wl zw;XPWz6A~zOb@NtV)xd29n97aJ90W}r#@Ow?H4vW-c5GCa%$g)th$bWsJK6RrTpdk zy27bF?D>jF&k9I;s%g&U))oP|NN{+>*!f&EM>@wuQyg3e-A>|>$!33#yEI3JN!qh zz`e&mFdK;pr@H`3JZFL(dT(X%K3w9pfgP+nZS0d>e!Zx-u48<>$y=X(>T0O&XWhU;8{GeK=FVhgDN%3AH*IhL?P7 zqY2jQfjWG{XB_(B?zNT;5B3*^zV{B=Sm8ttbobYrOwcK>AeSV8Hrq&m2<+k1^HjWv z{xjC=p|Em_2`HraGJQoZuno?y*@hM#t$p$8dOQipWObfh@JxsfU&Ra847b$HEvtxo zawBUryf`p*8Xvk^dj^e;Fo!)X1?=dmh}Q`baCjM>E|To?`Ad}cbLxQ-)^96j$9aJM z@qp>}*Usv8B4fExh)_0K*JcA3i;$d3(YW8#xA?QaH0hcf?c$-Lm!x^a$t=~9p(Drx zj6E-gJ{GFmCSNoGWzfvZahb!5rl!!#Ku-YZItUP=M1l-aHS@JTC_9M&_CW3GnlEoO z5Dir*0YlZ6BR`B-^>}2Jw|TdRSu|Num|SQfOeh9B*3YYFMgxMqwJE)!#_MA@X;?!1aG!|BZO0U@1%3SalEGnuB}wb>)o%{ciNFJPQ0D@$083P%gc zAFN#K5m(eUZo2u2WJsXHe?_c^40F}2_(U2bLC`@Cqb(5+%kIDc$<*_Nr?Gr51Oqo? z526(DTh|>@NON-8arW*Gy=UEfFU>Fb>VVgWsa7y&VuHIMTLO>f=x3cCu^KrqQ+=|~ z*TDt~KYz!tYf=m(wd|*)%pbbjcN^kg8FST?LpC;zWn#0{jAgWb^VImRGFSt%f!_D} zJrqhli&hXqxEfS3Z;4+@358vFOH#ru>UE5sO=+p^yuLAcM;!Y9q~|e3OY8r$_iXre zF?CZyIcLWWGPArZbvohvty!%H0Mi=FZb;XH`gYLXwRbT3T|foJ!^OIe=qfwX(Msbd zt_MJs&6`v;kq(lj!C$!)?2!*vg}DAPr=8wxe*N{2=^sQ0D9P9(u#1Wjv)Zn$i~Ezt zuLCc2gzL|8OE0Sr1iyo^*@&LE#CDWvZVz~EPkH)#>VX&T>X#xl$m2p@oU$a>Q(7(f zBG$toA2sFdBlY^b)tlF_>nPDk7cXKJn=AKVY#tR25>f=8W$PXmEg`>Y|IRI+*488Z zw>2yH@%ZcT{b;M97&SWrFH;x(5p094yBLG%(}@-UDu2HG)~>VJ6VI_{04ka`SX^rxK&lsF(B6= zNS)MdD%&}BiBgB$&{O&)Hz&K&7mcV87bcn8Xb0O{DR^x#*W`RyD0X{fH@_Z&R`ei; z=y~yNN$X$4{G|f0)QbOJ8!!96yk;s$k2=QysMEu<6yc6jF}>&V`4jjZ zl4uZ4jTVSB)2rM{FcpNCW6vfio5|=gG7x)t?YH_azk}jHEaE3Nn|VCq6noHTnTupO?4=GmX-eaVn>^ zPYX)-*VLKRvzi&=o~hQir{Tj7-z|K0=5w{nArAA>d62jyT-I|u+FLTs167cxzD2F; z+c)8+L(de^fM3gMNM4vdqjI5*A{yYR>7)l>lTynw-=!zz5pu=X`g52s=PWPD5a{E$^w{KeZ2`Xw zE~`yC@TXMLDnhSPJhgYaEaK~Vq6!S%O|Gr!x7#vkeAH)+K{dwbHC<85qI&EY1FQij zlvq){W&u+o0Fd_dit!_$RyC;iF>&8`Igu`C?D3Pq&{XR=JGs9I)H9}u4ua9M58paX zid6xU|a)06oGSPYA;4`JM`R$I6hi9NCf3R#qlqxp0yuci9Mbx9$ zAfSYyz@mz+74rIOS*yXV$0e?`Ojl#!?!Cp%OUW?C@;ieLa#`Cd(X4jUeIG;H)3Fwg z6)E{=({rFr{5C48Xi%dDHN^5ncWA8*TEKzZj@u}gE2>ft28zJ>eSx1N-Fnb8&z;d} zqxHSf;#n*{YD@h0kL>2Rq9@>Mc=q|qj$G9PC?sU9h+kX7(S~82okQ**K8Gjug%Jh1 ziFd6|UK@r}jAj&r^HBWDKZhoPhxIAoP=WzBitauw{$5el#Kr}j?-ivHF!lXvx+cXD zat3k+(J87ZM9k&q_ok1M?24FNfh~DiSaWc9wO`5>_EN`Mvd~HqYR~|GInp|x)bPBf z+X-2MQ9go3iHD=(Tn8Pln=11XXR?%qE!39-u)YN+iWv^?Mt&d+CTF@Q945i1>zID~ z`O2SxLtDWO^<){WFHK^Kn z95b#-vfie4vex>KE!>1Ru%ZyC5zw$!>q@2iMhk`5cL z8YK-N@ohLY_**$p(#y3u99(!E-O!T9IyCE=m2qMF1mwUNRAV-4+dnC8r@;~4ONg%Q zHpNT%Fd4UftVMYTJ?v#EU^GqdIN7r8pXRy+blQMvjJ>W|bsv`QPVB|G#%n)q=Dj7@ zj1ftFMdZ7^nJ=85s4VHd(ClvYU8G(8yg_pb~TMZX(w1Je-Y~R1JRw3h^Uw8H06bL(G(XiP z9WGdO+h0QB54iU8t@-Fz;=if1d|WvPg~iBOZKiGvzd&V{W8a z0mPPlU1z5`B#RI*jBfs*W*o#8?iy+IKd$VcX#&$hXi+bcMb0D?(V@MxI2wQaJRQ0=(!I1qW4c39TEK8p}>$IVyti49RGiXLbwVvEA zZ(>GGlSb`|H%w-?Fs2p`M(gY$rrl~4R{5=$37i4-q+XGNk$m|JNZnJymJ^e zj#)&XsXig3DFPd$86F;J*`poqfo2$`RhJRdoV~$FpavyxvT1^3s17ryl6% zhAH5|SFK3WAh|>Ega|TeXU*{XEk9oCiP1K!Li_JWEis?zfch;#F2i8iq7(naHH*xb z@BdEFG5O3|9XoIJ<2eSrJ2_B}($%i{0sR7geN`YT`~9 zlm7i6V3o^94)|gi;__Ad*x6YhC59O2SQ@(|yA&ex_o=O|t#%p*2BG6vg$m7&d?7-R zF}5d0gH3yOKNm}mUX_@){jm78ifok33#Pk{;}K4}!CBZIvW?2M8F^7q+XAKDDudUp z0b+>v#7^gicX7-|Gx%aiJVrRJA}cb|brK8Z?sx+=z{TmNyQjj3VbS=YGRIUPzA`fe z(@I;Dd5SUunkyNJR9Mo(yBCtCCQ8UxJ`D@f!UFr{)&cTNPPbZx>#5~8GWru=`$*@> z{!iW$X-YG3+Na;^$ba^9ZO9iy7H^F#;|f}8q5UBtrVXC-y1G>Ps^Op*94re25CT)N zfv>bc+_+N>v4|S4=%~0vAN&ahj#KTZVcuKnuH>t zmu(ZcoBKG*sK~g3O(I5WCrZop96&$t?q?%fxuCI3=vFX>9~r_|FB=$PG1+gzvMiEz zMi;p%6j?^ahHiwcNSVnU)5&|i3r!?zF`W(P-4{W76L;+vRd>##p&~=_0r$yR-*--Vm)nuUP_99e)bJ~>rC znHjaw=&$KeUPIrd#Ti|G?XG^SKH~DA;1B~i3DTdoi`Ql?XIwCRe$NFz3(8Mc**vS} zw?Zsv+4C|Ydmn^%Ih+1HqTW7C=CC~RV#?ndlrQe!Q99`^bxJ(1+YX2akWkyof_d^e5JIKmjT1*>;D^sTVyxttG|)i(&pvX^jvpoy}2>ZE!{mUtm+xo-igIt2P$G2pkVUaOvW0pa0AnK6Gg(e~uJ%hQV z@m*`^^dd?rXF5Qc+e<>LS($O^_SttTrgO5Buz&h?b=UsD797Q0>yDop_Nt`{`0JjS;;iTc>uuwy)ZCvWPySd`|!G<{tb z%4CVazWkmxnXj)@26y=@k|_xD30dFkZ{4=p%Hr$&Z;C_B2vd6l5FcObb-#=nQOdm` zQzAU5dC{25q>?rdQcP_NZ(2&2Mqc;`o|(kkG17F)US&jiQn5|I7-C;~qzHs!r?>Q% zA7YP54@S|pcK1j0sdM;dnkGpjB7D|@mIkxabQes|;qKu4Qx&fc#l)sep&_+}sDAq> zQe6=SyOWM%*EN84xOa&jj@aOHPng(S)wo=*)vP4(R;bk`XLP*;Rl?%$q3HeJ-7CK{ zP@q01RUWlWE#kj`>iDIngWP8iQ?PSo5VJ4dO;;(F)FzNXo+=+9Bw2a@}2KxOcxZD(bbsPEz+~PU*j{vH_7be-Mv=X1G#IV4F{#+!a$$TO~s>?K- z3j0)ExE+$wE+4O@z@=uTrD(Dy36s$Q%7o>kcjMgf8osNnB#W(TMK)ZebY#gK$rCCUybLifvtUg@i#tjeyKb8W@CrHDv0Vx$jQE_ ztv<83iR&*~x1nFo5-oPD5tLu&*;Ctp!&l98c8S>u%Yo~G#COrcFqY|jgvU))!Dx1h zQ(Obcs}$6PwVZu$18_xclTkkChFMg3d#O|gStvy%tLtf;xOtiO)UJ-YB~GF~lD_A$ z4Cw~C&8I8~-qF5m&9%~h5Wr7zd|$M)AV`_KMTnT46~om*n|PaIHqF*Hw(n5AIC+(K z47sm=gj2zd+N1{R#E0Ti- z&r1It9|bJ!>uMZ_@wH z^7bejt7cY1Md%Im=285q2*T--CHvhc6iU02c!cs55<{m`zN{i@b!aseUENEIMrkIe z2$6SW!!%uNL#~eePiO-EjS3#u)}FLAqZKM_^{^a1GcQ^R9s<;+@nt^OfxnN0QKiGa z$423kpYMe71%9=NV0Tkf4-&7qAVlQ$rHdBts9z<0cT3i%nnjqB(z4>!7_xe_ry#*@ zk>JnIHQG0SjEkyZEfFk3cX$^KkVudx_s4yf7bDa?;*9{&5woQ?=dk!SwLJ&r@{uNd zE5J0ox~Oby_>|0XXI6HR&x_slR=z9rklFJu-r`m^m^5i14thA8>|*jap($^oO7m(% z$oXhqP^@Zl!WJmFrCpsXwrDV8%skrCyy7po(QehUzphi_T^~i{$2P-jo4N8SuXge? z2(rEYbW2N_`$-83hJXPdZon=fr}f!7GPaXOplbi-E_qBhd2*`#{L8O#+n~~^o~ET7 z`UQd8hd~QC&G1dzUMCyQI^VO(mVZ31-IhuSw-OVFdAf~8i3X(Ey@pPXwjG3)jXio= z^`lc!L`;m^Jjro$a~JKC`a#hnWyqTLjb#b0u z1gqMEAF8{~S|RV&BtR%GFEPVbP@AG{&MhVf>2(aOLhzHe`e+@QFp#3WWYNRuPWR$)!U z(t{sFTtD)-DQi~2ykGalq2LRc61)}mo!s57Ki=#oC=lI5$PS9Hx9a83+weVM`17xI zzHWlVP->4kDcZPYQNk1DqmOtzu;|iT2ACo(_$wXwRnx#V>KJK*f@5zt(h7ke@=B{- zz6(FRrYjOoR$j~C-rN1^u*2wT8yIa4iRMMbBn8iz)V!~)X`eaCQ_VRs`f9v18S}yy z`_g+CfC+DHF@ZLbdd-9;WVL<|w!tIemSrbv$BPz$Jq@>AbiESiEplpu;48O8{Z|u@ zg)iSr$yOFCvsy(U7@@i6*_&{It!>UZ*tj!zVlxXJD{0EI3NoHYf) zxg6yXMYf>ilcsTN`x3+&ngx+nVAl}uX2t~0EDM$+`d`ZhXExJY1{Vh#G zDPh$0e!m}WxRsV-DOm%cvU#~Eo_b{_qg%m$4#|xcz=oE?&}eC9J7AmK_A5<#u6P~a zy?%H3At?GVVDnb>R4(A&f3l%tw-Pu$BPwV3c9$!Q$r3Nx+*cDn_AZG*xt)Z54T<7OQo z*OW_jds>r*EaRY{$>PC=cxNydLxhmnOt7w(?vXFP+p3q(Ycw{ z?Nogg{uQSukn7@sPaU7w8QE6EZ&Ll>5ImJ$CytQF z#T0Q11dxHNr}MfKfbWh=c<8s1GD148g1bY)H&~;hmgl)gXX)R8bTB=F6!W$vG{xU& z*dT*8%Wi@db@OH|dh6)3k%UTpa~&n_r8vvtP*$=@sp|cCFYgK@>iUlUd>c!%*6>m@ES}(OsZnmTIXaH(Mck4v9 z!2avb_gCd+Odtuya~4V@tiEB#5PRQt+v}x({V0o#PO<>lJWbd>>!=zpzP=k1rP8Q`a#88G~Bk+t0MmD@{>3F{XBlG)4R%!-vd#Db$}_} z8srD>{(WW@-ORFzjb$qhM?MrEjwFL;ce6{TS&!6X%?Se!OS{e$1L_U3yD|Tr=5L zfz_2s%Drq+&v!feyw1Swb9&=yoxWj&bc@>dtI%?|Hb`*o$$qx>t7w$LT`rG`xEZ^mHLfIe2wp~7vHs` zd}cem?Ho~yL#WI*Uj=x+o8lFe;nH)k-7N!q2aw9@P~8%?;mt>_R;fLeV)JOqPw5AW zSti9$bH8wqtoXf6EG2(4L$AC1{9WePDU-1uTM0y|4F6F?=%(zeIEeGSLEAPOIU0dv z(kNH5S%Wlj(HyPu#pye$hS|oQk%0RW|Gu`%73^yNK-bfq&w=+1Mm9g{6V1O5Sz_>+ zyUw%B5Y9B#_N7gWMCT*E#lF<{cVTdyTn;+K?GG>&GKu-GzhgQsPFZ|DzlFUdD%*1E zppz@SDConsxR}b<$qEINMoE6o4MEQhAs9IN_2lG;o=in5nfduB;y$(*=wv6+s0p}6 zoi*_>~K!R@rGu--gwO&;ELBK*>_jW+?onnyW8h3$n$&@#V zcm--LG`IAEVAwrVYc8oRYx)K)pmUFHDP9HibbT27LCoCu00i#k_IlODB>Uiq47Q{^ z5%@SAm1DDc)HrYuygrM%AEJ99oiojcE%TTi`YnPq0B61WVBS+y| zQ2PebimNm&zPrCmuw$HH#s~DQf?&3@AFjWCjhCLtqI==3S`OGHCy|ho_WoQ>ZINuX z1zRg1$=a`YNyg5A!Yow!Y4h$!+Hduv`#7dhR}{0m5V+HM9e7H&pcLrV>4m?tCA zoU?-yZVLSn6PA`mH(5F~z_;Rli$I1IzFHhZNJy66h~oVr)tOb;B|&3#~ft9N$~uVU9(C3T;X@BSuaH zgb#5PKv8TI*V#C4OE^jCL$%5H(?6c)QYa$%v+7-k--By%cEXzbeTK;GNLB~^9JUA9 z<}rvIG*9({S(%9iN_XFdhQItSn;f_2iEiz*;NxJ?JGFni!IolD2SS~f3yD=jejzG8 zE_W)jS7^5iitS`L7Hk@_u3-Eog=@8BMnH8l*708eP=!EA0Uz)$0!!@nA(em5AZ(oM z)CoSX&t8yeJjIlIf+h8|zd5SOL8LB-06Y`fIRL%Yu3vr{2N|g9xpP-w6P(;hGGoZc zpKvc$eftZq%hri+qy{!5Taq;KhHZQ{)8!v&;|`_aFI|vKzsY}7w)x7kM}zq@7Q1LN zxa3nSJu!;9FrOTnYDN_6j+2IdGJe*mM_OZU|JSCU^G7aF3ubX%JVbiRl1<;R)ektWM^bJ2 zdlaBiRBg_}9nXkMgs))K5c@#zR9@@$8<=DTnhT};5WR*m6pfA#_C9wKB^fiK4p0mB zWndImcvb(Dsep^!U;Mq6;q@;}r}!Ey7Us0{`;axk=E>d>>eu5Ti_dMeYq#wYfXssb z&BZSf`~bfKDVhK5PiENdPh>||f9X1@qjLXoPnCDB_ z(XxfXbplvwxrivD0=f1-tT`0OK@C!WmX>T1wI=d8s4OOtCQo$Oy@a|ymAk<`HuaQ7(o z4{tox(;?6;6xem(3GTiHhuUP5))5O%pacG$?8TAo9brL|NA@@B<^oE zXKNx+U&t>ZpV|5q+5R)}0jeu`O;Mu&DD_(B5aw2g09Yzws442QQnCLxcmf*A zJAZg0W24Anw|BKn#rXBAaLus_JtS+e&hMh_!1!Jl3m$aeQ|VN8g-eV{AR z)Za3)&7xZDTHK_;9b#8hEji0et{VB{>Hm0P;grLQ7&uz??zZ|WyV8h4zhWO1kYbP}+{3E?nxr4O7~`+{()5jrgD`@G*}Hco4oV zGWf$!yD^4Ib>N#)WA(5@`tH;xN@m7bMJ1DZk}>t(pPEbH!FN^ens>z0i79UWuQW@< z3IE3-X%w<7f6}Z3_r!2O1;DeUhkag9$lGyBI&^^keM>aXCuM|d*4k=Q;?#mu4ps|{ zns%E^1DyiI_fvr62Id#6gh^xo5zH`;sgy_>SL@dkdV2G(;VOSo@8QH^-t0Uo=k})( zCN*in;sWWi$_4c zD>_%MdQ{3sraz>e5lg`|UTF4qB~Y$j2=t%7V-r?J2B zC*6evSUUMHbu)EOOWm-u20seW<))BAQ2tu$h@#q*iA$R}{{NMVxydQZuoVkjJnR$a zIq=};5SJLsId_SN+tND3Poo?gO$_>NY8PboG}U=%PGd#(JL0SNLbb~LS1W?Prw8}~ z&|3L_oDwOil%p3WGb^@fu#PNBB+0lH6+EbrlxbLwpY&z(gq@Z$FE-%1M z1U>B3E=!+#6OEQeqM7jNrEVK$mjkEGy+NKiAHFWcDZ=nJBhvffFihK|(dYx-*R!nh zGCw*xr;^z$u*6^E>8c8(QUMWB>y{QHP*Qcj>A0*GXpkn|k-7hOdSaY}w^6))T!LB; zBF>(0@)h-7cF9xz(daA({eF4PwV|D1-%IetqPVWPCN|}wqYpxuY*S@y#?&+b| zVZOIe!%-1vo@@wbQg|nh2S39`~W1BvSO)l|M( zN!!Gt!n|S`X_W5tMV8{`>xVimP<5_>%rrmdt^M!vZx#NQLHzB8lj%oEuIG?$l6cl> z&OfGQSJRqUmz0~H5$x}WIh?R8uj<9jmdlo4F8#K=Wsdd#cSe)5p|v-BT%{TrW9u3< zo_z4ph0|>qJC|e-Us`8+-Hk>NiYIzjR4(-U5Oo2(yLL!=8;TMp8J>Y2tv_gFPHqZ* z>62(iim9_TA0v%DZW#k%x}N3ZW>`?-HPCkv&7YkVh{`$UfwKduLncZH*0azmR@VN+ zuT*|K$`dfP&XB(hK%Kb&jZySh7KsNNf=rFF8{ZdwyEv#$6q`VAaq)AdpcCf#%m=rBu|M z^t0y#5;WJ;1o?h9!e4D$)?<<04*HC=%{*VM>_Y!4N(({`ArgavZyCuS?GR9`j%L+8 z05%*}tGYw+5RZ&cJLxKpXczu-Pf?KMUyWQv&`Xw zdX@D9`osqJ18n(l^q=`a4!(;}nK4$xDU`bth|HEirhS+NRUz7P7`a~QED`S>706F& z%nVR;BA7IEY75`wCXKpDx8dlRtp>`MO? zLSwg7*mv!{c6U?6Gr!`w&NK|(b#gcKOE~n>BBVJkAJG|oY!gTPzjp->Rr(q1?yUQE z0+mVR{J0|oL*4+aXIal|7Y1vwv0OS&V#5MO$>tR~4+c*HN7YY~R(KC#A&AsUvQ!!* z&f;z8CN&Hw_5SO1IZIG}kHapQ9F*`WhLKszef{{6yA&(+fYI^c`pW7WY_F*8e z699RR%j^7d@>xEHd$PA@f77lavkWF!aRc~f$~WP5u->-P+a>^BnKwBN((O6}J5D&d z?RPTHop3+CZ7cHTwDj^Qf6~wOpLI=4Br=H=ZGLcylivj=Ag0Ds@>I{072=wHQgV#c z2n-{e`02dA7>sbkYP?+5)0&QfZ&y_Ym0Cs!S|h>_*`nx03XhbM?N99R_w`A_Rd{r} z)+j0IN5{QzG!LRcn$pTb-hzb@YHRZ$G+7V*EBVtw<&4{7?M{fUU4KT*WJUxob@P4J z$pdB;WM3QR_s@;E#`|rMpO9z+*n`ry*-HEZTL53bo6As~1qCWXR?hP#{Q^0qFfB&v zUP5NSCZun@8?%EvMP)rbS1jG$t%)DkU%DRc?%r+Lj@{o4ib19|$96=MySl7@46(qv zE*}qxpCPkfJTn;1&d)s!6nVStx-Y?8+V|Ja7ScC(xxYaCb?H0@OrVpV>nFD*vS88re*qkRuvn-1C8p+u7r zom~gqt+!vjnP2-G{T%EkJBX?RaeQ|TUU^LRkyiYiK4bz#@i$(^&WOv~Z|~Q*TQ{iH zFX!^QI$FQ$tydEv2I%bIKg-f0;*dW9EOLJ*=%VFMnv8v$Zo1#AaDeDnRtRT0tBsnLYDwwL61(Ft|H(V)D9zlcU>(ke!f zYYs5SDfax6+YK32p&&JHSXk>(c5%(@it-7}@I0*e^G_O4lv?$7he!q*2)UAu2tqI~ z!6ea+(6MKKcZ+LkLCFXU#y>_|2RQfK!$MvNQC$QYuPak|GsJnShoPfq~LdU!hJcQPz z{k+Qcd5`3&jp&xld+2r1_i^!+m$^-xac$9!%VAHpJ*wi~&tiyPq>3yA$Dw)ux#bTn z)UFYaC?gnW6{-ZVSX_B zV_j(}DVfT?iw@1>pT4|_R^)z%Pv*i`DwkrcW+khxX!Wv>n9?pLgU`?()Ve`TH9)a` z@-^Ot*uTi!|L`x50r53 zAO_cWLm6$`-AgYcW)}4YS(zi8^)Io)@fvgtbqdg;&WRBd_N=DcxC3P?TI8FZ6aZEqx+xThx?S^{COkmQa?RkyIU^?fB0qm8r9a~J>*3nPl`Mzc>WQ@0M{^*}QfMpGbu$9N?5{p46O z4@w%$aup_8k%mzYQrFwbLh;J^)C2*gPm}?DzUu^4jKX4|>3;yXMP^DjPX%|?w89Pp zv9viHI)coFrJe+}K#^nFV;8&ri9^#xE7ga+QkhFvi<7Vs*CLY?XYcAOJhLY76af>2og#+_L9MGv9}3Q7>3us+e3(& zszAswd{Jl3Ua8a(x4x&2U8B+z3e{D@*PD>D$lm)$DGO$ZIG8uXQ=85uq`KY7YxF9I z%PY?Yu^ykF-QCbUrVdiewOjrZ~XZ6GR@A*@N3GlE!B82x$l5_Y>?b=`-8^7_!_?+ zhN}dGw;C?d_(8B}iW!VwO&x0)Ze8q9m@V1Ve?-xi2fze%K53&SK!T7f4F=pVAo5Y% zY7;T1g$MJZU^UW3xG5tFlt0?0JdodIGxZ|r*PR}VAq~%R84lEOp(1$RK>G`tUiY$& zo_6Y6TDeY_a?o#(k74$a4D)x^lr7>u6dH65JIhZYtd))P=ifDTlr;75+P=eMRPL&e z77o&f`cw`v4P1`K1ueE)%>Vo==O-OwR3?Rt|1d_+&CeWZ4HPXLZ&YJYGx`se5?vu< z@msE#&Ds}M6S5bEizHZ+J6wK5`=A(B#t#N za_xOTbycKNL23GXHi#cxn{UpHy?li7RKI5YqYnU+in4GvVl0`U(Khm(g-!!6$wP%f z7+uW1Fs!*VORM-;4rwaj6UU1zZD@yVy8}JrsXuM-;trTHZUb+IjzvJxvWKp$n)-yJC;TsorA1AyIB(G#AJh?r?pyW@M0zx*oU*0%gcbBBo6emJy?)7$x~b+!S7 zm8S6Pg!YCXOVB7u2!Tw^G?HD7deMVhnj=+AgFH4UWeI*?ok_`WCQ6;9)hlK@T}P7| zMF2P9HPi}M!z8EcWo6p&9RBpgC1WhHv9hgA=<(&qd(wbp_nK{*%b*ye7-BDrCvv%* zQ&xW{2{ri66*C?FzE3ePq&?;g|FuAci#aN~DNeXL*A?7M|k`(V!jbtlHpU<>jgbY$Eo@XId9&OraQCKhk;SRyd ztPS=KpLPvEOS8e8y}6Vb4nMwjDSOVrr+L-RIuARyjs6usQsVwBU7#qckJGQJPk;{z z-#=JxUjfP>+22W=bU9QAKkE)NKVjbPcfKCp6^`_NqTmjRy$lBk$#y*dfT3{1Z!a$n zU(i71cJ}x(cAd-dYxAnkqn^*Gc?Wv3PN@#U^rz>E!=S$I=Xr3@xT~_~mmYgxepn9K zMcPxg9FIf1J0!vR{@O_|k~4f!VyOK}9DOk)Wir8wZjTf~a67XcWQ)>(2Ds(&Azic{ zuoW2ms$hFEkL%z+K)!QrGY!~p6P6y`FRKqP;cBqZCnHID)J-W_q~l54 z7D+1oUoy%clgpr0J3zItCCv|p?L8Voh4?B?2zCnP&Qd$FYWp{ZNTnf9FB@sKOct%t znMa^2L_lWe#yBJ%qHJqIVJxhW*-V^PEDTfTvT0)fh{u&bnV}i#rs%dUR4>|CGI7gw zH_ovGv5*4P3&lkj+%Gx1=X)b-6?)}c-dpHA*r*_7uaJHf3+Ugk_}RmlpBDw%8E&-! zI%?tKjX{eDGAexPE9C*`N|uu-Cq%cv*lMpeEvMZ?nO_cm7<&Yre+H!yS4<2T0MnQf zmc5R~O>|$A{v=giG+^J-pw0uLbe5Zvb!lO;V<|OOc(%)K#=DwQxbK z2D)vS4HZeb|G+#}!CRoNRSjYK7Y-WYmwUGA>Y_%Zg-W9ZUP5*+4P;W&HFn;v{eW}8;GNG222H3e zT-j*5y(iZ6Pt{@mP~Qf`nRMtU`?+~|kSXxoUo*>_so~MLx=!oLcC0UV0j62>gLs(I zqZ#}8b;lnG{gUbYY!KYxm_Da0iFtNBF5Kn9mO+9)>%%x@>GhD7JdiK&1y zv!;(6i-GpjNq!D9c#DI$+3k?JHE+jYfETw zaoV<%)@byTS<-(ne5z0ud`6SKyx{OpZ3jPVWxt55@On?1z#k_#G$!-YC?OrezhAuc z=38_gop0wZ=}&Kt(G31#4I@X=lhK?(cjl)5#xzUu$d&D)+FO6F){Leu_i+jT?vp7% zYojg4v3O^7vVRcj1(`_;+LfLeB8T?%L)%pE*2t-O!5n zQw$+O@nnbgLmTR|EWD_(iv@IQZoI32t0D1~F@d9*xx* z$YZqi1WR4#U&^QV?(td8AEPF@pI~{|0m*y90YJ{C@kNQne7@Av*^7rd72d(f5;lquy_Q?<6n$JKXh3OL zQa$i`DiDtJxbOD6RyGjza%Z9W*^!t1qlQ6l;O_i+^ki;>Z087pl|Ok$vJadbw*DFk ziDGG{MRT5HVMPRiI+V^d-+?2-Enz%vuf%$eu9uWgx%{EO17trlT?6~B1YpHxAWSyM z8|=o$Xb`x#s+)-CWp7lIj5&(>A%~s3a!$!qKm$p{wAi4k?rlQpb#hzfB84Lq;8+Vu z2brxIOG;5m;26W_yJ>l(7Yk7f(Du4n?ZkjP$P)-L+$B2*&AG-*&W=E8(=!VygVP|y z%ieg4eS#SkMg2kw4^ag-miGvfz^&(ux^k*T6T3cbL4Ou1=xKpEE*3>XlR0Tn>R_!o z2RVD{a;j*0uJYaXVO*-q#5=HNH}}{QZ1EM?!~eH1k2>qxqJ-~QrO7R4MNP-71K2B2BCFMumc3SFC5ztl5ye6IYrnfgFF0{cFQjOj~KsFg0{$>)VP=_*psL${OK*z(kKyw>`A*n zQom6P3NBQxfS;6Pf@XX&lU?p^t0WV@plxPvmD7NV5{q=Uu?n{m`reZR38b}oN2gf{ z!GIx*@Qm*CQtEMMw(q3v>C%^sCnCd*U7O(xk6nOiSxUmVTNx&$6$EK2kS3|E8@d?E z&}~?f-JsM-=+cn;8ABCelVFm@$wh4*8d#^WMS(H)MaPrL<)EdA*{Yu;|9H9ZHG4(+ z;pO*$w%GAQGQdGkJHQrArkk{lnsy(g^&IhXZ0ce#_Q+M7x}QH_;buAz|5f_OJ;Ha+r?-0H(LM0cd^E0p@UB zI%lru9$QU<-RZ5jyUSlzj6DZz#|i`{K->*qrte_jsI_OF8(Ma5!~Ca~SsT`)yJxu! zuRqx`8xPQL9Znm)G%Tw>K=m=<_}OP~Ug)%n!bOKPc-ydEcEOSw(U%=Fwgk1{HhmaR zS&LR4rN z9iUMpr*_A|?bt)%QDUH?>5?gr>;Pv}=GgOOQtz5G_qV8v0L?8W2&WnK5X?;>A zqc6GVe9L>?hAa=`)vvRuV3)!p>OSXf$!V}X8X?ed8QW>k@d6LC_uT#^KHJrAY%a%g z94+sf#Wef|@fh`_%NZGlmUHjBwpL5S;f*^4foeaMQf01b+H;U{va!`>3?6RZPTX!w7_Ts+Sn~L9+@K|z(it>bUt+_|lHf?$O2Z37<3i^i`Lud8`Wj1SN^j=4nq$;$7=_2I4*WoUsq{ zPYAqvQ}$``r=QLJ9f2YUzQx%FlBk-X)~{bH*~|f5UsoSoPnRuxrrF;XHy+aijs^FE z86CH80R1}PrB|+}Cqz|^SnUj3GdlMO)e)n8{CPH!S^|VC7T=q2H#PqOe_IVWN0I;@ z<{HTdk7i_|TUT!%T45bWJj1Aw+$-svu4sAA~hrU0>}U!AWLcQWGoA(vp(@$Mtrr4HuSb_>;_O?c)y^ z>LvTpQgy|qC#SDI-Dq{6^bMdo2>Aqv_!mR+D3uc9mr zkUtx{&{snmIAhCAi5KcY89td()2tF@U&N&BzUY+Ue^88tK7pWp4QR=v7d_6PqWdCdAFw}(l$Y@4W7=^M05qnwzGmnD~8xtsL zqeZ5vBBclw|ARx8sG=21V4x3iMRJYZD0x2-6+}e)0FcrtBda)7N0$Pw@ZDt5uHA4F z-1owwG8XlqQ4V>~*Q%#hS23f;pi-4-{Qi=I@Z(5;jIowd7U;B^?hFd}~w%AERlMJ@P z!zh{nX3i;8$2a+t<#&7PCLnMh?8o|0rNUboRM+-&D^r9RD!P`=*v@R{E8CHKP;*>7 zTzieo)y$JK>&EUrW%Q$EfIKcomQuz|Mm3+FvF9n7(hXez&>#bI%-ACo;>hujUg13U0N1=m-`3d=p#HqR3WZSvEIqnF+2-lV@++z*Rv$`spyt!yxqZi}h6R zBkH7kt}U@&yVC=bVQWdC8wC8lK1M^eo-$ufg2;?7zHbruiDQPAFR?V~XH@6;@i+VY ztF2>P$LX6bJcNpjf3YK)v+Rpys2W5a9K+N(hu8JRT^K|gwrlu%>@;6L-h0rQ;$E;L z-9e91_Cni`tG?^_L~=QwDZdS`?}51u<@IBQ+6D^Qq_R{vR8R6PrtA&1v)|@M;}X4N7kZKvRo9~1J!CtGX)bn@CPfiwZF_G3Tpwp1^aD1+%$xB1 zt#C_3H1PISfIK(9?(YC=i$-hMS4C0u)cQ~!UVB0w+f9(Pu&cAYNuTkt{+Sj^?993sq|mt z#-RFhemuaTG2|MfR{7YTB35~y1N8W?W88waTINCyTJmZ8+-j)=y}`cVXOsq^ASP^J zgrU;zs0VkXp>~3wkPXXMSq<~6i)**d*g#B^KGZ`ReHn#W)6k!E8iY``xP26cT=#D8 zHy#{`htQ*?s0>YQ$6umQj2#@|&s2tlKpixRILYb$6>l9{3P(P<&mxu0vp_~X`fgS) z`IFB*Mr9J_hh&Oh6PQ1}bKO5Qz^$-Du2TD^bR|k?ee&Ogr3jUClpD`_6!xU9#6tdx zYtj9zs3`DrHyQn@HMM7S>62+wQGMl0sg`ZK18Q~r=iF7G6z;oK#SgvkR(Lr}=g7{= zC=1bWwvtEmdFNI2VQYFaSz%4m`9XxOUKuAyy#kpi<;`--=0w=sn$li5!USZ z$!Ei`C>|=Lu^tbqUXwsCrsr4u3*H#5l+M)L5w z(UNiSM~O}xFD@{|wY}Kc=#=v~H;hi?1mdjivWM!*EHZUC!rFjQe+zii;kKBxdMA z|DW)p0$04b`=tX8EA#dxCUD5{4J3x@_#-0OHKmQg5S|}YL2SA!NyX5A_q4WF@g2%d z!vJ38S;XK|Ze6o^5b8!4`Fn@g;$8XJv?+ttrwr-HVn(U_HwcrV-A#^uKK~_=Ba!^S7Zk|x5M^t;eFM@IX%q#g!atkBHa&~f3g6a=7Vtu>1ZzwC!YSv?BCW*xi zvlW8>y|aR@0VkZ;aQ0)nesCPt3G91|qSmS^-$L_b8pEVSqWg;8)RnH!S^(8WiQQ_i~rjeh2H`e<9C+9c-KzVSf(b;ltk15ffJc&sn6>N%c zo$~ZX;8Q}|7>RUu_Wzjr3br_xrQ6^T9D=(gxZB|F?(VK(a3^?hcXxLQ4uRnAZo%C( z19!5|clNn|V5Xn9tEyM6l6B#bL4}A}j_$=2IYT+g7k@j!xhg!!i0Z+TE{-xXBf zKid;cFu2UqEZo5b5)`pQ>IEwwe*7z}2bs7Z2M2K;+s;QY_T%g4F<}FwwxosT1&RaZ zianu{K?i>A!ulk7q*9YmPSw;@U(GHQ>Ebn-pE5=(H2>$=XbqfY1i=<2C&>OK1GKXw z$M5NMl1-~W%@M0H0s|t&xMnLUJ~H?=tUQ!7m`0hjWxv5xb2}}t!rcx_c>b*dLH#8O z&xJ;XzR0kL$O@3)g%so~+w?2T5W(DAz*~WZ)6Dvep9;qZ=^wMU<@A#;#weLM4)I%EyY2sT5lAkWt<-B?*sgNw)4#n zj+?gRb;wPiip)`2^S4d@?wl;&Iza4G7lUKIyNJC$se5UN?V$xDGAz;mSG4;3!O)ro zTho5=OAwQyTn{P{H2WC53Z#t~$~lAy?8kaM?a2Z7Hm^c_Ej6fog-Rjj>6K`|T!TdR zCW!yA#(%%mV#MD1_I zbvHHLKk*|q6%OHCROXOcikj)f0H5Zcy(Xe;L>VNYdI`gqH#KWZwpuKf?GEjkjoRsBj@o%Hm!baWT})qJH~ZVjI0Y`{_#hwO1rV@4 zm$GOZ-HU%cYENLc4vF3So}8Mv3+Wp}SF|@d382%!EiobCESu)!CaL~#jUKGV zvgh{4s;pl{tp8I%{2LGBIQlXtFWwuk$b7ll2eU;Ek5#E8(WUmji8jU(rb=P2 zH=v}WzWZQnvqQ{R6~;JuaAB#{Nf(_1M+d?C!SMdJE8)HTwkM7?=Zu=r9OYjV{?JV; zLT?|^rEbR=dMt8$XPlW`>ZEXdoezb0i?U?mWM*c(-be z#oSKT+7KDvD0uD ze67LGhEkSUNV@?Ja(E^R8KQ_98r~>DB;dp6@;w^6ljLeo1Po3?3*u#;>v8R5kov;o zLXXYDs`t6?UC(2Gh-;$06ktL&$PP|_;?hOd zG20G|#{_VQ>AIp#D@PQjZ(1_!VEGRvX~m8IuM5ilOLu8lxmVEA2kEcuNl_8xjYLq? zzBO383DIQI7L{|9D`ZM|bZ=38HqlQd0yGYETG%rBSL?#wJPa-kYH4r6!%jkAx@stJ zaUxqp^#KKCLqj2Q0U~@62i=+> zcWo&uc3y&dPTMEyzYoF+ff~fmkLjl_&tEKU(mI=EwEJFrmLciY3%%Z_&I6pq8wCTg zMM)CWTHWVf$Se4iSETZ`y33_^E2BPzuNDyn#uWyjpozplR9ENcZm12ZSQC-68kJK} z@*Ee|h`EY|{Te9W{c>JO@#~O>RDG@NcY11LIASH{Y*l|R;(xJ(nSUK?fh%bVR9HA1 zQH2!~ZsfWfFfYlAl(xJWC5hI#Ut8|86!2Be8T!Pt31i0`RBmq;&|dy4^qc(*SiFbj zpHC8C;i#5aGKrecC7&8QgV~ndq5x-OR8eA4ErV4RZEO`0_YBb@sG*bjxsqdkH_Kkw z?Z1B?e1=XoVkCYj!pVX3^d@LxAr&5hj%{|_d$BE3GMv})otq*pA-MG{Hj(ygL$j|I z`fU?LTtmjF(ayX~!Ptw&i#R+$Z}Si=L@Gp`k5;qTsdhj}KDjjc5wxUC!t6#%obcQj=&45cf`B*?Fd6Tz&Z!{=b8~Y#J_*gxE#sQ8Ym-qqL~m7ouef zjdUtyN+h+}m~{`$&6#A@ZOg{BRj_hbd49>P`RsazgzaN3foz+M2JB@9JB_LFWM4dj zdLPiSnSZsNOnq?ZB-PB>Lry0euQKnu^$tcizI=Eg#j9Y2iB-9Ql#|;)&*03f6rpJrR3b3C!C2zxJV4VD}K{tj2oUToNM%)nC(|?%dsd^ z;`mmvo2K>4W5cTz+r3u>trzlF(Id>#s)0u)w+lv|e{ ztZE^v(VkDx%0Ly+oo$_6;R2Bp$(jW%N{5+?%vFN_4KN}PD5%2GD5sVlV>ePVXe&E$ zTkooagK2~$D`KP=n(nyZEF$;;ek#&(&#Vc(+U144?&hbJmQq$NCE*jD-@*#8UWihd5 zQV1CfyW9u=&Xqhw>{2R~N>LSC&!hfTiP>fC8 zGU8W1xjCho^z9B*U({SEB(!7x^SJpx(kx=F2(+fxZ6j<6rzx|ilq0h=ITmDH zVEtm&KK~ac4EqHENo0oKgQ`}_Vt4Os$c;81O{H%r1bpaM&X=pila4_(zARc&2{ zw~em+l=fjmBOo9Hd4`ts~3+k8A?}%tKHNWcF@?=>Q~kB%xdRrM4Yr z^AER#p%|8&FDFSKnm=AvhkLDu(m`Z|uW*WdbtsXjXu$y|FtB9Zw{k@y7 zfhCb5!H_%xK10grsWiw*=GiDh_&(B5=MsV*hRC$5E;FNeg_%(>W26P-Nxtz-i}R1{ zPv6IoI`#kco>x(QF}-jUB+Z_8Q{*@mL`ocSuJ4t06vMMCGv6>kIOWyKL7Y^&{c05R z3d)b8c4)so?C6!ENKI*&MBv*589{=14OE7RU_vOeq$B93jj@xofP4PWP#CFjn4KfC`ImLOH4mi_ z0--}3DtDB--r*d_p4a`X9fo5*8ZL-VOe7;e28wvkYT^E{UiT_q zZyxwo;`b`>@#vDP@YUW%wUMWHlcX+R$~7e4_(P?MP;}R+bVcbblN&^AEJMu;%Tz*W zG=f(FyX#`&g{vhid?E{ALHeD)mI@bxh3DMtvrzOwYw0_hi!mK5aYo>YQ^w-OaL_jv zRQA>L0nc5^neJddDJLpt$_GGc!VBjs<&TQE_CNe0E&nCk&_o`BOeCfJzX0eoS8!FT zks0KOh0I0PaPx;fL2tFqqO+V0{C$P0VnhV8grAhCiAn>j3+b)dh@1uC0X~02M{j-K zHw$g{+rw-UCx;sTi%JM+izq4nnB*aHWM0z7el7)!%g9EUM(M%pd1DtzIooKO`h0G? zK(Jg~Gq%(;Jo50@|7JrX!+uKhWIjnfC@X#O20OltS~=%1D<<)0&@$AsTF)CKSYPTS zr1bD@A_o4T3(AR6(DDvv1dJMNTh*&VS16+aDgS~c7IZoJxd|*GM+$?Q}W^Vl=zdr}|mJaI!YR`Lme&2Ob67RXSa08F&`-Jf8MyZ@J!Deh@L>`< zY;W2VT*V+nw$HD>V0Hf0(`!6?Vq~LJKB}_99v!Y!8_J_RJGxkygaCOjq9!v|{7t5c zfi=nA)NR-ZkMuts0e>y#RYZzaz1|P5g8PS23FO2{ockZLHP}#Nxm!5L6*8N|-VgF{ z+7z_S_N(aK+*+L#5<*Ir`+wl`=O3*a1iofCyM8??(WwZI>;DHQ!QfH55TBU4Wg`cs z5miG}aox%GaOvGLw;P^9g4!Z(`|E#( z5B_ExYr`M3u{Sdn3+8DTyhu)ldF%{F#PqL0@&6mDd{gRr535g@tzo6d?}~WZ$}7<9vxCzqoVP=o zabwmfKzms+Yt1~i;*sJI=eO&SI7icXg-W8I^@EngfhP+?{p-pwzLG@hsw06V@>jlB6RuJi(f^M(yKNflNI>m zXgw(^`Na^<8s4m8!t2%G?Cl641Pc3v-yv1Sle2d-^w6rw3f34wkLKBvUf`<;0z+1m zti{%EK`2}0r!(S2xa~PLi05K(;z>pLyi|Zrds{64!>SxcR7sr_+P&XEH(zGfv5qSAU=V zA-g#CIXldQMEJz5YG=s(?s|Kdz;OWkw1Kg4!6xq_CDmTte^M;s!R+0`t|?EM=9pY< zCQ$Yr$M1mNHtQ(yNen0aY-0{V8vp~|)6v7Al1*?KRPoJW(hh3&znEiKz<72sf8@i+ z<$Jw{XF@qX)H3W(EBP}20+c;9f&pCh&#>?{QISD>k6F$l*$5*iw@J%n zp#iP_1`FkB8@11n+?;>(<{>3i0?yP4q>a(BYou(EgQmJ;W+Ec3FC=KJE`IllQ!ueV zy9}2%IDKGS)=BoWdUkS}{-0BTKA1Ny_{5pjli9KEjem^)iSI*|T7BDP5tUYLTt-)exm7Hkc@r>EW=8ppNQ=o%Nz! z39RodG3xjg?OH16w+Z(wEj$^FkM>A;$HykYAyWj%j9T%H)7rWJGfUy&$;b-swnkv? zfzNcnm>MQDB)czm_r?5<)R>S&C|mXUkrd5XmX1Yui+xY!&jUXTl0{ilFIHYAhSX)|y!-L)5WM(L6RLj#4fD^3kD@PRI;UZy_NcCl4bpRrS zAr+2>Y(z)8BwQl!=)v^^>j6Ewyyd;$YIfc);U-W#-v5lF8?B*AUCr&Pn>LX6@c8w8 zJF<#{hafZyA_3pIxD4J*U+n!mW8xWP#x={qx%F~Mgl$KQg3WJe1c+PpCf$(~jK^Q- zA~6US0cb#It$e2?9;!h8f$URm!K&@hH_Qrl9Uj6$~VCt&|;Y7mFNu zB9x);+A)CQ?1?AS6N@M;_AMUCY71ksbW$Sw(t-(jT)=19wptWdeEWDjCbh4I=$(@) zV(950O@OSyz>md@T6`cWBXi#zV;S>;8;VJ%RRZ3q;Q~zRi$d`;VL|8lD~0J{+ps2lh#m1ibF`xMlXnpg8(|ROtUWst;o7(!C_|9 z-;@_6nJprCsh#}v@1wG10*+)KV!k)uZpgug1L#P9_Q5iDn+2;i3rA4&7f=AbDr+jC z64RdJZ?*Zk6=oMz`O%29g4e$$%*{q68U@k*Yc*%6)baY8@7VxinZYnPOKHY%;)pCa z2grvno{M@7d0Q!cG|05hs&`xQR4_6R^FJhsveK!BLrQl> z%^_)!DQzj1iG1whwJ|zojay!kRTRX_o=i#@k`ZjuCap@Ybv#N8%18ufl)J zqF^u-zE@U;==%#lAgL7NhoM;9sGw&d+9SrW;s$U$d^`gNgRBFFRQWmTZsouQ!_-RgWj@zSp5N zhkh>kc5>;&=Spk6-%wNPj!UJS5npaZ>m1H93_2RxqrXynA#!#L5qQSz<1`fX?P9YIT|r zJnb~>lKMHAko>Q`BK5*UstR6z+nR#BPHrUUVawRBXZ8e&{lM^r5FgS@1YjT*|0XSC z&{>qRH%pr6Q zJj^rlqLWUx4R2D2E=Mj}miuYOWfS&&g~o^<4388(Y6y<~aSB`er!1(fAqm%E`v#mC1&-+kp<$IBVRQXbT$%0c_ z-vL#6C7A+FX)tMn_BGol(Mzi2Bg#tCRpno4uA$5y65|R3!J(26otCE92)%a2^`?w+ zyd~XFS09CtlzT!B#xjg42#28R2jMvvbI2|qJ4!*vAbvEc%=}EcecbMtvQLs5=GUjlUpK??P*4l znvPnk!aU()``-owe)8_M*f^L140UB3UM-u@P#ajKtX?_vY%cVyk2J%;;Hs$dpn|4y zH{`V##^0cI6fn+?o;7F*2Lp84zZMGZ5uQRVqx$Rn4Bdwma>mdGJ0|ZUkT+rEnAknv z?Tg=)66U}P>8}dXnM5*?SjUyU z9{X@K*v?2BQ6D#D&^ z(IJ{l_B8c*uid)-<%Sl4?UsYx6ya6v29b`h1?pU;<76|0QYT`fSk|e{Pi_E$z z!6slYMjJOYwtGdXeH;9-{{=|i!K)U46?iCHK@QY+Z+bcqGGqFgw0(!LQlQgoW9VP~HZGB^pcgK?c>o6mPqL+jJP4s4;+_di!x<;q7;BxhI-YF9#83>2n(t z!qPzBXv%b~o2en`Pi+xIyuhA1)X9OL)_+?@RcvUZaeH(vu!#z6^T^4LY$o= ztjCKK;N#F&{e|;rpL4JJHpZZ7WS7uU&kxxZ@Cq?0dxa>T#X}RW(N!j5w@-w{;5T2? zSVevCuYT-p<4$xa-|^XR7hz~2{UAkb^8>Ye-@Z&)9vZg0jOcg!tZex1Lp6@A|8VN> z@;i@ydKT5Z{63awzJ1;E-tGPS`tzQ~x2+A|jyH$R&SUU0*`bT<;_I?r=n21$md4BuvPHY7=kSZruK{^WLm zmm;76Wzi`b{M>U5e20Febu#gRHZI$63}2-G{CR24ZL{ooKa4^9Hbn@eLx&4DaEz@U z6b1)ck;%X?uc8r@xV@?bwt+UY(yQYTfhTg=efBGsCD3@tEQJw4_*lRSc{*b!jaJjB znzJkax}1LPwm5kY<1V)IJO^`~xBv9*J|53W6l985o! zrL568sz?mvUtSfm$uBf03Uv#c(!J{_wEbY{tRe5129Jo*B14E%>Pj7isw==NJ5UYo zGiFqaNpRw8c1g^OCr+#1wY66eY1wHbdD}P35EC#k#G|5=-KkDSS0QhplHK_ZZV?8D zadEQvMc`%p>trFS|2R02A&3v2j~X^j;GFaII{F3&rU8N}o9rxGP}Aher(#l|a|x+R zD<9vEPlG?MFv6|zXm*QI@4Ue(Jey~Imi0<;Un3N(nk%jh^E#z z!Tw`oDa9c4pJF8-i$ zL?-x3syf%fWLMehKlAFo=&iYyGK`+%ZaCE#3*@`^Yd&}H>e|wu@7m?7$-M1!Y+Bl8 z9O`x_%H8*_8)H+5scgFa9EI89Yhd44ed|$^HB>LCXy#v|-{H11HTLjy&Qr2-co+mU z@a2oOWb<@1eSlRh7`=S|@&$YPsDX%V1+xj(x*RJZ>r>EJ^Rzr89V-&H8lWPn<*m{U zDtk9OlgS1px?_{vb=#sWiDTYx2TY`Y{0D~;zf}_v=Bwg}rK*oqeQ@P{IYo8~D40P5 z^TSgPF-LE8R!CCb@?*7GpG!^maJ(ySMPO zmNfHLq1QN}8m~WImL*X1J4Q@4-ftrTE&CpJY(?e@z8)*K#R@ib!v-~h1`hpr{rqlZ z4Wouc*>pvrTxO( zr-di&$-dt`0{+AXKF9kW$cT#XBdwJW0&m|9zr#|`g!}KZ^)%~TWLCbtHR-&!Rrd!PRX zsnoc~=bjPy^FMT%F8T@j8Jjod@P^4=)F0kQ>AL%VJm-jb{dRP%Z161j_IPqhb@=rn zqk1*_`R#Z8R!HgFHP=QY)6!HYj-emmjk?Qnu>G>2&ZWo8&Y4Nut9!}U@NhNWoaCk0 zFebOSdk!=AcqyshR`jChrYcu-2zoaT?O4n#)iP~XAoD(rY)v2&VaEO0L{KVZ5(-wn zT?gI795DPXOG(2iWfg9XDto2qJ#Yl@luP*>#k$C0HLgHkeahYY;l7gA_UA((nAhoJm zZQe!%!Gz3;EJBHYk^18loF!;Ns?4bG^}c&Q03QHr``zqQA=)A#`tK)8!N=zd#0t4Y zPb;)I*I#MQl77cY<^$pRza*BbYu6;F_>OAYM9n8tKSb|(pj8`-@;j*Ka1gv zxjFUxdb)aY{L}BSbr|F8eP)K|q7*KyVR&Tdd)_R+Q5D65!CxV@77H45)UZFTw{3m* zF;&xo!=KJstIKJsos115ev&c|kN-W_(Q>tJ^X|2@C{7Bp&L&yAxle{N2OHUtXiFoF zxzdC7gMLq{^Oinf=xO6uxHJF5sgk91gn+>T{G2UfwBsz(vvm*2u2RNY&zGK?4%M@>LzW;c{atz9i(eR17ya^v#O=jeKU zU(bjnB@5Fthc7!D$N=1m*@~2^tgDQ zznE&7vJ#HjFZoSN-?g|zb}D1YncXkHWOw;m`-o;Qige{X8GdVV?ApB7@dKeV^$ghE z9PPTb)aGVpm;d;zX^`o^2u6~Y5890pUfZ3Ok3Mx7t*2~NVLo9wYd3E)QaGyh4^&WM zLBzN0>fgR9*kg!?{3QH5@!F#TBU#ZU(#SUc#-gQp2A9GxiCQPEHW@uFXRA+jI+Pk5 z2MYU})x&)5)CLIKIkb{$87TU5t&r6UP;sy;1!*^$o?|<|PAd2NzNOo%Uf?ysIDa3!(-A8pE`M1Xu`Eb^5opz88s&L$l zI3@$*NC1l&0CGX+Q0wC`9&Q~tD0~60!;4=&XPcw2L&X>*w2I`Q1m~p-oEs$E2x6}* zh*!cwk)72uB9gP*tVr3*o+eJ(KUJL#K+cWv27F-Wg|6?^o@4yl57YcP<(EnhFR!I& zJ-T-**X$FP-1D(fgvR5S#AlPHIa}p|m5_%&Rbx@{=6CojpS>Y!8CFt!T4$8PA7KEo zsh6F4_o5~Cjs7OC{?+n&DrUdGFuxBMM1?aXx4j0;FQ>4eS7FlOMOHN^XZh`)t zwyqo7?grgBrxyg$D%9p!!r`TSCln&~QSeJ|3ETP}JY z`!7beo_AMYACgh!%zLk11t0B}Ov6lbi=}j5I%n)sP^-InWBXiVB|KJ0_)&kFKJ)1f z+)7YDJbSdIG zks_5Pk#lX1ga@R^Z}%lr>{B6o+V<=F*{{0}Cx^-xbIH+TjD3P6JbB89R^8sq_7_@IvYybS}cSq1M6DQ|Lg^0}q+NFK?9)$a{Fbp3_6`Y=_`r1OWC z0)aZwdJX=M{T!_*9D^T$_9KsZ9C^pS!c!Zv(S*@FgKir=`Y+24qHihA`GeZl{tC1x zwb2?Wu;w9VZ9SXhK~k5sCh+IJlEsd)J%#*-VP64T{Y}vt`0$sRUOlJ$bbAI=ho(!H z+X<&7ph;V|go3Tew%1Uf6wYa@s>wKj*P~=|bq23RIFDeveN~Nd*Tvq;Pp>b5+>CZx z8n1J_?jFAPIZnWdl*6+y%UV}JtykxQb>Yf~o1mrpWS<@fTc_a`c2R|g=W@Y6LD5sm zIZ&cK??7VjDM@~}hOG`g$7O#z%twUB$1%fa-`789EAD|*MiZ2KK~H^ zXn852xqLs=AAu*5(^c{75f;uyV`RuYgX`Vg%uPn^i_p^O#6jX-YTBQ>xkbn0^Aj`y zw_;gzJR9E<#rB(;G{9T=$aRLgNa8E0XYo^8D~JN(f1NfJU7PoOX`{Sd5|5W%GdaRJ zFcWa-=5?eFXX=x0GS6J8n>?mC&7jx~Y2+1}4tO?a4!rNZox!Iy<6miY9Wp@5vPt^6 z`=HrtoQFQZ|5x$mse?m+53WH%c1nLrhzoAi#hOHC@6Qg$awa4Clym&xsvrPP)PA;Gj;5RhzwS7J=IDROzhQUd1 zR3LmuX2tdWAPbYhBYW80R-YtfbsBVY20XohA+c|uY7u^Et(lxkc&#MedT(;7*FGagm&||%}OPS#NH6C+naRKO$o!bwF@{M`X9+HM?`6YV%>zTTZ&37(+$3uOO z&f+eTjflgUgiAagi0kLrN9Pd1sGr@lH+3-^C6Z=rfYt58!Uq7mAI1@qrjVSif1 z^sK5;9SyKB-(1q(SoT^@hd(;TU~U+!ALP;X2hgC}nJBZN@C~DcI~6|`T7B-D#Sw}+ zd3}ORhh-0(!dpx19JZ~$s`)c)$+2CA-lLCGXvhNTfq4|%J01!Uvk-0VnGY8ns$@ft z-Z-y`qM|K!I*)#qgFj9r=HhqrqOZD)PLx8HYEb0wFCBI}a!F!JI9`3AKy?&&tX3Pv zP%DvLI<5{IWR0R;3ZIb=6+O!({;g@qtLq!%DkYdYI(Dxlszji_4i#OQ=(hR8BA3hD zJdX^q7TwPOf;T#yH&)=LPWNX^g7!&3nOXMsA4l5HJ~Xz2L-sxOXR8CY*Y%2iz~49L z&FdZh+fEnX4qpdj9&=qEHIqCtL>v85?$966FWqG)hYArdXc*QExPTk23fFC~BZRm_ ze)b2eZI_$(TeU53qNwp2I*-0Xo|nDP{iiO8i3&%)x#~Zq(4g*0USst7J9z3>bx<=~ zI8x2)&O!cjuD%*qejVqxR{9pxgt9%BsDZcgQ!F__8aF_cKiwcK?s#zp#Up-_JHipq zL6Ci;_?36`?H)70V6oimd4=jI zel~pf^o&3G?jkX(D$$F%s3=ttL|Ul2XIBFJ9U%3fG@JSfL5&7NxPJ-0AG`sOT6%=&#yxF?r5 z0ra1=TfG;bwF@3zN7V#UVnct-g5e8Q;qxAG*K9-Z-FkRqT3T~ooR{UH^XgeRJjWQI zDQq57ld+@e@R{0MmVLh>T=(Ddja=<>f)>yn5H3ECG!@GheBr~n%kaAT2DjS)++-P( zO0^9VzcT2W;5TU5;LXADe5bmUZ&Hw~rzomIMoO|XJf!;q-}xS!LA4uMm9hc{^hImJ zvHEtOM~g}J=}_FEa$aV`P7PkmC|ej@)<^zZgtBufAQUNdPsgr=gX4kACWc7haj7%T zq=_CvicTv=&q9{6dy8ujD$po(aFh#**k++xNd9@2{%NJJNwtAj(Ly^U(r7ITJ_`1e zWH2^4j##5ElE9Nl*CaCyQ%ylR=q~pyT^z<{FyJW8_WaurfoD+W<>Fw@+Aq#EheGQ5 zx;jz`IgTI4^}1iI=deW`k)iPWwj=^gau@RIP6et&&0Pn2sRePhqku~G*g+1W5tvNH z8$FHOKNunT9Aq1t4pRDCCV}UsEH34c}OqkS--8Au=Voow!EK%dN-6~$}X;6RdV5%ie9<2)JlE!IgVl;Jm z`03QTd!ED3;>XlfZ<>>KStTMB~8s~4@Oa>ZyX z8=;Uj*G3U&4vo`POtYlm_*;ZtEZ5F2XNT7I&Gfzeli{CSCueVsj$OSMPrWtaN_awA zj7f+{7&`b09mD!jdNj!^o8;|dIwsTfTc_4*4$&~^!$%{dxHFBnerB%bMD8l~<4 zfj73!E7XVANECbPeR9aDtb*VPE$DQ}bev<5VR5-lY0x5!6KO6{skk^ib#M(HNzD(| z&Lw+n+Dxf585u2$@Jgc32S~@uYFd=pas45G*=I;YSYiiSe~$OO(6iVoaSo@H;3Uva zUS7IS!n_*M`0y14ih{z>EZm{oFV(%;x($qUmQ^L{vY>&N^HHH+VSH)idk?_p$r}t$ z_ZaF;>?&2Vba>~NWqfmi!w>ZW(#G@Z1hFDT`S=fNuoBrs%Uk-dJ#_e3G}_c1*has0 z%bX`sg`=iSqH>%AtXN!JS<|5?3F+kcBh4x6NWdqB-*ubpEo zDXyEHe$GyUF!~QQ{Pa0hQ&!Ic7cWu$wz}pCj34xZ{pPfI=9nNI(>S=cH z#ikha{Md3o99QOpb7UBQQ%+~hPu`jxN2z8b_djjSceRmX4&wV=jFQT?#4#+~=z-2( z@}K+s##1P;_DRI=z19vLz|CqAzGpt)jb@KHU1aWF#^2wPOh^(WZG!B1W6jVJ(w7k@ zoS-}8kh<}~GMtWKMPc?)c-UAplALTvOjV1p@8`h_m%u~hnfeirTp-=;nipwC1uayh z8s)}PJgG*w{(Go!G!zYE>Pg6x3etcz1iQ!sM3Rn~ z>w6JxQVpp0+<0daFv%vP7Mm?0egTOO;KcjDnN7lAQZbWydSctO=DpvnxgkFHpqS0( z{HwS5iS}ZM=W844#++bE=H%QduU_t2!JyRlJbmCs=ZnskahXI#@sK5v7Lq<2I7}9U zynV)ykp37jcD3lF6Z5^}7_a|98@Ava^swJjd7h;iQ8mF8oBm{r7roTz@u01d6(}iq1#zd-@|202#RY>y5i>MaHXti zKlOc65qBVORTW`hIzwEQb?H(7_rvd9{Sy!K#MJ2*$_G{nUJxU5f0K&tS4603e4l4t zl5mR%Zo&5=W;f~??G>!Doov$^uEo&Q6;s;t%Kv!u#gD^+Bn!)xcHrkZ zK?G>jZ^Ui?X<~s`Yso!&(hv^YG8r@{FfoE-?BbAsqw5$D_uD(gG&PEPWQGinzrCw% z6@w&1fQhCg>Tp{*JVEksw7pCRz;x)OZzoc47eci((SCaqY2={;^zm9EDF~%IPUXhr z0+cP*pEpy1{Li@j*dA&R*Von7wH8;J{24MhsI2mLUAO(h8;>;1aTzvZ@INzsq|X7} zh2EkQW%2r?GK%s;X!|Gj8BVUXpGxFdXZBuhi{rp=h1loL03B8>*?G8A&5TFumoDep z&nNgVTUS!(DGrq`AfAW@ZlBHq4^Oo(H@u<_A8^=eTYQP_KZ4iz&fU|Qe%ZKu5UBo* zSzXu?L;VZkcgSKn*^x8d!cB&|%{KSmGf9`xk}DR^Mq$Qs<{%rso@|DxD~bI8P^HhwL2k&Dl{w2%_6 zVr4X-?QTEZTpmiw(%l??lg2;KmL%PwV)mjz3M=mlUESfZ*U>ULO%LnCC*V9Nlm2jT z$DZJuJC^kG^tm|sn{8r{4QAOfC2gDdKd8#X>MYV z3Uj8?^Yp?ochRH%dHi5#PY0NvLvd>G{e#(qkxkvfqcrS|h#YX2h)*D1B4b{~%q1!t zROFdKqhbezk9$m@4*w@Riv%Makg_d*r2VJ0K4@H}xfZ;r$r0RXj|^_U0e-q88MbGs z<(oMuM%_r(iJ5vDmu^Nyys&MHi;6SXtvJ95CZmm)hmEm zp~~jWf|aeL+H<2A!e;pf@CIT#=uejIYT^Cg6aFfs1gG##)JyGXc%FKY(4ya$0D5Y%k^EZ&)E6Li(2AX z*P~{dL)VdJfV+b^Z>{0$`IB}OeQl4^#A>hee22gk0if0YuDMo1)M6ZRWGULm(rd^^ zKiAAq+!n;Z{5Ix(ctIb#VBin5ujwG(>!4cG+09!G#=W>+_4>p0W^8wQfvTtN17`S6 zuhk8&UYi}>i{97nG-Imu2=IMt9%I@BKJG5Ba8ex5-+@W!yROdmA+hxAg=bCEM}1}0 z_uVM(uGegX)<9f7hFx!0k~MW$+f3)#4u`Am{4K=4wc3elHyf}TaN#}P$|l@3-j}H( zH~+m1-`%+$b8Si>Nz!j__gWmUkaCVwR#>V5`);B&Y{>x<-*eR6#@bef5qznsmgDAv zHJctyl{?UN@{ZTVTj)}^8O88cM?pyU0v_!vO)iy`aBOjuH#p9XxLe>9$+szZ|Ngk{ zn6GKq?K?T_t2LJwZ(&t1U25o6bTg1uoDL|6E)wp2qs!?^Cp7bd3b*`-@nBN<*3pMKxm$mJxE zhDEu3 zZCtt=>F$=68M;%XyStT6rMrjj?rs4o>28o#It59|c?Zrp{@*Wr$ctp7& zdmF=gum!pBT|61WwmPlpkg?{VkOxnK@|wceAFJKhMp`jpw%E`yjWe7%eb;>WEvgP~ zOx8Y$XZyCu&Dd$W_$IF+>|IO$`oQ_fzwy}M@wEHv%H3?s^HeA0YR4-P6_HZVcK!R8 zDge^hyA_+7mh~IML0YPUR%WM;&c-$k7yd(qw&l4~zSzBKY_pEZ>R*<3QQs}}@`jvu zmrlXA1E&=fH?i*&p;$k%RXW==PR6@p8|^)!W~{(F4QBf;4rgQP?PMw)lu`22`e=9} z0`kPvYuA+OrDnWjwZF~PixSC4W-*H=H!PSxPu4O0tGVfLf9?>)No5VjieC(W%4y>J_nlpNpt58xADAN6%$VtzPB~28xP|feFvM|SY^TVn<#g^4fhO3@*)10?I&H=qNs4~1Z|gp zz~2r_*1&EX8y&X}^X~DOci+Gd!foJ9VetK0^NyZOU%{oO10mR{>9p-v0fzALXRtds zo>2K|V&j&-PUN5sdW?D=}v6KDJn{9lNQ9Vq{FD&f`f8Iz=woBM` znmv=*rn;C0gSYi3spHK*I;Xvh?Y%6Tlc<^~*Q6Tnc?(A(yOfUH>E{Q@O~Wpv#aHV4X_|+_GvZd zA^G#DGx5sI-t?-L>A{6nOd{ZSb^BI~e8uktUoL*$@7&c&$x-h++kgl&r|*V%suw-I z^>oevRD(8aJY|!$`lr7$es#@M|LTe=`+VDV_lA@**YI0!^;pdWNp<*!Z5#FG`Sq7$< z0|t0616*TkYtcuPrwz^ge#n~qkbE{e)sKap;39fCp~sTUu{Mk0=owir6ToDr52ZV=PeTyZmF?nLWwVxhG9c*}37ySLoL;t14R ze2naPE8UfG=s@=2UUEygiBF8(+0a}zdr?~+ftcrH;wT+&;&=Z+W^5;K9oa?ODSzBu zt-T}BZX3x{3Em0#@-=KU1TCQx*#@A*$eQ?b;;0!tV#MFL97mO2CW9wHw2*0~syQ|r zCK%I+4;7;MhxPELu)P$o`6XSt_>q^-e@<0tEWL77&Q_K?WLVGta|!UR3b)j9y5xsa z9Ju7gd^4aDp((FyIHo^34&=oJ;OEJl7H{tTW7}E9<96VC9EzqY}U9STXkg1I0GtbIE3E{BAc? zMb@N<(cw_LGzH0i#S@D#H%cXSEXibVJ&9ZS_Jbd{+FqvQhc8kITzEWOgYOOkANWHY z>wO{DT*qJkoR9v#(Qoa92ne4Qy!RmhBr*NHS%V`%mV({TV;V;PjCE8rWzuhOrTEBA z5(Trcg%wI|-xi_LRFxKxOB%0)iM-`f*~Ae60?!vBT1ta~lFEq)J}nGw(?goU?86jw zbE+h{+fbunFqn}G1m!ZA_PX#~1k-ud38^Z`$`r}L`7;I+s!)-b=h;86Y(Mmo`!A8d zJd2rOodO2_*m|yi{8s9rCEp%X8q+v({07I5IuGs$H8+Pf8*dTbVMGJW52J70(Ds1W zu~TSxRXYtodIKm_AqaqHnuoMM9+WfPJ9B4V!P2~aX}=AE)_51*P!@f4cosOrqO1t< zf^zB2qeK-_8PrZTuaJ73yOuE&iZqBRVi4WJ_gVe*ub=2X%$;bT50^in=E#zUSi}=d z9&+4FaP}yy)htsdkDK-@QCS6=L$x@}=6#TkCp0N}GVP3NS1D~vxwUqEp!iM~O!}s);?;>Oq)?F+_x13z)r<}SxzpS#K4WPKkAK<%N-JPtpc9N)r z3-7LqLo1KCwwQ^SpM3%JTZP9iO2psTOS#NSj|pMe$RmsP+NkrslUK&IrLivXb21Uj zW#f?))gS`!UJxXH(QGz?V-u&0Ok8jP(kh4I;`|XKIy?qWJleZwTuIbtd*>;rWnetf4a zC07^Rz0j}V94!%Z9ljQ0U%X)C%A0sQTuKMTEE=X>bKlZ;CQ=5(w0-YJD$=ANZr5kC zF_dc3=?o@H=EmH)%xt<8a2hku-js&`YhYHj5;qwozDP7^&|hKVJ7R7fBTT^`992UE z;_q4-kolt^&Thm8(*NL(Vng=*0hAf(g#{Id0f+^iccE0q=A-;sWZlh5Y78KIDmb}a zBv}*r3#o47pJMtl`sTGtDixM*%B)tN<>}A4WH&Cp=y2tfXn^z8tG)&6oVDbPh=lGY z>=iy%xT#OpW@`3|ZwJO=Q|o@_VWt&Bx=XsM2rRrmO1E1whs^+cW5fUXO@iVCB@$T2 zASIWWTqdr~dxCWQ2S`&)lT$|#j$+I)PsA-$d@pRobx~ep0<9JRv4MLdS$L%inix^g zQ4YR(Ry+!*-d22u*vjTAM#vmXC(A~)jwXzQ22y7fYzIePp@VwzdE_wUiLAqSU)@Ak zCZMz+Xwg6I`n{n2pBK=QF#OvlLB3C?2+|UzC+K%ihV{I9&5Wq6XnS*RKN_R0GzpwB zEy8%j&TVW@$cuWWa`qaTYdaop_}~Y_6#fN&z4uVQ^2$Dmbnc}M zg~cOp$hXkIhNYrY$Z!t2qG;=#Q4^0q?m^pQiK`3m{-4d0%&6vf|2lg}9g|fyCu=5G zujI$;C-O#$G7HD3f+c8>id%f0ig!RdsmWvfmu!bFmx_9Fv%PSjW^)}YJ4r&^){CMX zmDK3Vz=87XU+1+hNys{xX!dn=1lCx>d{d{W+7ogOK%aSxJ@z8*Ma1EWI9xc+ViQXp zzVReGtbH}wy#LvuR$_QP5R8#=$e_heaE2Sr3c#9_17Y!$$VHN%Hw7+E z2eRXQcS*?CbSUPzm#HA8_?N3;_MUMsn*!qlR%-DShV>}SLzgMcxN#K1PLDXCL3vNML7 z`@@RCvQRaQ{f?W)9c}X#@)frwo>O_)>ZT0V<&0kWj@f?_HzTl!IDNa*sg;hXtv$td zNBDpv4%q*#P;XdR4vi!!@%V;?#it%<;)X3TI417d-roDJQC{f82`9!2aRPNQ`6MP_ z1QyhN>J?q%AJ5nMOLOw`x9P!R|H35*tP-n6Ugaz9*pXj;sph=#Xi1z;NRYi>Pw|&6 zJB9LX=k^E>OwyB4$fV;<4%f*^Pd;Rcl(^rcCwu+hg9NQ=)Hn9htcWL4)x(IdUy1vG zL%qmMOF6{@MkM$u^>u9G(#4_eiCV4N;4Pc6f3)f_y3CC~sE?r~LxJugfSi|mdxBI6 z+MuPx@j`C6QA>oNPsh9ms+3&QOHoS%jOhh-1z`r-iLeqM_d^EtrtHo-tMN9os#Lu& z4}ZfClKuTQPfCmi_q&f>u;LnRTDOC03?g(ZqNK4Pw3#m)mAqkG2P_#FOa$|pJlC-5 zGiOQ)g_Y9cu>WpX6bfH+Z5-g*yf&q)GP@N_2N{$rcOY$}NmU#txr+G3Ii;l+AA)HX zrL@%-wZ(#{B%fcFWci76afiZx-^4Kj(K5s7kus4kD+19UD_5bA^IxaHCg5Dms|593 zrUlrmPA4fXL^?iZ?pF;e->iHmm6l|z zp*hnN^qiuSZ!}yqw={CdwpY5;OeViMp2`n_(-2>YqnfzQ$$IV6v!~`+3ao zlZd-zR+85~$NHCdv%P?|aXNUO@^v8gR#4ci?D&$IQ2;e*9BLgri;Ra-b|p6BwNy95 zh2-Iy@yD*sN)Nv(%QVD|Fk!~Y#TQ~ReMV2glxQ}7WwRnHmh2!YjL=x3$h*^;zZt66 zBx??iN&FGP2H^&73q>(R@32JDuq8BzvTV4rOvI{;jq%*&{`Z9tTi5ozpFV;}@r=h# zAJ>DZOq2>nPr-Kv&4sS=AP2>)?kB`@tB*Ubz2=-d{$dMi96ka!{{PV>(qD zW28*LxJ5l`b?{?=zC&?Tr0JKrCrjAwM=b$C^njVh#%M~(NSEusp`NlO{+N8qi1esWACXFM~TFiR@SvshEIa32cVvxTs zcPSNtuSgz5#y=o~X^8fBXgI`E7(^Agqp;SaTczyEk89ccBU1yO^$8ow>YjuLEn3Kp*y zwqnIh=$MFt963yc4k*>!vd5X~&^&@n8naDRMoaY7I_q{AC}x#(OB5Emj`~fg|8k}f z-pBZM11S=q4XkB-O1%@uk)a+KI>31v{@*j08P?u_b7jf38mK=ZM#G5N2Gg_$!^_3=3&jy*-iudqY)1U*pPRtibRyfm zAMi9Lwa%ol-wpjx{Mz!_`O5daM$Zxv;qq=U-Lt$X)PJ*UathE-;5eE@F_wQ@CIa>5 zH)4&6Vj(a(?#!cEyh>xiXp)^X4)o?oJWjf-302b>gjgc~-N0tCN_)~H(1aq6$ZCwM z+_}>&r?;JDYsL}St*qa(=b?sUUWeVXR2=axyDehg@qh97BsTQ)kB`yOqOmN4fN|O) z^vi@%!KcR1Oj4?ggedjeX1gh@ujY{w(y}pM5b@5HZG6?xlONnKLo;JE#_Ylr6In8N zc5f8`wEu11>yXsEpLIZK&%u^S;2IoG5P@j3+&qm`;`r}V# z&tGw*3`Lq%MZNAM#C%o60&<7|t(QYsDQleWzQEJNoqYAAG3`ePU+qv}7-oc234mQA zFwSwT7l&|6OCJLRm>G8s%qkwva*VhhzSM@U*`1M z5t)ya=8S_;6c=!6MM_W~{i^UQ%tOpgCd%29+BVey=Io1rSor*VEM80jYOjuyLlvy2_9s@@Z2Eh@t6_)vHP7t&x-%Yc3e88 zGC&NPqbVkAd~`vIw?6BuAp;$*lYdRiA0_y=D)9|l{JV?5lfu`#M&JZ z&^H-abL3m-4$gy>vuU@QJu7N1wFr<1KfyFwv!1eSG)&B=L1!gRKlxc_uQpwJ0~sof zPW&9zkiV+m9v&E$n4a0Zd2?262Zscm{v{9Dd) zyVu`&xWgLiql3zgskx8ROkvyKL*mEFQjrOSLm(svp_eNl2mEZbc=a=vaCWH?N;amG zK-r?=O-GU{ppx=56ubXtrfp>X;2rrAp@}jHdPE$@VZeV|XNlZL{ebJq_A~lN1=z)} zU`=h}z7&1lVY{Uav*i_+h5ybaWExFUe@o_2NY{Q{39DhVXoCiU-=XSw&aE+)f2@j!jpCDtdzM2|WKZ z&wrx&-rk-o8tuyQo1Bn;Zj@4)>w9r}~csl;k zEx~@18xqA{?59wLK6jf@`vB2hvP+`Y>B!QsSq*g5xxvIq7<61ZK{>ebCJJpk+q0z) zGl$L#zzj%#V(Ts)n)&GOXD}0HPZ3Y9PwtlHdWWh5Q}`8JutuTPak>4KKosQ7M`)L| zt)d(szU+W?f(_8ZDVZlO!>upo1xdk=F2@Q#H&|YDw{a@mqk&y)LcG$f89Q`vgCB{c zTrx8=`wmJrai@!j2177;LE3)D}YEla!`HNu6I-kwZiyB0tcj=xA6W$!goO2guKV%f%E!}3(#bV zn&3>^0_X(+EWI$%2&NDo_%sgk&97Hs_|=XyCBONpb@gi793323(>j}1nWr&Z5;B+? zpkHxi9LJKt<)bI`yM*;Cw8tk#EUm$`{3nbL^Me8(k*>0+zYkn(=5<9al z*}k%@Iv-(O=kzfzm&H8;jZ@reyU}QngmRnjrOT6RmgTlxBv)?b-Y+#!E(dNT%o|~w zzJ6EF6sikrH?)&){(F#TS+|-`>f8RvF)l=K>K_|;N6sSf7c+H?K~~|5-uV^WE0EMO zbC(;iL>f>5ODoe;tH|ulw!1DyONmkqupkRq4I9h z(Yz288@?+=ZvKBDLmX2gRb=VmfinOMwWVg1>Da5XD%h*`&$I$b_6XlnQA*$DtJB_7 z=N7#xtP%5L+(|&N{*Z{4gDd0?X?F!YtAn6eJk}juE+g{1an~+0NNEle37QDJ*p$eO zK5m}>ka{8s5m1l?l+RzghH-fq-X#kU`o}N8|IW59`7d$}k>xi53rr-E?0z!OO58uy zaB6U{bMkY|yf1?ZII@Yxz-WdxZxw zg1@bDXF2hVy8FHjx|OV<_?%U>4V}BNXyvMd9-JYI^>sc-tRZogIrYsBL!xQ z!Dz78lD@~*Z1B(bSC>Ho(7n)=M9I_;P3hC~bmvAjbjNMsQ6!(3-UP?Lo=C&h7=nS( z6~Y&LyAg~Ibn&e5$_8#EO;+U0vKM3YSR%*~ga2|_;#S^yfo~FY3dtmzsb} zd!7gj@<99;3vNU>+RzLgORN&sRP*<7u7h748kH2xD;1I}>>8R_E*I)(MW4LoB^||v zvU^_83J(y2HG@xOO+rigZqVj61Fg`Ea{xTLV4^iM;KcP}tsX;FF_C>Nf^d_{OIHW%dZ{=@~n4H$$s zhj=|QNRi25fgqd`$&qq3&Co3>Vq-PyQlU{#PgU5zS;&x3o{H8q;HNyAaupJj)>+}3 z)0_GGuIic!Gya~`K*}P6{e22~7*g`uXpMyxqEn+7Y^%XzN(=ft1PCW4^m(xc7f<0! ziHsfScsUCcUU|n}#a$?w*K(k?t;gAx+zWK`F`ihPh2Sa}qNzy~G|-f6uVO`A*N$V< zj)TInv)BSlz<)FMC3+_lNlxM*2(aci9xmV$7-N@R))!B{&k7xDjE-=#5$iBLUnSVW zzjV@Uli;_j2yHr^j;?Hz0b&*pai5!7bwu}ka znrY2}Bn;KuFK(wM;#Wz_=OHH?Y5AcT^zRmgww2AFfKEeym&-9RWgCMYBftPbsMuVr zNuU#K`3Xtaxv?!@NY1!G6^6DtpOJbQqHQd+!f?#hfy$^^wzj8ic1YiU_WAt$hju_{ z^Ch!$$=NKih$DnjOSx_x#!yuxGy%#5I9h(7NyHsRu!P0^=rXioOT|po%AC@|bzp1x z^)HYlZY8o4oZ>gw=>;=^0Z=cfT8SrC7}dmH>vv!mdyLbfhm~a2t0PvMc&(Ib)e@M- zC@4LocLHguys%*rVn*b~CD|@Z)mb88s3rnSk?*|;oRlwm7V1{fBf}7J5ae!gvPg9r zSww*4M;?68b~)Huf5V3m)^P_ZE-7Ss06A^y%rV@#uYKIm5$+Xo{Q7{1Y{_hfwMEX5 zXu5rZD{(ZehN`p#DJ2=S9E@EgrqlQ5BhKHHQv=d&j_KNK5EWZV{ZyGnSg@VE>?12n z+E73PP!K7Y?d8p52Rd*xmjEcIgp-D5PIP~ATloGx-@K)Vc*FyH6;P@;%3Vdf0nnnE z*vDGX%=45#<@ocGt3gI1)@$fi!tY9H8!F=fat`lqpaSK@X|rDQ!lz-2UB6^rL}D?? zsh_J@1B^lDKaYkGGLF|IYPb{%sAuv!-E^YTIaCfmsh#U!qH*R2780HLZ3PnkFN8kD zzoxGAxK&vDh?d>hH7#V+95z*%ft*=zK?zi4vJB3#vrG9i+zek{rcPrjIhYLT0?|BY zS_DHFpIx2Qnt1HuYuz4)&nM<5&}ES3X-yiXDj(w;#OLxT1F>B{2DM?f(}h?eGuyZn z7rVAnvI;D*{R=#U+%X9Yz21hCA&{~&G^o^0-8`yfG**xPd?)37Mr&&3 zm#dHnGiWp(e%bOg&nIw5R2t_A&5QgWMoMH5Fy-uFm)ITP>K)t->Qg5yEEHDPY&dy8 z6o_wm;i|;7oleFfXErq!Kb_BP*Ur?yqXPdo!&ssZK#2xQoM=IqiIf0dZh4xHtypuy zq)xZtb@mvg4Q`;)K;o@Gdi0mo(kymo30?dqe5s{!(@Q&g%JGkh1r+}t?UZ8}0wYwU zNR=b<99@-oJgTe;hW7326x&hfM&`_RRmbrQWeDcAZ_J_*?RLPbVQp^@KZSd zi&7^8?br-urHquF;Mk@pH_-Zm--yyY6x`bo9^4az33VI%c`4vRfDNF*J(o(dwAtdm z-hzzsUv6XW-0#{A_My^z_T?)Tt6r~g7QqT0xn|S$ zW|2${X4N1)ZyI>h>$@EY-nMF^PqY==kmidWaWf_i#8U(Rl87?|LNj~(N)Om1jLt4C zJ^Yv$+BuFM?L-IEJa0^ef{q~|p|{Gre05=Z54i8Oi7E^p7X`gd66g5;+&2h)oh~Vq z=2I34PB|>r-VOvIT_Ie!qvz&hrYq`}ZN+g_$Ql23GxDNWGaE!$#*7MU*-)if?X z&$jHA`i$j$j!}cqxTqTvj#eJt$t{dURc;n`{Fa~h>kH6?W{jlZ*~)v(HW%wuOoJidE|<`p5!-(8v{V+#tFXE<1X{ zq&_x!A^6IRyp=O0J5(Nlz~bs%1~g}bF9Li>u5Lqo$!!$s!cMR&Lj8(l6gwfdEH zFh?9Gqj=&nd7I!6B1egA>N2|$X@Qf)ml=#d(KZCVBC3p(gYaGRK_n=5N}&i}3=5pC z(c$9S>S5oLy8JMrz_8ogm|8EL#;+ClqT$5R_%&J}E=-%8*NShYMe!D#bC+jiE}HA7UcRU_KWA%Jokvn(~ye z$0F)Gh}5TGk}`@jdl+1F1s0d<{OA+8A5=RpR~d0KUuzQuLh6;5s|T%p3A)m)0)Yo_ z#h|II;|kh=ui-38a4}JtS?Ljl^zY%UJnz)TSorzr)}k5f9X2x$0Cv#-k45+7*AoF_ z;WwA|dRUYbuU%rR?`&Oj1kJwiP{lcmg+d-C`UUeC2(*A*9{4dB0X z-G9+%oaw$`{5rKb7(OAj-YSY0Nd1)AS7gr4CBlkPL27am>-ji+=oYnA=K5ygY3Qim zS_h@i^I`)wazrMu;O8fLSC{{oRuG6|07sO@EEkhFqB4&OkL#JnR_{7Ek1iBWAY#qv z>XwELMw>{oWTjq0EcroawS%sgto% zWIy#k!}L|)X>|Aibc^$DF=5T4!NkQ`;LNv_l_>NO77+E9>H>Ig?xzgZx0;iGKM!R~ zC_7$1yt?}kj>=jLgRP+1o}?#O8pY4tt@24Y_>N3Fr5)4+GUsOC@(V09b1~WzQ!YJo zZjLQmD`d)6g!DR|LtL1QVg$P*(-_wngbH1P zMU0yJ(@0raI%+-9eiTQ7S!q6}i%}uAHq@OA1hnzDgBeB^9g`)p0WNSh4LiLH4BgyJ zXQXoT|MO&cj2&1m5!Mzw2S1#dZGjMB5xOn%Zk(V;r?@$dHIPwPHv~o927=HPd4X<1 z&+trR`RgP%oto|gI_gztKeoZo@2>I`|7-C9GCVt~BV|L}X`s&J_ zRv}uvqj?_}$kJ~>p`v++D$5J)SPq+1R!TzT$uW9)rmdb20=rcsce2EQ(C%koLuW|E zhJJTLN<8$`VHgs#+U2?TSq_nhiD{ueRe=X`8sUMPrb*oDrSOCW=!#z(prX-j<{0y1 zV&k|3xyAdD^Q@)Q9{(l`$K=YOL+(L^yAeWcOUO;4oT2qkmp!MD&~nF&=zNX3smZ`) zit`Vwi9#nTwcSegfMu2+HNb>E^&D4-RdNvOx%ZFk^Z0RMIsHT=_x?`^f=|&3(&!*m zkCNII9|7cKCPv9hOsj*<&HhvTaHn*;|Lz zk2Qwg1?g_!Pd9DyDQx4_7n|~La;$ILYka!(Tb*b>f8Lp2TpiDNi{IkP@3}Ld({}1} z)BY>_FY=TC@zhmhsR_wapox*~F@s1jo{xJL?y@}VnM+C` zV>|8e{;r)>9jzgg?X~q#>>pMsL^SndAM4MP zGnb7dNtwiBD3s|T@{&JO^WOQrPz~&T!$0*lpw4{_@0ZM$D{4A;k6w8~*nj*h54rr@ z%PfRHmx*Vsok((Y0n)gDX6M0Ot@uhZfm6^twYD(po6gIGq>H1FM^?p_(Udn3GTd{< z6ho9_UeP@r*H{~Bq8X?8dH77JKvM3s_S-&FFwg!5#U!ayLzPbOQ`T-0kOJpk`nTJc zE62Ph>OKJ-u2H|MJ!@qY1g;ns{*pkTr)pW5i(rZwV27@q}ty` zcIGs~;bqq`Ep>7iS_HI^mToBtsY*(KUAO?QQ*=sVO!_c_sw7Q=`!erMu1}uyj&6-% z&LXJbjr2t+L&`6T? zZ+dy%XiVdHc%fFIu-CGohMnuhuDvPErX83FP14=BqL1(DgDP%TRUcWM-lt*(%zCF` zelzU4oBeg^cFRour~MZu*4Be*4vUkfdll+cV%NXpuk1!sZGB9}m3oBKCHu1mq%7LS zvRsvypvKbjV=yfHC+96Fj!J-(;_C)=wsX5M^BqheoiA(2Bk?dt&yArMhOo51C%zrB z6pL12KMk?V@tadQ9qVc(vRQRWkld4Em;T(w?0UL#Chi#rZ-2eHA9#9Y6{yZSFy4 zWuhaL`Np?3;K*SocSG$QD5t@qo577uzIY<6Q!|7JGd-D;xRn!^xRVWsmQWJn__Ub| z+H(~Z%L2*z57ma?R?^+p zGzikkH<#_n<@VvflqBJPZ^YM^-YY69WXok?LS<5bSo7VW^$cx-zI?6JLK|>wytSS; z+X|Z%N1BLgk_gGGafy%2)6G&#n4b}m*L*GUzClcyG4L-?9rX_gD*rBn_S{&%QH(lk zrx&BaZe;xKO_=k21K=n^O-I?60C$ zzv|w3-(i!sw`gV=7Pa`yWwTj^(1HT3&er<|g?}?ACG0~GkLE5USGzy2A@fzi-A|t( z;KtR2t_!#pSUc5g>Fc9g{LjbPw)I5Z3{cKsgz(-2NCbh9$Q;o+0ydQUg>B-q&|R2a*8(wgG@ zyU+6Ts363Km(h50x$|MAiDjZ2V!pHFx4&q}x%Y9SE4IBq5Wc-WuKPzFcZwxekArA{ zl4Ci~Py;u!HHJ%YAg+-*q!>kGoV49Eukxb-hh_qS@I%7J1bS>ClYf&yM1={}0c%f2 zXL7xmDiTmgY#tv%K@fRnpM@maMoeHN#T*Vxdq$ZJ0n@d7Ds`k?1g9C2pN>vtQx_T6fxl?;7jj@ zEA2ji3Mns+wn@SxSHSI>t>KDRsM)T-HE|cfJBAI}v3b~S@#+mgrc?WMzTse-Y0(L* zc5%x)fa2i;=C+66{ri-we;Pm}972l_@KY{ewAZXw{SMg9JGa1Y0kC_$=4RB@ovU#A zwO1g@$+xP;*bxh4W$S zgT|ivU17bRJ=o09KyM2XM`8wz6jzXjzi@4Ll_TChfA%yhyWsGoh4f`>d&Zj9+^qYc zNp_Z3Z$V}#U<5HOSA`}u>Vq=9tB;@DB1*a>w5d?kHfREWrr#`Fq_4Oj3DyTX$ue?LtBwV+$pB;{f71xQi^SZ^LD1-ZPA`c#)F%O%~91+DPu-rU5(I$+6iyM*m%=h#Y+=(rRvifW8 zr^aT)FIie#q!dIThvSaqqyjTX;=0oz>^G3O4DVAmr~IJ@-#nba=RnVX50L;T!r7kk zEj?uZ=KJF3+vHI6=ZgX;^`B0AbQq@&8lk;bp>E3%g@ zd^EwOF2ayFhR~0Rz=c^wb!F2c6q5PI#ZPZM?RCNqFs6ducQ117Nj9gC zqu?>&$WuT5{5locgAHqVzx#+5&?1yX`gV4Ub|uM+d4}Bjs0V>8?9)Fpnok`;igSnk zpRQ^!T2npIUFLw~w=J-W<>x`3!qDH*^^ibw%LO{7b2hQN*PF{svsH>H4YV%M3_WSn zj74F=#XhGxv+SUnU7wbp@(@wdzanT8fjxZWm#V;VbI2S3uvSbzVGFsGSq%g zwTQB+bH1%4q%-BZWOzi?Na^zrgdACooLV{vg-KoCbjYe4Z*^iGy4KAI^lrQBzfEFO zZg9~>2Ew%dcC*iP$U-#ugxp$dGlyYFyl?sUbn%^f-8IT>Pk;QoK_~xEGu|C>H;iLPWC} zH~pA=dsOdLD6H~F54mmj_Mb8j_tfW+>;vaYSx9N%4Or`vWbukj4<+5x7~E$ac%xy6 zyErR3RyNb9`-s=-;M_EK!3@!sV@dBJ{8!%v2=%WO`rQ^^QFS^cDp1jxKt#>Sx@blr zl$Q2>b{b5HpX={j(?2n_s%dxoV15rlHXVMT1W1_)Ce3~WQZi*p4yky71WnW&vIuWB z+{t|m2s87tg9t|YYoB(_vaF-y$()z4GYShD*dS(L^~az@KCcAD}n?G@~jsYxn4WE zoN|)uu6bBo10U^jz;4agJ5{dj79QCN`Q$?lr|AiVVTZV=SioLrt;4#cV=_xZ#_7b3 z`*73sJ~erUo@NA}I8Cnv2^H0w=CVHmFVUVdyb!EZFXWThexA!~d<_>XOzVMDg`vy} z4a2H`a#?H9NEXJVzW+7b$L-?A#my9~R1)qG1yQX%%RNo=hc`tmWoqyc!_0~|)?2gn ziklJ&xMnsABvmRy7>0-A@z~blg?ka#l0Bjpv83F9cOF^DL63HI?oid4zp zb_sxKNQkVaCWJi!wgk{1xGqI}imWrZqnceN!fq*lzc(xi6p>gsxVt)<=LSeQIluvu zsXn+d)70oRQUI=P8Rd%>7bs`c$v>S@PXk;Y_k>T$U|Ku-{4ecPyFy+*XdKegB-Q}# z>USpj(&*fWld3Rlq;El<)pOS}VALes762W|ciQqha%(}HnnPS}Lrb01QAjCC!ux#K zD{T7*_0B1EO?dtgjVUj~hrUaJGOJYE;DY@y{hCpPI+^8tJc)WAJi2nDU`m3J4-Y%i zNwd$wK~N7Sr99Twd4n*6ZwnR}a#(aP9F<}{YMc#0IK&%J!&HnSYYRiEk^8=HE*?M>^x`L-Cbkz zN?Jv)SaGzepA5RaFZUq)h@E7XVv6nODC6`b>_vYToH0B~GpG*KSg$7pcdfkzfC!CB z7pq=0);;L4#|uq$xiTdCf|~8-;)F{idBmcFN42KFHMeOZ-Az}eVM}1Al%^f&$glJ` zgHIy+ZdtR!+|cu+B;iSh)A=;IqD3SUGqvE^fQrKi z$oz0;^vL!ay|kp8RxkvdS8`(mL5|mVNRvN(KYn=5aM$Ge_8)zcVR1~q%td{d)c=Um^uofP*NGJD*(|ANPl;R0FHZ`x@cPb7VYRRUtYf1O(dJ=Z4(Q z_tH%YAN~DRDymGO(GnQ=gzgb#qSOw`(WtubsSUWQWl&TBIZ!IPlK9Mxk9CP!QTan< z73(YA7LB6Pzfcl{hhk*90** zX>PTWlq}?SVGMbSZ9OCy-U{A8+}B3vZyZfz(4uJdv;iX|dMKNhm|I;GCxYPKuJ2zm z&mdV7Kiiu@g-o4IzdFx~t=rYZ)BDr=+V;yQ`CkJo9|mplV()nveZaCUTuuUKsbM%< zNt(XEC5xt0NK4}SwnlTb8J(b&P1xmX1tN@sytuFK)2JBUw{J}x!diK_wVcCF!Ibdt z(`noj>(A-zlZX`E5cJv9VPu;FC`S$Zn9Jhi@JRDKuHY6tSVhih5Sl5^iP5P zaHT4%Npi~koQ9lHy#Am5`@1EQBh(w`3rIPzKz!d1<>+hK{+wXys^og8u00kMV`P^Zr7P;cmrSIKU7?;9V&7z?2echPHo~#fD z^?|fA3T2>%9%|;7i+JpI}K_PV}?i>I)ztu<#NMz0%kXrGc*{*B*u<<*EAp_X-VJy^yl=97Q zR+7w5a~!u>Y3(m`BkNPmGTwhWxnT~Cx}lIZ;X5F$B<;=hl~Tv8AoOG z?oC4yseh~3Z^7=jnzU$+kg(vU!B2yS!4Ztugq7+ne*enm_2Cb8Vp$y{6OuC9f(0k7 zd4UZZJ4ovs>tAQKWcww8!&<|o!Pxd{B?*_J{$v%IH$nV;kxo;m` zbG@Ay5$P%uew!Y!tkShzIgwiQ>2>y>v69Ve2`bq_5G+T`7z7o^3RI zODgJm^5I8LyY1ro$J5GYRvy;s%88!^6`f(?qSpw~56*j<#gP{xGzA8ptiuxFT)7=W z+XRC5kHYSgkNbnayx3~lM)hyI5$GNh4pcn!?idLf>%STlEWful-p6M(ckCIZ0>mt$qF-3cc#~GKX&RTV+v1W`krhK(I}KH^I>hhj!mBr$NZa{)l%qDW@48Jr=NDg%nxM!) z{4-`wX3_}os^ypJnOR@i4;pNLtpXxU5z(5))S5^y z^F6Vv+|c|(b!0{x`;b@4SWx*wBlW4lDmw)pnv#}UL6X_nFu<|lO)Zb8ua=Njb4o=Q zMjZp-pM-E*21?cc9W+AF6IVc>7_;9Wf%ivY`0^$7!);Y49eV~4SOt? z%=Lt(a1kp$~i%ILe7~Ip4{Zz!-=6N*2p6LMegv<$J zoorBc`bfr(`MHki!UDzDUSr}7U|!vnB2@EWx%RQSGY zv@2!-RQRa5oh#a1{`>*^6x58$Cs4z;Z)O~2rVO+5 z9Qkm=DqV*Lqfy3Z3oWgPQH>#%Q*fS>zgJO&tDn1ov1*d-|4I?In?bIHAY3=E9P+Ob z@}j&U3WEw58@PCu6Q;6!3g=a2$a&H4hF?vq%=6+q=4!12 z+3(NT5n?YHEQ+)4B;zN8-F%1V@W0G>qD6VD zCO0~+1yKAdf3-k z8-k#&Lj0t_|6#zOL5S8itZV^^m#X_BhhwR^9Z{||ks0U9N5*=LNK3DV(tI$R#pBKb zVgjrx{43i?DLKe4{3ngGfdVzJ4>zlyR5Y@N+tzDo&IDpyImcXENzlcwlPu2fLyDvc z`bq+cv>ztVB-jI7<^?^condMOOy)-7QiIO~j&fx+on^e_U9o0UL zpB#2i4;UJ`DCT00!M5=~3Kio#2ipy}T)aB}G}6l1zQZWfVuYfIL-K;?3j6s7iz%$K z{kLEB=le|;VjuT1_M@?iN^AbT?l4L7JGo&#l?KWA?{JFgNvye!M*efE7ChAVOsQ&! znpzYtW}_N$&dNDc>#F_Jwj1V;O`uL#w9-F68OiY(^U+BSQY&h&x*An$+Y!okZcgx!G1R~Kz<`uh#>{{{C0F@Xta;=sB)Wnt|z_07%`At_Pb02f0?B) z3>SWcJ;;q#sL&etBgPi_k^6U} z#2Df5LA8>~s`e?vzbf(HA)Zf%b_xdPW1kDcGJP>F$qiUCXTKJd6m5JV z|2FIghW|>MSn^H`m&hrX)B00nuA{q3Z%!DbLFh zNtJ0;%@NLWsSsW7lwd|2OmV4xn%|xiR@(UWKUy`JoOE7XB~sdP#g)O0_>mUT8V5Tt z@S$)~5l073x=c%AwDBzd$mH16W2drS9*gbA+-TrC#E80l*hLlQocI^K6AqO}6iUb_ zo%p%2V5YS1{gts{f!d1d{XOG7$&r&eS1{3dO|JXhCuy^!2Xa%6IR-`Wn}X~-rWEl1 z)8G>w3v|R)HbOkgqRd$P&zH z^Qbueov<4551SV$XF{Ufr?l(2!rrtbkLb(u$UH+i58~qig%nD>`EEB<;6QxE-xbmrUfCm>9O5MYUHceC5QKfvJ693rxVm6q7B=F$ zrDOVuULI?S0;ZS!`zTU$j;i#^R0HZe$nHnybXuvgD1_fp0(bqG`L=foOzS7r;Czg5QcfP_;l@u0zbkoXa6Z_kD}iClb*|(QxyE~ zM_>|o9QBKQ0Kv>-2UEftG~tAt@6%_K1b<*tW8oqh{pgPK*2Wiln}oeG4#9^j~jJS_7`WP5qbZDA@A+Rto%pfpr?)1RIQBRD3 z(Y*S-uv?95D8Ni7p(9}VrV1_nGZpK9s(h@E@H*&u*g%t9W9st~jmp+YK~o0#SNrtP zRSMG>|M48fFB_ZP)jhnkmAlFiKI zj&Sxn5^LmBiR< z8l6uhB&^03UD9s;BeT2lZlp4`eu>##So@wb6`U4&CdSYRMQmqwh6#-gJP%D06ly;ZQTKqGeiQB$JI zy)((@@4)jdlgt8#S3*Qu`Kuy@#X03`f+yg^A^AIM7rK$};`%80EJGYs`dz1M?Jrl0 z_bDv8jw!7Au5SAG{$ADR4-KDIB3Pk)KKof-E26M@Gj=T_j3X5aO0b8aO9N-KUhpet zn7SRbYobGrJAZV&wxitblD+E52NkNaAJ016T;znBXW8eyGU`39_QwAV?2fv@cv9}< zS+pFJ5vRpm90sD^Rn^BRA z-whm>DKk4P?S|yBz`#YAKCW0VRrdd?%j zgTB?a3_DMef`woGGtI9dqn8I5&CAU1e3FNSHn?_B=-x{53=6CGhZomMK5|l zn6PcADzxXm)b7dQ>FN5A|5~pld9C%L@dN@35fq0^BOkzN2I#Ol3aNpyDF;>DVJxyO zyB54r0go^$u~REY!6ny*uk5FGvuj@Hu<4@DcE&{=G4!vu7FQmQBl!j|q@`T_ewC() z%$~{oyX1#b0-D-d5}0-PBLyD+H(2WVlcfN57{2^Ub1eWZ3SIOBL4FxOe8sJXy}6X6 zZ;s|^%$AG$8~-Eh;QoiXt>G`SCqPh<^*MQ1zXfho!ztmF;hu^nI@e)Iq`~XxrHHMB zkHxq|S6Wy3EdIET(;St;TV*{XSWRH!EBWF3cr^2M=f4)00xcZoq>MNpbfM2xRA=Zr zgwXP&T;*80Y0)81oWMrH2BDXsLGwQVgU%~hnkd-!dfPHxCs4ggCoFsSp}odYqrKsQ zxi2!vO33N&NOkLmFQfvpIO!w!f_ti=OQo(J&D)~JrYyPab^GWyaa6KN;?6R}DUvsQ zfKM9)q}|e)mrMHRf&wsl#fypbp=aVplqGVkseCZdkUdp^+`rz{-Z*Y7yeE^;{-92$ ziIrP0;5mWwnLpeL#g?ybGykpGN zKp}iWJ8K_FWZ1bSk+Nts&y7Rqx+`g-Xv){|LuTvJDy~pb?!QzimUpiAcld?MLF+TIBNcob}15gV`_2J zFf=|QBcrYtpx&ZznL{c0GZ9{P7>D4Sv#Zdr zIL`W48dnB)*A^(3Jz+tL_TMT_PfGWOCP_-;%zB()WURjcH;@3!PwFL<0!h3K=yDrW zaG8@kw%5(cw6+Z8i*hwA}%8k%RZqZa& z^Gd-9i|fUXCEL5)z%%O|OYnGz4S^To)KJI{;wJOMqm6iBQOfLZ!3ij8i&jhM6Sl!l z=;k1(^lVEqNeLkc0#X@KKVFVV6_xayYUEx8VmVItMMn6gbGRq-3SpHlUd(|yE&XJp zV$^=0eYOAo`L6qQoz3v`X(U3u zX8wuCF~0AEWaU2)B$fnHnK`F+t6e8YIw){h`d~5Zkt*#-5+CnqktV%TC#~m=Kp4g* z0|XVU;!=R$%Dh@Fqce>2inA$2YLgJkE<|69aY?^7JK5$rDbMN&k7+nxSSOLn8ZAa93PN4p{F`Sav0>nngCrFL$ALE+>-38bjfO`s{=8iNO9 z)&g>u>d9q2%o7){WGlz1Lj6^}+AMaarp9r)C{!p;;9?lk+?=+(EX z6f01bDrlT%@Sp;u+xF7<=%5FB7Pn{2{wn*J4;uA|-o1XDir!5Y6kTd`^})4~JzHA7 zX$FGagRLd3;YFPda#U1YEx-5|5E(H@F<6p18am7FDTGLz02NHbcQgpb337i<=bso3 z!6!R-Xnf*U08(`v$I694tf~8nG@1UbNP|%Tq`r~uIVqz33MvHdbroUWX)GK664~W@ za~>ONWXG_-i_%=c_6QWws=I{k?(v?;|!NVs9T_j<)ieW zuk8Ehq=Gq&s!RqJgvup&1c;H#5*ZPT^@g4wV=D2CxbY2$u)_&Hgy~0R|D~w3>T7fq zK$fszY>cc^0;#=+KaJ3cay-%L^=vDB6Vn9(wt|UJ;x-;jB8XzQO*rnelG5hG%ZnA6 z_{edte1^Nc{@+;6Kf(2d4G378`j$w?mRz%ZxK7WB#&m$aVtJ`)jR>`{QPjEA!@t|u|D-JJd)B4 z(~Xi-Vida-y%qM&e~oZv$J+7a_~Z*raUiM|b@*-V*uL?sd<%iO`R0u$bRI!ULx?k4 zjLu;Bh9uIL9Se`7Yvl#*PYGQKRij_QR;R!tpRHVE(qD~QdLB2$7yJut->R&%o0A|b zE})L5nP+61yI>QXOe6eC+PJ`w;hx=h-vJ%DqIgH-u+(cJFk%^`*#ntg`yC z=JX|heX-7(%ws>r7tlxr>W_dfLt7m@?gd9K@QNiEFI4IV&bNa?4(tza8yejtV)XvPD2H^%dor8d6iUD3| zmN@p(MwU{RSX#|G$qxC_MjkF&?!Rco%=*KWBgCvhKPrDGJFyJ<20S%#YKvpHIvT{< zS2Z~2tjzam2AG`5d`eBka%7vzlNwTl<4~(gj!hS1?>@6!ZS+rN#E9Dm#!?!40IUXE zc7}$;2TalwBjR>xw%X@8q*)kuU5EHaHjqPp&NcX{3g4#w{M~~D@ay}Nqtklr>!ui5 zb6B%}H-6{%5!>9TPqa9^-P!lnDLdOoGitOwGkKcFu1K!(dP!88Z|B+5=+1z?= ztIz3V6csw__aLww(il_QS>I&^-O(|GUh|GbT$9}I@)MwRSqy{#`buaAWs*UzrzLtD zen!DHHgPsb5zV)C0?8cTBGFh+K@>*$wCb_1a9LC{YW%zS7*~L!Yi|QgR=)UJtwM9l|q$ zi)3Oyff%PjeUybmABlsT2Dj&zn?tWcDfmZSY~%FzpYXV@;K8LAil;R0-*_2Q>CZ>3 zgjSoMIPJ5A&BF9D_Mi4MC0hoqTh$M^Kf85aw_2P?%97!ds8=vYf-cN~kesa&+%gR2QfXtj_ zS({an0QB9-Qf`*b3a<0rz9qWswAz4DvI{3QEWCzqQv@IPPG1Y`EanY%amTazury63 zM!Xty0)Ks!n|1m%?)2p`bTA*%kp%k(i??eWi)x)_ji8D6GY3rXg{<99@#F;Rl0!n0 z^vXCrXkD48RHHxsA9Dtc9+b34YdnP;CbUbHFs4WTug+DK#)sh<`L(1P+R9$iUyWHU zjtOC%*w24bPkVk7dn@b62}??;W1w>ITLY{O&T&a{M`RYE-utp7?Hn6fLls)=MF02i{Q9L$g<*>n&SJAdoy0GrGv@ zkTvA{mhdankVpTJ5?AmLpg(V3-h6gh#&RcS85vW{ZP^<+V7QUjlz zm5#$JSh2wYI(~ojnCv_G$dLh5$3mF+1N7P z&~l(xDF5T}?D?11bzI1{Yk^G%o>Aue7GHKMSYqUGqo??`mlX6@@@UZ!J>hN_6kIo` zm)sHRbsFz`=%!Ic<)CF)6avgpSD&bAnqxoj?JAi_lBszcQyGSjXIws&b#}|o3CkY! zoITS!Tcm)Q)E7eZ!?Evpp-IO<)@Pi2`ki$%v;YiD?nPyeZ-F8OevSeS7_S7>ot9aZ z?~t3!>EZyqJ9lPBuJJY&HaxO|ig@wClzz zdJ)#&NXR>zA4^T~pcqGUmh8(iT|ROGe)T)&cVV(~))8Qj27+*2upw7+kPNw3d*d7uvSC zX)v0M{ai3s3t@!+pjF+gicMZc$cWY}9p4%+7wdoXWhQ`kBD6I}6@!ri9N7NFkZVJ8 zM=P0*pUh6$tEM1^_-cV&*?^q4ymFMJx*^rMSQVXH}ArP1c1?TYf9L-KEh~0 zUEfY8ROgvyjjpjIc>t}73vdLQJQsJ~A}4Iq4e>zVpwLAKdqkW2-zV6q2J=#MH2aOd z_`(K$t4doDE>6UrVC|w!z}W{+LB_IqUsF>!#hp6&K`F?B1I6PyA-E5V+L4mOr>eTv z&PZy?_)lXlC{E%!@3e(*Y!|sJM7>(C;lMl+Cm)57X4y(D_DJ|4cXl~+SFh&u)^qBt zxZZ^nT%!J7hsLHp+sOZY@7FW@kp@nPK+0A5AT;f%Z58hx<2JgBQi4u==X&W#U2qg; z&PN&*zk$U#eP-5`(zs}I(m8Yy_m~vF6Vge*sk~?Ml3;KA-V z6S@iU!UXwH4}%KlL^TA!~==R-$V@(^s!;u`zHXdxjj;9uT$7ccA(Yh|$HnOET?L5IY-ha+G?W!hojvE0RT z@@irDPXc~ImnmA_x^TOm*K_jO^a{S*VBV`}zafIKvnv|qSG{!GR^Igl)LwxILY4{z zRk)numzS@HbUc)^=rH1yCa8ETCvszmnStdXGAhWtw#Hc_r&4Q>rpJz@Or{b$f zqd1WGBxXNL7DYgUfh8(@^@B$kaFneF&)dVn%j)B+^QsEJ&x1aY;V7R$DOXL6p#zEL=Y@m9OX{Na64`4k z3Ik@!)0SLw5C!AyBC9WpH+(*)Kev8qx{b>SO}Phy-$jvTOn@{k-;u}oT!LCphPc@I z7$B?s`UM}lLQXEMNXi8EqPvL6VEIl5Q{~RF)<>m6O!AW41(_j0@>A$|#+fTPf`XB+ zgtX)=Vhgr4I(WqzleBt|Ka7_h;Dm@k@^oItg4AT=>t8iHErvdJDY0QCVU zLden}?oG{mo7+m%Z+?E~KW^elWh3F$1zPPB~wZJNAwhu5I~7REi_v&FOQwyb0I%n>zw z=O}niYyr!5;~eR=jxdqh_t11?Zr~scAK_*O=xZcwF;y&MkUqMAz)HQFt=rWb7lYOz zF)Yo#?2Hw=d*g1anmwJBP9=T6`x#$%i3te7L;-3(T6s?EqER{KKvA|O;_3(@O$>?V zv$gTKm996@2>`Q=A}eCf0JiuCrVmJ!cKObr91Yhxk z6MNSqXU_j^rBaxoQWGkz>>s*@})wEK_u|Ay5sm*jcu2b*_z=SNZFrK0Np8O#@SWqV0+Lz712Xcc-yIV~4aH zG%^44Xv8Dsu?qOuLWqRtFgXwQKW;N|wH2wO+^hNqNYSQ%r&&G*nej{`u@qA`50)c<=W|rVC|rx<0C@Q0&f?uljBopm6PzaB$5^i% zzKb1FnBa8RSh3xVB?)SIG_x{)j4A^|ortFxTwF<`w;_DeZz-1vUcor#5Fhamv?>hC zKx*R}el&wY{5hme8Qo~}z@eFChPYi}Ly;uLhlbDgFfzZKWk9ph>)dxi|2FXs&>CUz zLHoLSRqLFFK|xprJqN*yF)@9NPCCA3(=2P2C-n!SB@dKYX8sYV^tGKxZA{dZs=^>P zD=@*q;2p9p5o{r64T!0ZB&rGB8o8U25KUNRTg-s4@+Y^EUTJ(GLE(}`iowU8Q}7VL zi|^89t@R{sWVhDw^mFuHJ%zd3p(`IHKR$fw)D$0!$Q6lbD`U6R)%{76^IB|KSH^C! z@X-f?NK`QqNHgdM3nr`XsT)$)?c@ZIC2&m;X%nqub4A)LM<4dfzHi4(v5P9om@?Ye za?9aqEi}JsbbYUpXlab<<44 zG^1@a*!#%K(y7yJ@dbw~km@^E`wH)u?>qa4Otm)EyS-wl;rYr|8DO~D>qXua)#ji^ z(n*~2r2`wg1C95PvjH0v5x_^K;1EXnSUR&0;Ui*nIH2T@dD2uy>byxyc??3kmuF9g zv2c^`K1CNN5Rx&3?bfS~2@Wf3C!y+)S|D(j866h-zOljiw}bNgoe)PxyIspc3Dve< z+_x?#7+|fYz7ey{x+|(@jH#li_W@PNfv8b;L!&bF!6wB)>>53suy&f;=fD(*i&}-b z#*P>S{J`wWpcqzm7A4L)Txp1xpVLk)^ju7@^o^KI>A2nOegDwea=+_9ew{30CY~Ah zLb!0DxrhG2$Uw=hkM?IbA~x;AVf6G<=8of>!sq4>1IKm0uJ1-U1S(xQ4YGwhWoo_V z+`ZM1-w@`y*+^E!gw$@{ER_i@^L{bW6p%M+SIy7hQwegZmH#`lz%|97GmB%3Oo#g2 zsXqEj@3bDD@h@)BgMxW&I_q)=V(bS2b9OEBQqMq1vPGus{4oNpT@AyNk~_$ucQ&`x zNuI@I8n4Zc3ykP}W7bee^~|Srj&Qz47X1ioaM-waImnb1&W%fZ10;hVclh;(Mk|Jp6;y z8u(KM;+tU8{C^xU>FDGmm0YN%87-shOLI?N>+8OASW3;r-@mi>mZk)N2H0p7`H(*Y~|de~9)z$0KF@CcNW)%D^yX+~eBf)9(LBSRIc z?zH=6wiu?{EvVn>JUB7nFiPCoeRQjqHwdlLfOC7fi`c9&yNma5w4J0^)BA!7u5nRdKMw-IQy1Do%Ax119?<^XDLVz9trZRKPVR6e*hSG z+ag62&KXna$o;k~%+4b=BB;XyK;oM?RyrkW>x9q!rh2*)+FO^hR~wh8Kmo}GzsQTI zizxO%pjA}^q)N-`9vXP5XH^9lB)$^dbG!HR)T@u$Rgcq&f1qtGQbH#t*cvN|T8otl z>{FCw*=M^o9s0}w!j%5#V10NqiMU8I*hzA_{3n`7-iLE|dVY}%?osvhs$A@@DSDbg z=c`%ETvHd*kVw$FCAoJcvne zjc)Umf=t}|AbwzdsH*f<$$RX>AXh-XsF@e_bOi4>o;v2JvxHe{0g_WT3T-H}rN8-y z$REl<6PO~dNHF%U39UjJnbMrj2PC56#IZ8dx{=#J(E|0K1LqwHzrWW6hp@M(Nuf-1 zdwc1+*7iX)wE6h^?hRG>S@6)=4eUch)1S_xTr&8d%#w@ zV`G$_+i(QTp4xq3;#Sgp!SbhooOrC9tU&M(w zZo*WT->OQ~ zef~MhC1 z&&a!;jtLCC(Nhx!1!XYClx9Cx-i&udJM*hAX?7&^(Mf1ai7lGb4y`M1I>EvK`Y*^~ zJcd&I&@_}{H~PokNur}HOT>uuyxR~Kb6acnQdeL6hG<6*J{arH6~?(Sp&i0T*&4D} z6^P~OMfQk8&s%C@7wH{PQJ!Au>!wD-;xo=mO=8UBw3gGIzc1NLcrX4*RYig{Hi*Y2 ze4l)0BlJCP_b7?;m6fv!EJI>3mHn0t-c=*wnA5^(el1+GuB0(_Mp)uX35-WHmIhd5A*$G3E}8ZoE9%V$sL zU#@h}ESws>RYl2)jO&WZMvWFgXbSl?-R2>F6JqZdED+> zo#CoBYx-q5`OPhtW%Fy`f?p8_8AlR$+O@LRbDC+_WYXbQbADgYg!0KVMt<5!pM!+g zXfZE^dH4qJBnV2JDT8Zy>W};*2{StyOUD-RoWQeS0ieR@Qu&W}$`fG#kV5PgDnxbe zh+uRj)oDHc@sux`h(qKWn|IfG-z&uiNz0WeRL2$D+akpE4Xq~*dx=uO=dYD~hO$4y zDXGMtIYnC-pIb06#{ar0HvV;P;upSWtIo%}*16%jugWL33<>)tnpA=+@Fr9%i^D7C zy*eIsRXtU|ma;dCRct|0iK)&*O1?164HN@2?)NLUnfdt7eBmy~g=mU)%B&A|9}Y{# z*aKY$FPCZ z^)JW$K?C07lThXjtkI`g{(i^@NBOo9?YKOV zrp0|A>cqI>tS6)sxZt&1N!FgH#NkwJxcaR$Bo9!1+l3$rClx0BI9e-Scz6AW+vzly zb$5w9%IgJaRW~N7|SXR(EjcjE1FiKhOY~tS+B$ zR4nq0UvZ0ow~_HOjAjb?;DgsWfs9go*J6ed1o7?4tor}xwX zY9EwcTbwPP9nD|x!!zbYLkIQK8MWV8ybVvmpcAh@G0>;fhL?b6UwZT;j(GkV>O7Y+ zg#>MxVR(fmK-(_w$*aa@uv){0pKD+E$+C3&M>@Q^Y{0AF^)_P?M0||gma0i2bLEJ* zH{Eaunz8B2b{*Uu`=XcNy`Kppl%p<0j?vK$pBLz{@_8w93hkNn9%z1(i0{^rl3fry z`hqueoF52e|UkHDBcsCt~k5+E0B7rdY@aMOE)UJJn!>Iwk zy`I38I+XneetOa9%YdsP;5c6`+mOj)M|+*EavL$<%c|{%VD$pPu9{l;k*t>I+u)E% zOSD#y*H**<-+;aeU;TuD|CQU=K4K{muVR5YZ=@m{#&7n#I`*ATMWVieNbTH#G4=TN z)hL&HMoRY@ids-Nbd*ns^eR@NKiT~4}Wh2vT5PURe^xNCq z&&B6V2}h>~U`Mf5{KXUpCOuXN^U^GY!^dV0{Ax)LH0+FJj}Ch7YhZ}ZYR%@wvsEL& z<89nh=;oOtz~~V+XcR%uAg*BrCFzlZEi?p)ojN|3aMokgzNmKJ6p+v> zgQzrahzZ)NH=o>@WX^J9y?lWE2X)6S-icDV?$_90=2PSc06BOH=zw#}84apshxa$p zIU+5J`H%%4n;Gw^9ODD^^5wh5tCDp<80B_eZJ<@x%eJ#~klRT$swf#WxB)~Omz^Q+ z!1djUOX)pA{K!6sx!q|@=ARK&Un)gVAq#6UM#mm|zZrR_i_+Ssr0d+cf1^#dOk&zr z8NWQkn4EXu0&y9iOAe4gdngbHh&>60d9S(t$m30Al=V}!$jo;UCKT_Mvy{YpJxV~n zWgoXhzBSbC-zPr!Ga``OA^1<#mH4DC(_LJ?xV5Ez@;H56hau7%fVCKktll4=n%RC- z&G0o<*6~VnN&G6o4z}NV&GtR1O^r}0g3s9Ku*5z0;fh^{^Z1C!Ko_*(C34ysRzd)& zk$DSY=q46YpjqCg0}~D|QmB*uo%d{N@Q^WnOdnfFmkWZxEe#s)C>ryP$J1CH&SpCJ zha%zNSp;f+?HFjp6RS83e~Ei3lzqVrzvH*V)0nwmjZmLI+V5NRCPfqhS?17%`;SLJ z29#(ky|e5E*9Zr<1QK$mTOl;BKX`0xQ9rKWz||(5o8A_tb_PCdsnHZj^JYeyri)#z z(F1>Ym}ZSrmT(`uZFJ3=X}ztf6HHhrt!TInwE8ElY-6UcYgb1n#uKc>exrhMgTL_l z?zkHY)!!nbbt+@eau3cn@cG!l>5wr?o+jnYPu7IqEY-Nu6ZZ9_8jJAP8`SqdOBB>_ zHBTC${diP8T6)cE$EJUzM?E>!0@5odY57Q|%Nwg7vB*-nyDPY&_3{LPe%4htUNpI^ z=qThMCUbsv>hUaqUEz)tC$Is6%HTH>yER8*K$Y5W7?(PN3|QT% z8Su|WW`7gfQepyebgT~H*Dff0La^TJR`7n&NuMVu_T*!b#QTYuEi)QBRo0>_xuZ8| zX~lF3xZne}FYL9Qz|FXYcgVCKSz_*$gJqn3cd*coGATV4@i!>~lgTeFUKaSP*@MP} zDc4gv@UzbyMF;VaO01qyZ}`{m<*z>BLj6;;G}`5imRSAnL3`EEhZJ8vy>8#L*U;rH z#7n2rXSc4$)t9SvsF&ZT2Ai)F)ICBLO;I;TJ>Fd{caYnrE`jHO$(ez$w}C(O*6kQh zJnug&Yd{=UZ?%^LUA+sOR%k&wPGhWrJkSF>Xyg3|EK}KUFyb2es1D7}1}A6Oa``>3 z`i+hmCT&v;cEQNEdS~0Xj&kbE(P6$LzRgd28G9)azAuOBU6)-wY>u~M1a@B@&xN|2 zYBA$)0?^WB*|lFShuZ{9U*VG7@cFJKKEE9ZTfd8Hk_?=tuePh2#3ueW7UH9Fw(fV0 z3H@<@{0uGD2hVu~Td;-qoL}x4Ej!g;wt1_eMq@uj(84zw9|L>sW-unG^tCsxE!JZ^ zJJ+8x{a_Kh51=lFhsbrT`*0U|f~EFr<-{j~Wl$G%QgEaAz{>Q&b0JdSi`!{pvgHwa z1JeHn&YXO&aU8+QS|yz3cbq=xS(Cln4jNR(eHn-@Nt{niJS?L-EIq1VFl`*6?u*weuU)1~T z5!wWeG&=x3pc_8f8@FQ4Pn!C$e9J7J87Ks?MhQ}38h`#2Qe%ZWYmf1K!|JDLT`V-Y z?Ll`1n&iy(xL27l>1pA)k;~@8bN0J###)Yg)@2Pj8$C_afPM6cB2&XhozIxiE2#1H z=RThe!L#m+31Z6f3n5>RMSk{hkv-H~tUC>S+JKd$uq(tQu6rR9AJ_wt z+oOZK;rhiV5%PE+=uBx8vH8%sG3AUdoWkm1L6Dw!wW4UwpCe4`+^7qtwS*4HvOgQX zp;$(z%%#wOjaArGR`b_ys%2^af$rPWKC9WhItB8eEWN;^vfaM#mZT8Z&N-W zI73Vy?o}h1hm&@@be^)=QG0Q@B`>mAdlFw#G-#cxmm`z|8O45Oe!WE-(jh1&CZ5jP zc+GB;I!LH2W5&(FPklut$5k}36MH*Y(0%h6RzZSc#(s-$fij5-i$t=db8GilWnmxa z^9#583f|9MpS!h0hcF_&7v7Sgq!aT}ru^)vuS@twbC^YuzRZGK>Aa#iJ302N1WNWq zoR7QShwZF)Ez*Cb3Y0&OdrFT$fi`*70d)C<;`M-Q7Ub_mz_{r#bal5it|sXw$#rB3et1|GS*>V+7BOes)?Se! z5jDSAe;y+T%lJWWG+GU7JUr;;7)(aEf`TU*j>k1!y--2Ir z+1>3Zd!6gu&QDWhVRRilGv5bo?WmW>L*~{iuETsyBBlBB4aS|6j73#FM!r>SkcGuY zU%j#j5AORvi1zj?Hy7WyIE8bXqSu2S1)rrw|E?xSNU<>-;sEg=riLhtO5k2_j6nn> zq2Qe{HGNC=^oNnYOu}ZyTv@7B-N=oN;!kY}*48!0M?}kT9}%@Ut8l^(^MG1(V*;w- z0TFEkie(I#&CKFkr9xJy4V^J}krlzLLPP*K>OONAM@@-*%f_nKRj?Ry$M4#=dQGruuzh%e%SqFx-U_T69lfAj{~ZqlqM=^xty zw$?Ze6pvrahPjt3dZ}G8KL17nmDZl z;1o+eM7e)@)a3)>;v?|oL7Ns@1Y2(&d(U>~O}xFN2)yy#PwUsSRc*IgPM13kTw1W& zvG_K2{%&CRJTk#r($Try^}q!RNjE+-c>V?BU_&^o2g^tOd~Ud*>Y&HO3UtQmyG$t+ z@ig1F$tp7MFV{=VO$!QI=)MgxajcdSk~bKO{-WpZOEvv4ej>F|!abTo6J-6@mmc=~ zI2w(fQcdArG=o7z$!H0M#-`CKU82y`u8u zs{i5Ovr4+^`{2S?@2r;A9|tZi%_LL4k%1M@w-Gt-YEgMr3s!c7gJ=5(#}u|_!c69K z%r&ArL*L1<=db}TMWifBEZE{f^x~7E1EI3pp1Dll`??obCh9Jycl|L2s3w^41h@>|Bu`o3hlqF2y6C( zxXK24bw^^8!C>W+2GpXIld$U~dG#dy0OI7YS5zp}lXj!m8k*VMWrgi8RgV9%7y7#n zFyD6x)9(oH@~bi_CL*u(?2?ScFEi=9zKpDV3DoT<+qmBMqT-gTeBl2@NX;*TF*PRC za%{~$Vn|ugh)!XG{8zxtT;v|K%w=T$-8+&`w9H8V#+#3X3&38Gqe(pHyuc7O0lQoE zK*^(aNl0r*@RW2R%0HZ@Z@B2|3Svhsz5ngA3ft@R{jNB_@qzg9;}q~QEDM+?x(bnO zdLPSWl|a58!&`JFbs?R|Cp-4^uM1-Ql7dvZtLN8nIZ5a&lV&9jfitKgL$`myp|&rc zcWu+wVV<7PV{WaLmVn`j=iRZ&t4nU+#*4~t#eb^jZul@X9q>R42=88-RGePtOHam?pS0n8hUF!0Mbog$5q za%wV=TCltigSxhsSgrUF=Au{l+{@2#?e<~ALdEO#J(Cqdi1bkOmk3IVw(haHF(%Ez zI^i3Gp3+Hzvy~EJEK}hdw)5D;1!9+J0)qbTFnDlSK`&onOVWdhTm>Gb&q!cN1@xce z?C-{n{o3t{vxM(V14IzRJ%ds;1`8tS1e58M5iLm;|D0IGLJZeK_TzcQD<0ieLckGs zlY8X*UP;52j#K{4qWnL2DIM8mrlXq1?gsw*YYwIA&w_uxk`ilBk=3;))u*@sR9mga z;H2eIx0P-~Qu+?->Zl9yTeO94K-l3VH1Lom@t2qRYs@uF5lIlEViy`Q+f)`~hC%0;xHsx;I3U zPgI4MH5*InWJvlm5Go;&n($g5gO@4i$dX(s-KXjU*U-yq&7MFYfzJ!^DI@JNnkws z)^kdMJ8`!{jzvz*EJ>sk0COXGTS-VEk7vU&rKBnC zU?ifL*O)@xVyBE~iX+lU_;)Ql6Nyznv?!SQ?GL(=2yYfQICCYai%ClDi1S-Hl}K1? z9{T**>9Fsi$Kh0MM>4N?7vM=#yQToQN;CMi%Rc#T%WMIE8{hT64(!%w?&@cOH97AZ zkfANIU89eklL!0O$r~(d(5S_;{I5BUvP0|r*8+6PspbKpjR-cdtsDX9pX{v=MV78~ z7Jjqn`*-&qSrj;`9b{OvW=XzeTm!D2EC|fPmq;|JIIHu&_4oXKC2dxRwHzsr-M}E^ zu8F4Mx$7O*BMbOb^YiNGe=EOwc5QS>90+QHH?)ZF4qayqpc#cgfftHM=C_*i%Lt1n zEPOm7nKQZhVjSY(Mtk4+Pz!!}1%>@ILZmQh`{zxOd*Rj+t3J^b*`cTgn6Y=GZ%U9;Og138I)uo9fv&Fi03m z{v|Nj{1x`PzA8Voq-zo{)TDRezw8ynRM@F2$SDFO)~m_ustP9HS5jz_3(qiMnjagH z@8ol}av&}Ygrd-fXIf5C9l1y!%-WCr??quZD;dpk}gIg{iNN zz7&M2xIYG(1T$Hq)Y82?_>btlq6^$Ej6K5;GAWi~cA#06at#}~rx?}L)r566?;$gHLMQ8hs)0Dl)a5d;;(UH z*_+TRB>Hcii5>6Z=T~{_`033Um$Zzwtj(xC{r@rbm2pu=Th|~+cXtd(H-dBzE!`c1 zv^3HkLw8DdmxQ2zbPp*h-6hfu@8Er|_x<8GexBL?bM{$#oxRseWphVx(u1Fts>8SP z4x9%R^@np$^J3%M0Vt>awfPJm)>&QwzdD@5m#V71g{cv8K)ZZ9G+lVI+xE z5k)Zrs3$euDEG_`Bk=K1_+srMxIHOCUd%`7p-t+Ecf!;!Tre*E zswO;=nt3qZtl913O5WANido5H9~I*zK;XTis=m}gy5pL7a~xDb{`0P}$E1J9`po6d z&FN-Xy!}S~fWOI#PS(JuUw7g;oiqmDJtn_9pK3ne9%W4L%-5UmR7bB+zFT!Ik4TxtwF4efImpHXlo$bLWro3j>;F8>Z(UsE1S*u!=lfr)LgE2-e1uM)4(hR$(qPf8Yt`xr%SvVac@qq zjsMQY^;uzo!McEzHyNuT^zY`tqB!tndiy(5DeeyTB%w=;rxwHGj}pFRvI`BL_=Qi$ zawvBXrkcQKTMsEu7S>P;!eA;?dT<=f{&z{*SRUt8Ig-0UuXI28W=uXYil@8WyKyLd z_H-F}|CTBV>i*h!6Ug7mAr`!AeADWA2CZR1gX0AEJM~|4bNJj2SWjRk?>DJ1;_3Y# za9y6*7k4SM$ebN~LF+_;!Nfl}omU@oPjhoUuUbQ=w+#1NG=H?;uiT3sJ{M%yLFF)B z@(G-j*>LE)E4Br)4etk$mFMe%nvU?WU2(uzUBJzoKa7IP ziuutA6HOwD8FB?*#4fI_dC(;WdBtClOAs1NYSE{ih2uO~olIrA3#DE_G=T4i1%!4rxx2`B{uwJve>)ZxJnfxpr}OCZQuScP12k%Cz2FzvFyCjpWO- zwluq8n(Zs_Gw~QB^-9`? z!-w3lS#du~2T4o=ES7Oz*g4;F9K8JyTX@f;^ z%8#a3h|u3O)!X@P;FBA?fET??)oUgjoW$};{FCR~L~49U zDQYID!LLqxjVNQ8gh#k1#Wezy2}4!WX-h~BBDoaoxi+#_aDbvG1OE7*r@e80e9UJ# z@jVDiU^hr7w9IBa5#rzD_tt?L2SRs4^vp9Fj;3j5GthOCKhY+5>y3h7FgCq(jXhIX zn2JF=Gd@G&!#g`P?;#~qn-tV)hDq7II!)e4O}F>&y|E<*3A*ELpf`i1b6tr2fo3x~ zfM4@1q=<{-;7ZcTId|3u1Y;hx{e820XE3g@k-HV_S%sK*PXLgv($jS9+ft0rc>z~j zHsWv`t(jFWPvo=wBQCknmFdPFE=&EffZTALQf^ft)Vxm1W>~p3-4v3y@7B{q>^;cL zr@@zGwv<(v8s>k81Yj*{(h$alqVsO3wu1ZX?Dvypmz;XfG}3lO@km2|7}P}UArK^V zT6*vd`RVKNt2T}sPSZ9#$#-nw`d`zL0TE^S>>u)0k%J6UFM-og7xqDXm?;KA_70mB z@Zt$LV4(AT1$B^>)yz9=>ss6nm_ObhuCYf7rH4x#=#gH7{k`@ch4!38qR)#&Vy7TK z%L)TUzSr%cHY4s%FL0j}uU{ig-jh~&{W?5%_~{*xS6gdKFhC0IINXf&?hEa^0~w~D zY!!4K;t|X>y~CJ-&^hB>;~kM2g+osXZ%$QIwoQPS8%mi3U(!KvTOZ+}Pk#KLcIfFD zN(rC(XjKBPK` z_sMfrt^TV#LCk&pfQ}vx1j%`t)w>;#DD_V+ty1xTokv{Jr=dOf6~86KM|Yb-(pmQV zKP%oM7Qeq92aj1?`b@2II%YY3zwr6=>z3MqsN=SulyK>JXl9OtELf1>e(x&5Pccvc zKhEb~u<&(z+OeeFW{>gn^yKz#7XAD+U#$7Sx<}PJm21h|)f@XNk1rSMv3-tgdapB!(WUkJv9>1KXf`k9NYuxql@|u2^YI5|IB-oc{&ngUPk>}tO0(Wb8u49 z5HO|P469sEcW#G|cS$B@lgW=2ETMKKJVNhK|G3vPzEOJ10L8&(uP;9k@?vZ)ABnM(vLk7O$>>kYQcID&5t71hUva-nkIS`ueniB&Bm|rTR9I?~F>OXN~|t&OSf_#8u#+Oy;khiHM-f$JifjaHu9I z`my8map+d{e6M?u?on!WV!$?86}^9yo)iO47c<&_(G###zVzellkWp=pZfvB7NL>P zWOSe%0&IVO{l>YK{$e+7osqHPQP%QFtX$OIp@^ygoa#`1^#?&eFbOY@?vG>idV zM4kKF+QP~l>!0mO=9VfCX!$Jo6}?+;1VBs$aK(ln0w64F(A&oi)r{CMpO*6M?SZ_Pofou7}F1 z5(GG=xBM#YhjgjvMjSbblH#kwp%aBi@JqBl{OJ)oGY@|ijtus0%AUTwl{2{ zW2lxgqcD>g(O6CEY9v(-%#euzt5^+XS_~Ce&bOa~WS~{f^p8Bo1$aU>1CCwFXUr$= zf@I|!p#=j3rO?ts*ps$Cp=-9Cp9zCz0YTzexuym_EYh)*$*Jd?zX(NEv$TuM^?XAD zj~_O>@-Twk75Whn-g160(nJ;$u;jMRW{<+FY=R^jzcf1i)aB3Qw#g> z@<~#^8jZ+4tN(1UY_i{^>fScW!Z<26VDm&kMDV~@6C`Txzvjc|veWpCL7Zb7+ivcx zOE&k}0R>W-eChJI@mbnwqqXp@u3+V_5Un3KIK2)Vz~<2Mudfz!MB4Ugr58kdLI;~o(m_uRHd zN5u^TpkT{#W*p6LN$1g=hf{TH!}L;-50}E0M*mI+3LSIZ6CebixY*@k@gHDN*&FIX6F=mHFhZLd)vCNkW7 zTH|jKfZ|V#FqQO7O05Z6h0T zBnGu!)P~&QodAmb!eWtONUN@JC2YwxNs5v)(nLSf_Z|k1i8SL`U>=oEX!j-WY~1~1 zQS8{9q3+zEfEztPcI+TW{Rbqdy3X4HvkR7|{Xr)_QBWH%M^_mw_P!&F&{?$uTC{^v zj>UR%JcIj?2p`&7a{A^2mIRh6EtT~5Uj_j&yHJo_#G|aiF@Zv3OkkI722d^Jr#;a4e8&J~B+c9OuO}*c6 zb#9AQPR=De{+i4G+Tn>VUxGP%dm+{T16NsYcKlQ~%+Y^r;QW0S)LF0V+wY~6SH4MT z?Ct*T$unk|b`H$mC>T7jyE4b|Vx)Q<)g693wS6vF$0o!>fUZ{d`#xj1C$dNB^+qhm zjy11@V=ptnIa;1^^|ADlqjPifc^$F0$ev4c2Sq7X_(9t>yzfa+QhAe5Z1At7y$2|v z(y&kUhZA1zY9)38xD&BSKgIEIfCtx z!3yG)dp_-P=|Ln*ElxS{cqGrZF4=J+ z#fhob<#IjhbL2yX*>7u=fIN($sqsCM2l!xf)8Rc-$!wysHI;O(M##Et1;!7uUBs`p z1&aFg`Mk~g2MGjYRHB>~9@Ke3jdca>(Zcn$v;>Q{HM#wvc@#<DBu2LKMRJw5pTw|aH zE&YcztAd?^z*xVJlF*4sRvBXGVi$=lOs8kZ4QDp}p$3YwVXWj}K#9dmDr7dxeS8*x zKG=H(;aSPQ=t56~dCb72o5RmaFO=pQigHmx;z~8MgZUwtq9^Y+G2n=X^)Se?GXfbl z`El6Iz*$gjc=W6LA&q#b51K(=@!Jl6Z-6CS7MqEr!)3Fsva|noo%(Y6; zSqu3LRSE}xHyxth1;rZkWrzsNeCuK3qcndB6Ob&EnVFsS!dm2fz+8?9m1I) z>-fFC=Vj(`F8A06Xwa&4JC{IShvSx$#c|W$RlQWjL51|4b>NyWP?wk_xXoz zYYx6S5$mKFLz;n;l)FVBg&F%OC(rC=%&5&_rxp~#6qofVOkeB$2j?ePyZZ>6_OBwl zzm)4J*ICF$26cA*xDf7w{WiQ>Zw|b!XPF~@5jwH0I_-w1LTXQt)g*@$?pU+(zhat_ z&|;rr-lIYq3ai4QA0vc}jaSZMX}Bif7iKwfIBd`FrrCj z0I#f9751C>uK71ZJ*Ye4G4bMWRpt*f%{ZL~>66f#fjn!>S+8C5tc?tP|Zw2jxy;p5CPS`TPNF=;Gz5ZrxN-D0-~(pTSG3fnlNgT zguOxd+YL$o^aCnc-fr`_@MCF^Pj-HO+(O%c5oLJc=)pY5r|}`?0yoOEu2K#^mG-VmDnK5+TJ`S25PqNdJh0N zjdIR%^vYZ0>tvtUK)XRtkL>9=l<^JGyzAbrXYf=>8MMKj_=!SHqYL_mG#kA-!j`6# zXqL?cM_bd2Rv-=Su|Ry`3{f^Ntnj!IM@kqkEAnf*;^?!64;`&LCcxlT^+-mEZ`BT!y|Y{4YjbRM?B0!J#C%QgH$kK!%T?Us0K6$msjv? zcH=?rVm7h|I^gf|HT!{f3FfGUIe6{T7o9c8Trvc^3}Q2PxT1IY?^X&@k!h`a=fRtB zh3sg1j`BbI^;x`6gmd+*eQ|uBwcNaBeyE;;SX^Vh$Ul{OadycC+L~u)(k`|JovV+8 zN4RX;;ERefG?1%dn&Hn5oh2N?h;bctA&Sh6N{MNqlf9|cR9bdR@a~D=;kKwjKy0N) z`l`K=%O}G2{lVEuSwaixcfHI$!^=xFM#vfJg>N0A*xj%^D;5nTf$j0*8vOnpZA>*B zR)A^Bu7)MDhMZV8p}YADa0Ob`jTazIC?-9Z$K@#G)9=QY@&L?+P{G zIKEe27HvZN#YLO6F)zrws!J5xb+|(9r^BVG7sd|adK6kta-`^CbmQSpe<=-B&0^4U z`6pj{i>b6Y*JD^^l^jO)3*@g*PwGY#Uz};LTYk=Z)71s_Q}^~}vIU)bx7_^3XRs5D z=T^|oIHE1jrYX^AnYa`^`vesWZ8)w&5`gx_>lP`9X6j=k6uG8|Ca=C{5h2*Fa&-q& znq2s*T1piND5jVmL^Dx^6@1_&6gcro_`(vEqE%oMcTr!LQOn;Ai^wnKs(M6dl%?&e z9r-rcE!t=>Cq8Ib=N+K(^$Y?(N?{Xkx(F#b)`*Ann6^XdN6gm=Z=5@~XW|R?9T`H} zs7+V6OG{BBDBqah6ZQXs_T(9pu7_oBOL=xD{`I@8{d|-I_YQ{iWADzB6dDE>iE4 zlUw4KyBO3)SVju(`dH{@P0r3(^EBAfk#N#7UN0-~@=DrQ0@!=f_h~)x`2(tdphNM5j;4|xJ(`d7LM*%PbgFNqgPD*;pNus0EDlmvhUioFG_ zIY8krbd1_cfbl9aAC7-++hF$0jwjKyel-1YR1tB*baQ)aLnJk5LEVHR>rhR@Pcyci z#*+DcwSr9z3ml|ZL7_qFqW#3zvZgB7H9M2$j^b+1%wIY1ILSL`1=Cqs;Cg~Gmd)Eo zuK5@5jKWKybPrD-%J_;1NT7f8iVi{ZYG~FZd8~_f@$EvFX_yVZH|JL_MePPnX$zM! z>k_pdt7`QuK!Jy80S#@K3yH*_``>|&z({9saKK%Dj)Ef^4O?`ib9@B#S(nDNf_BuN z_tnSFtm?D+Ee5otEaD9`Cobas8Ubhc{RZ!a`VBN1_CX)l#s>vXb=VMJbBswI=z=A*C8^#zT?EahigV8($CO%~@0625G2O*FkydGH&ZkCk;8T+VAp zMU@GIiovX!lCxT(rF#C!XICc4!X!<&4pRT{+pABN`hJar>n)5;G{~~+Q`Els-nr9g zdW^5I`!X5Ne9pH`VZ?hv>GS%>=%s{s)F;gYqX)kgR^skjCmk47O+!cp~t!+Ggm8ZDO(lJVh$v^oGJ}+wwy%-KVpeK?@ zMfNJPKP1>yBKZe(OFF(K(hTqMSPIJgSt;wPS&gwq&Kl+4u3f^>uQ-pAC`ofQQXGw| z-pH>bEnu<#Km{T+L4V((PTJJt;2G;9sF!8A<>f%*t^N2_#O-p4|hO$E~%BH@H zF#3LQ7M!dHz~yN02}?)0a^m(1N?)17BO^$#z)EPrATSZNnh*t@lDiR_=zMcr54ycx zz3cqWiQM@NWga%rBhxXZ8DtT&g?$C^pQY;^>}5mFH#yLnf@DqeF=4_^2a@roO#_ZQ zPI8p*n(MRGG_)P)qkk`u4Cb@*RHx-{Nn61BN~E3NU5YbE)y@LHFa2)7T*bD(?P z%X!klZlF(Fav5`>M1T}li5B#IZ`*D|zu-kOZyAnGX zBJbL$dps_2a~{;S_z7b8@PtQLSI&zlLiRiB5tPbJACc1=f7vF2@1~xUxp(RCGR5DR zRIkf4;Sh0Sg(2ccmcCEx^P<%@<$1N&zFtimzh1?T#Sz|P-fzmeiI}c>N&0=)UV8`; z`lZ2}So1pMG4kB^C{sMQRwD-0x3k+5Y)iU}bjA9+(}l0)tHWx0y73k6)-Ono=gEc_ zn*H2TxQl_Pprf*vdp-N*nff)YVUIMW?Ze}O*@8aCX{!|U!m0`Z3+bdRn+BQpGF96$ zYGJL~4MZg;AuMsS8IeyUhsZ`=Upw5GnE8%bRv zBo~4@Rf8&DYBs}ysfxxJs|bTNX10P3zMrvZDz1STi~ub@euL3<6}Tt}A^lQZFv%ur z9{-za&9Aa{X$R3Jd0*lfFr0q$0`?W3s48DU#ZDi^IhZif-8e$J*4$RR^B52&v9iJgo0?ryCf2F}LQO-VTr zL?3>#W1?O2X-|j_Jz23*X0bnSMDmL@x**>J(Y~nB=ZCs$1bhi+@TTpX2({QXI7YJ1 zCgr1Wl#VDovk5pS+|B((-wzSZqDlW`NMCUj$Ie!hGH13U(N5t6xeeN9S8jPN6KL?M zx*4Nzyi(0r=FCUu&Ha|nFGP=iS@#7U0_xw$O_K7dX_n(N!pIBecR8*F2fJB-^A|*{ z`f3~Dq%PiOdsurdg`#Ljy6QEc_PPvp@#JLSE{{%-#K1HR36jhZzZ~@*pv27^ZaCYF zSy@!2_k?QCUY<6FUD!VXwXnYWay>MjbKgK6a)h>cOTC&lMk$I`%3K;jfhCK54sFb- zX18^7H)Yu177W@jA}S-oFJD(HlKCBXx3cZ`SpCV!94P}86m1d^u6mwn8|zt!4aj&t z6@5V5Id<^(&Ky@D1M*jmI2iFd82L><{HKe)&h@^!C3F1gv%me*q*<%mkG7)UU8^3u zf}hVH9y_l;P5a!SB1-NRUSfAaP2fv@q=b5MoUHm?e?#ny8pZPKaX*k))LA|8U4z>h zF}~YiiC`i^iId@HCi*demNt*@K=;^Y(M^t$9liSu~V?tc|HxfzXg zsQggr&%Y>Bh1>6TaSUx-Z@S$!es0itI?CW)ak{*Za@#wvL|D4{)_Jb{0G&F%)845i zJPxqk@RJaQ_^!JY_UkNsXh&~2YDE-r5P29sxj3X0JkeShZ&+5pC+R$VB;g8D%Jjbz z>=gF2>o~3UKdF7sCxJ1|8RiBN-i1G+B*VSf9ecN`p^LnJH*o5)YnD@Pt5_4h8a-F{ z0n!>tpFP+gv&`&>DG`H4=CZ8p`>^gqD)_w8zIUGGjXaB9inlmGqYF`ORjLzRA#d@o zdcQ!q_eDf>tAo2`Jg@z^N|df)e8hX=?4Hgq$+tWg^YT%-xz-Ij+Boch_NaGMTJ9|o zWid{1bXd#sd+72D;v8%0W6Y|@w@!!W-y3=~(A`x-@VuGk&?~Xql}~*Iu36$vLd36`#Z$#O>wR0;vA#oOUY_~2!6{@q8*E-Uv7!lB#TOloJ|>W^y-Q*ZNN+huWmA**e_9Y~-z+Y)*M3{@XO&ch^Tt?V-5OSKKvnSYpz zs@)dI;Z&LGd?rm3fn&F|DCiE(<^S*zywx;>f;Y5{b&L>d*CJ~jVgHI3Ay|*fTerTu z?1xHImb!b=;)jA@S@Y}2yHZyuqFMfnwZr@-^oy&@{VDa?WCW6fVJHm)VP86|s=YMX zd$(rPBYq&ElgM2LOiPyLBIHIE4d^j|wr%#x9T#Pppk5jA)zXo+G!;3}Hn^8+;JAPI zxd1)?lW%H6Y~q4%VRKlNp0?>qJP_&!YQ@Yi+WXtY?7j&nloixwAyT>HRO9Nm*Xf2; zKCfbsPYUhq`|!834;<%y%u=Q<5HqSK+zvdDZ{(c*#dc`L#Hyri5j`*DP1H-vUm4od z>mGb*Eu%oYXS+F?seg6g(+o)D{6{ely5q8*39uQHt>Zv1F)Ex}D(P zf^YDLB#?QpD#Ah>^)jCNR#=fj`9c*cfT3^)_)>HZK`|ty1?tkugmW|H(Ey#{ccX~$ z9MZf1M(-Lo^PtWd&E$+itUT5)9}>!{Zmdo(tF(8?2NXHK-HMLH@*!Ti22uzPe!S-7 z?v)oSLUsp}eIS0mG&|p$`d+SFk~r&L9Fl@D{h5cmCpSNK zd(h1Ksi?M`OISTNtVyn+LVE#VDums@O%;Q069iT+9DV{@*K@%nkWj_XHq`qL-5}Y2 z70S;14BZJosm|eusn%-Z{CfXJ3>rT?Dv3JtZ5?n1iQI}_QPs@7s2wb$W}(M(+%dy$ zB*>qSF^mGWY^maF>!8chqIAKXA)#;!P&zVlv4}hVvQP63ooW;|uJoH;H!@unEhRWSh|7pw zFTsNL2P-kr=pmSqY-82ShYv5I-m$chlQFbXfMsnW;ED%-aWK-U%Q-KpxJdmxFMHE{ zekQpjTY6CPfi&!6R2Z~h3HClp!Qqb$9Y}j3w37r9S8tIhQnKaqRp=%@8eO}EQZzIG z)2X0$Jj&uqlNHO>mD4?qjK=rjqak<-I@;|jX?D}Lg)WOlq&|Za$2jyIo$Mu0t|gnf0L))OK&-e2+RYyP*CY1BYh{OF^9FddR(AbJ7@xJ1qH+fYqbHJCrEwiyrJiL} z(O73thaecw)hFtrRlmd2mNx7o{{{&9&%)bYvWYjE$O$d69SI`epGRD=4#F0H1^7Ro zs0p^7TJe<8Hu;ctr0yAwG7Rws(^lhWGb|?LkG%;!mh@E~#t(+RFb(objsU0yr4lPE zvdAxm*or;0lyD7y2|?g=p`J#ZIJ~A&f#9*eG5mHup2QGMt^HA0l0ApqIYLB|*)0Z) zhdDy&mz4jX^Vd(c6XMsYEuM7xXe{sXH7j@h(CudXj^%UlG0v>VKv)a+%~660{vX&> zrn;#m9s*v(#@)Ne0%b;N^-m2op%n*yR{GL&lUHJcY~9SCp&hR*XeE?u!38_$)>Svu zJSnId1Fy^{InB%=Wifq&w5&X>ym@{5jUg%S{bhTR7pr@J_Us-=7f%Y+;TPyTAmFL% z|F~nnk{Om}SF>`7C7PFHLi70F9@jLiYz6bkpzX8v zdNK8DHUBuusR!xONRr9DMj$!1t~5$J>`AiA8)-w?t8gANpa1R~ z=*x;)9GERa>l)P z;i%hz87?VU^NM~ZXq)RxZ@(dxG*8hy>h=RsNxqF`kiE!7_1)2oSl^`*J{D>MNjno8 z-2%;27*v?!P2W#Ut00IaI}j3;dB86q>3?_CO!3?v6XCHchSdwC_A>XR^jo!`Sdy}je+Efm1GY%hu&CCQXIYQDC zNXn;jqB7{4gnMaAQEd}(8jfF@7E?EA4K;uaRs-Sod`u5Qt${+d39z!EW7c_Ndx*AC z;=pV+Jw9_#N{2~CWSOI$qKa5#!7LX^Vis)j3Yy(9StFr9 z3bMTif7z1qlT&Q&ng~r+kxbE5_XG0>=SGxxIhW$iHy}^6d$N*Zo(M(DW4{Opj5& zu((tO?1rK<)DjZ*tyH9|Tc_X>S=GN~Y#m^4RWK1VCsZ9sJq;I;sBT_cot;yTm9FNiMw}92^s6jSa|((zEzC?#a~U?6ZA06jf!( zSG`m0|NC`9;>W0#u)D9REG-#_dqOS>O@AX&FJVHdLpy$JM=D){pC_9T%xBvw;g3gt0Ggo2 zhw$nw+Sw15Q4qTQd*8xBK_9(J;cHQebw5hpTmrh6pW)Y0Yfq+#sXrN{70uu(dTF)2)NeH-3FHj`^#gypg{m5L zAmodD*;uG}y2HOtY&)FOl=dam<{&jS`S$V8YCCO*R}zjzqr1-Hu1QBYOt!u0MH2Od z_K0jl#`|{#nkuEXg#2^~mRCfo@)4B$fsOr)Hnz9>d?A+^gRAW@cvqR5&S`AhUhwmn) zqZxxG(|)Q!C(022CVZ2;36HYf+z~sh>A6N--j0fm!h&g9qAKUn+Nr-l>dy9m!1f1t+W4AFSX00=^TzrHnZS?OneU?0Z zI=PdO|29}xcER-UEP&naJmgNrBM+5{Uc$JOz>^T6UpTgD<0TKtEYPa{CUt~Weig3P zfV8xZW(eK6qAwA_Z6qf*pG3=;aw?!a1fJIJf&Y-C1B`zT^47DqG8GTJfy5bjNDaAP zI+>`WX|?@|%L)G9<){9KI;rozW196>)WbzOz*J z5H`L*L-$~2AoN2zOk z;v9qJl!y0}CG-Ft3;FL}SfEX8Y^vlE+qmy!H=+Plc$M10)hNFQ`xl^X;gL$6XwnJb z8|+(ZpZzk2AUowq6^0NeVay$e1VAj*pq}&gFJHqwNUxAQ%0=_ z2{oy>sSP4+ER!1XVb06Z;A)KVVvS!60M5G(SxJ0C1qQR6FCuq(GSj^smrB-N zB$TG6oATLC<%1cvEXse;>r16Q_5-*JRL%NTP{S2tFKM*KS!R_VGt_3WkG~;!$LYJcO(h^Tjg-`OXNxi!`{3|E= zt_;&x>SrflX4wqJY3?`2Zxe?T_V=z@*1%a@H(n??!5++ir-LPYVR$X7U>X|3jn?*W zh>bTItE%ixiCtpM8Ahy97QU$-by~_Ra(j$e*Vc9wBwyV$i28$t zbPF{bO>CB0YScg4VOw?FQiCA|G=Za zEUsor;q^$-`$us>{xcJ41ksLkBq%}ke-Roip*}gK`#x*QX!qIH|6m~nEtMU-BG)gY z(~sYQM`#m}KJgV^0SeF93XI^rE2zdUw2ugy9$G#QSZznMtn+AsvauS-|1i;kMx2H@ zId8ua55dSmQ1I8|5jc1)L-3l!8)#^NGQAgCx>^WyBIh(aU-Y*5kZmz9#Xu(OWkej+;T^!VcZ!D$cq{t`FXQB@5j`dpL_x7~+p-MuW z#miK+bBy7`Dij8YQ3B)-8F%A=z5gR+aFg3oMv800Mu=0oIFqNHJ4$4ZZ)CA?OI-6p ztfG}JhqhQS(M$wb+f#}~dRQQ~!C~TIJl@Mju31F?-8vz5SY4{B1XqoK@a2@(koR6q z+E?)9=xsN@j$eBRGTZotct*8RcCjW#BR9eIFzKFrpKA8)Ws-@34@h00PKC{Yf~3Dm zPRE?Y`m_1!=RHKfCPmBZskfxNKPixjJ!HeeL4JcoJ&dg^&&or3tvaN%hhAZ@aZ+v} z0@VK-VkQMbFaPU%+PGtj%0#`C5jT;nnp@Rb{FH{GMEt}otV#Z<0keaK=m&J(=m{e( zQz`u**2|hv+GZ3a&93ZFJp^hH^WQfK6SbXTMbRq5^8E5?v2BOd6Vil6F4ehd67n|* zpU?KJqPAWq45By{ZHY(m2}+RqGNn_bHp-tQ{X0ybgJPT)&WzYmu!q>FuHc^gwi3zc z@W=@-5e<)o7*s&F$-;jeL|2#LlMLC_)MyHLN(w)Q zBBles0@l3Cv`5qYQOYOZZ%3tDQIPd9nz-_FrXAi8tR$4tT!B`8f|7}h_DpK_R+#bB0dv=QW*C%EX!baqnuCp<3- zIgDb|lezwj3@Om-S-Ee-Ftrof%n0qgH+aCjlyGj3<*1JCaoumBa`}0??jstmt5h@`#h(VpG7R0u})22w4@^zB8XH_Fj5)&&LRKjE# zJ{FwzR)>>wxDeI49!SbiM?spnZKt(^5}eOa`oFo)F)BV0MRzS|!R{5O%)=iI(qbq- zrY+4bZnYonK(ar&^%TJW%E%)T%~{y6swL;ke%xs^8$+mEDhHMM3jKQ{3t^Sn1`h5v z<4WyYOCwhS?j^@`4=v@d!l9u3JrpMc{na>KOHosYoPB?{%)mM&o|3pp#8^NT(f=>6 zHHhDQx;L^21WTpN^|>?hNJ{Wzt7T1O0M3@g9EU@xMvN>h(8%#x-`Cp~T@DJ(#@dS+ zwbVeT=LtBWu;A|^U@8mVG)!r@n>C^Ygo2~k#+QaE%Axn4dj>ei(qP41>nA*?b$sG% z{vGv*0$%uGF$B!Hpl_x&gE+1HZ)$rCumG@&AH)b9j)}O0L@A=NS5`x9Z8vG2#t#4o zIO*kCOww{1Z|=hwG^J29(G1~0y(Lt>RnPSZjMU#={Hl*&&a9L$!uAv=FrNi@T&ZF- z(dleT}v8dGWAAFkepv0!kbzHacB z5ohiF+S5=-Vpi$fpNHb%S$6e{0q2`N_Cr zv&Vg{fxta$rzp~^+&!O*$My2uu2u))fv(~7{bIO7!W*iq0$D<%2EB9iTuY$a*P~!M zFVJCtdc-W6TkC8@CTnaq#(qdIoYu=q%ppM}7dfNBQ2&kzS{K{DzTZMaHcwH3qjhHq zHPt!!?AD4pTmS#>81SQbgWy&ZIWgV}HDH0NL?L&&fsR?G7dfUm$qn$@Kwj0Ya%WnX z=6yp~VJrH_svA$!(mdvu?ecdf!ZgoRGbBj;b$24!tPb@BlRRL|@=ZPM2Y*+7by~Iz z?>t1LL~*k-+LMR)pSP}Rqy<9V-F;_l0>G@IF@dC#f3ev*z-{2|C0CWViaG@F@dd%V zM}D3;ulV$+0yk4+7Y|uNkq?a$PnGF`P@k6w6r!(&+apAL2$%h+-2_BhkpKHo;@CIM zH-|)OW4buoqG3>FM-yuiB!%Dju8>9|ML^p;BK}d8Pfsd!Wanv5q&R4g%YiIg$Czxa zx6^4wc%|mQrzk$AYk#p&ZeGCTz3S*ML5Zmm|J1Js1;J8FC~fWSAma%Wit=&lk#{{p zNd_&NM)B)HO+jG~3YQ8g)1g=m?JtN{DUYJxCP0NyUz1^t&tGBn9&t@Di zOeLtfJ*EqUC}+j;#8!b*uTnO{6zZFw)&>|7$+shve#IWc_@YK#rv6)+ooV(&(JUr}a$rA5jK!u~M(A z$M1OWOP`pXweDI3F1al{dSN5gnNt;GB-ptHc-3aXBTDfq_cUk@Z8|1~yhUJ=(?fhi zWekCTL3uBMlD1T|rGoI5j?w>36(Oj?oOaM^>MSWHtJ(46uu= zHS`ASR)O|vhN!gmX{ucM(2)F{!{s}|3@KDZ4G5mGzK98o2T$> zx`3v};vZwd6r}^R%nClctLaaMt}H)cp_Jd9=)aYq(`3TmF<7#mJmVl`kfBFCAIEh( zkC07HP70<(U>~6xCQn@{C4=JjhO6Rb8JG)77P8zD_1^+TqZzZQ+lQ5)B0zsjQ%PB= zUa@X@fA*(}aL*>Py#up-rp0bcUj{~2Q5CSWHnqMKj!ufCG#QVz*yL_md^=n906}a< z#pZvJHB#%{{94ryK_9}XxYD+q(@*uNYmdfuXxV9VS_{;4mIk!p(r6`(syq5wly-~9- zMNOa&@b`gZ71;fF&983_8)Oxen-0vcWa~(EbbZZK;4}rr6Vp=<^zGT51kQVtbD@31 z|LGcBP*s^-CmM$t!X3sNe+#2BQi_DpSP5X;x?aOn1x^?mC8f1Wl!T)NNl;_|?1U5@ zB`#W<16M{k_WtP%EKoH}Nj_oFLrYbICHgk9x{MS+fop2+T-hjAaB>`;2IHlY`d~@w z7O%8Lu7(u-h=xY-MKKbC8^6!Y6ovSp)_;VOA&X_XBTd{z8k29kPO<##*y!6bxzNwF zvZuxsadhZpjf)GmZ8(A@b|3wW(LOr=E>{4~AodNIX~{80{tvNK#(*3__kpJ;&qf4- zePXGRSnH3gB__iX#oaqC{-xX!7xGQP-6;!idO8-m<MPG8zd#ZBvbzaIC6EL1zIM;$|Dx-cq(1>o(t~Eh(YcEm+=yegg30w@=q{Ww-h9mngSP3!k zEf8`qBh)+4y^Xu~ts*2Ts(-xq^BLEU0g(oA)6L=Ie-0S_1Gd2~uBP#u&7djwK6vLe zrEy+jVdX*vvdo7kpcV`q0rrwYUgbVnM-$&k_L}18W7C5_^3U$YzuIT8+Ib$n1N|}m zhPST@%9!t8lccRR+d)R)ewUgn7Qup|OFXg(S z^0m%|{N~~-YP|9sE;W_VPFGf}j4x5E)TVEmMC{HgXxGP&>f$XbMlqok3|Er>`6Qr( zgrhGo=1a|X`+rlu#Gqy`P+x3r+b-V7(({6CY?D@>wtY2fnVRMEQ-#^y)3sIM4?Iea z2)Cn?LnXZ2Bsh!jOC{Sllj5I624@g0xu9d5|4~&zPU9A@a<&S%AbVHhC>>qw7smVl zn7XQfsJgW+-HkL1CDJKKcb9Yz-J!IC(%s!9-5t^?jYEi}bTfo>!@u!6-}%qYT+PMa zd#&}ZH=a1nH{=v?B?x6)G^ud@f{a@@sq0nlM5jrYU{Raxty4^Uj?gFt47>kxH}jx7 zahWelScN;v3yd|;YcNgU`LN03I#F09YJAhITLc7EQ;HNm_wzSAn4$3Na7kN0^rErr z=AWlbRk?L<;fs-QY?_=MDZ6&1+$Ms@CnnNf*%k#U(3;y2X-}Wk)McWi(byoc@+(G; zV9Ir-3Sy(iky~Ovi2XO*mn)u1gvLt{J|F@`Sjo397myrSwhgSRR{~q&P!n%;NP;~H zSaGhzybh7PlA4DUl|=eSe>!ktG5?n4-}T5QhbI7jm1B5;m}sOeavZ)b@e>u#N*lgz z?W~(eHx(CODH8$ICs11LJkUI9Zq6OMZDb1EL_&1qhu1W?&Hvx=Eb=_IJ!BetL(Ea5 zyo#=q=gAGc zROSL682||F1rLVc{kO90!B3n1yz~an=5u1L)?@1`2tWRyl$L^BGp`#oc$qHm#1N5# z1s_bi^A>-dYQ>X43;uZQf8!_(Z*}XmCi(vbf+rUxc0gtAd`eN%G`!;H=d(w5M4x%_ zL0?6QZZK$$YpT^hqcGxd`^AJ8P5)H?z*>Pz>9P$&fTq5z>t*OLOJS5b=QHT&Z;<1V z&)fP#Gy`8Nr4;B65$9 zL)_dJ5YU7eY0VYG=?)&5!N- zOuD)jjcw6ue>!$ER2JxXDmLAtE0qdW3sfbh@QR;AwPUb#ExDx-`$a8pxoAQsTNl9W z;=k+u^Pte4fXe*ybJqya>=K>f7Io!dyJ7h<KgeOey!y+sj&(XHZK?d~Kfh>q4lEdP^@_ z-=DKXNNhilKES_;kG4Oo$_~-5)s*k>JIYfW-M?H2)X7PeT`jG6&HQUWiK;#-99*dm zti@6d^$bMZEP3suR7|H}UUh!msn$qV*5tzG@5FhH5OcEWYap$ck7`OC>?*G_ zd|H!-fwO$))f+tQCNCi_lcI>EEN3QH>yoQ54_Y|l$a6GNjIW&vnpMAQ?8|o#4%9*m zV*v;Ry(G{1N7?%U(e)8NE@sEq${RvM)~&`W0govKW(UT(=s}7n zvD>Rnb&-GPlg>K4Twk7!r|!CP_KofY^gEu~PR(k>&KZCPz7yl?uwh2LQcG(qq^4+t z&(m^cVKzx8L}>UdaB{l9h64WsPm{ZA;1ADZCg=HHXrNraJ!-4V3Ry3ZlnL*ga9B(w zpSs#wl}T3GtF|?sy1J8gmb7;bF7U7*wSONH%a_^O>FWD+Mtn4PvW$@W{vfF7XF>MU zW~0yGe?IJxezLq*FW;;3!_(uA#kXoGv~&0daoo6;-{jO37V1hNAt)yq;FLtRg3#6` z6J!oK+EJ(1R?_oV=18iGs)*6So+ZE#B3PRP$RwD~Io;OI^j_D0C!h(s|MPYj(EFxz zpnCZ$Fmd{~cg|>lZpIrC{at%pJB=cFJ;=bGrq3Qc71yVgv@6V_MlupM?#=2zG>k#y zf(Bce5r7r?@AcVkQQK#a;jxG%viPPn;`mnYl)pq$$Lyj`{&pm6tGldszl>g{hTOFX zzbp1O&qH`47!hGuFwT4CLPYX0!}&Kb$$a*OP>$_DkeZRXi2b;QTlOfO+@r?bi-?J= zZ;>*W_ZTAY6BUrUe9m|1wnpoB@RC#Hi++)^!jA{&t6myR*WX{c0vr5je}!!vGotE# z+xHbb`|XnNAb4C@E3B>fd28JVH1=_6cn>`m5H{$03fkCAv+@CSX)qJ7+2?{UBk9t8E*CTv7|=LoqhRG?k< z_4hyO>s5ywCuKwE-7#;+l^dm!nntE#}m*GDh77QOTE;GYO~9nTRLSlEb}nlswFry%Z1DO{xhIv&zRy?i^s*?`X)^lk z66h|p1)2}CVU4%}-CTYofW+j)%+U7S0#U8SPwXyQKtzLA5uT`f{PFU*==kl*r+mJv zpz$<@i7OexhY3Nz%3|_E2I3vG^G-xv@iSmzL3WPe)%*a#BK%45xZeflMI0H+Dt*|# z^Zt4FV=2N*8w7W*aQw4;jkcFZ7>KS8@)fyVS4(Gd^{Atl2$vj?fZ8*h(VV9UPyyg# zL;g>=ET_B>UPIX1>=5Q>bB!%xB17R5kR+qPjoRC)u8>p4rjeS+&(vyCBuYRl=<`#X zp&_SEqis|wXh@KKQ3NsIn0ZrB3xrJgS2aLhn|F|y+=ZIp5Le0J8mZCWtKlw_&RSY5 zUnGx+)dAU-?e8^J!ZI5Xdv_e}Z@Nx@!ceGe=PN&MFha1V5-?WC)7qsrtSw|DXWAp{ z?YuTIK?%*X-}tqDR|;J*EAr(aiH0M}9z>tLJ{$&Np(W6mZB@ni^jbwlvY;7Thx~*& zBY*kr_xWQ_L-H4$j;`J>5=f#QAU}6+US8%8OI$@_1+-s)faw#MvvsQ8>Zx& zb5Xxi#C*nu&O^4>%d1%(?2bCSTURyw^Yeq;y@#%n10w&qKQ*0dgNsYVLeKh&jAcuy z7Bri}*}JelY3Ti?PGYHijU?wR8i*ciZY6uB?T+yi72QEV_WVt;x^nnlgY3V`fU9b? zj`xSHUu@XCR0d^H^KG4`-6Z@WmMK3q)kA}g%@%CzaoxmS0|QyqD!?+4Ym2u9& z0&;)!hcHbR7}8`$cPpbV-FODmeir}ukj+R=5|06E+)#ya_%@T@qNw}+-J48O?i~<_ z=mLBBAy97t=B+C(4uTEIz>LW3Tizo3n4<_ zWYZg)z?>{R2p1aLdm0ATdeH$kfpQ0BIe8 z>Dd=y$2VZYC4wyPr;ipzQm$VlS3=@z%TNnPpUOxm`2zY10f!x;g-aDhykXYAQgyt0N3w=6O^%%wtDT)CLCFmQs!~OR<%IE`nh~-Hqj(w$j=-4n9{O{W? z0+t!@Z2bhad9~RO_kt#GqZfr!i^L$Zw2AMHm?IPsS@?i3C~RjKA#L9P6TrU>ceQ-R zAi^?a?e%SrP0!orJvjz%=(%t}{YK|IpR(O|qhF)PNX<#Q{ivqz)C9_n+h^zbN}NuN zU!4S@N4Q{l@i_?G25r56Z(e3#qX%I=Cm+PVYjwLH6y=dA0Vnt!EF6A&JQmiMTj;Hw zfCh4*@3dsHt#?li9>YU@|JiGO;`iuY)nr6PbrQ|A30pf##AI1O!@7cV%~V=0l>tGb zl|KK_m9kK)CAO6Yf&nI@?h;xbvPO*LTnvcK`Uk{78?U=-()5UllU7={EyMAxAkXvg zhp??{D{Y&F#`ho>k5#iMmORm5gkgi|D#zTSQ1lq_o^zeCF@Au_DgPBS)ZJH>99x## zCV(TdCtmj})Yo_Og-6TSr|yPUL}@f$5s1&z=b(I;QA5v%i(X2v+W4T}`;r{hS*ppd zl{QCnQTfte!Mrb56HCY`pOqJNldf3M_ggWM7k))Y<#hZxo3yCy>TiJy@IIuUJk{P| zLMaaEy4~`7L)<9>2)W?9Nvcdd+6su)fZZ+;_U%K}<-1S5pO7Y$<7QVa^tRmm0X-~= z>Fco3erwoJ7U+9HW;=x0^5=B4^!jAS)Wou*brDU0XV*r*_f)Lz7y#I->RDv|Ak^ldYhft$HSzErw(fgf%w&fNeIsU zWwaR(6sw=s8f8C-BnvU3)U-@1Qyzo>1SaEK4MgbeC1?9qqSm%qB_OZ#kD37X1~@;1?y46C?5bziYWR z6K&P7>nVv38{5cLCU+EkeIJ5d*Z2&FV4-V69vMUBio4)QrH#f*g3Y5L>oqcWbERW2 zx-fY$`P!y@m1t6qD*k~AVe^oXcMF}@peBP zerdfKX!qIoirhMCK9jIy{b1njqNN2 zV+v4ief|JseDU^iWT-v!6H>2(mY^ChF&`dRUcC;8Qq#^$wm_QFp-`KNWFY$;`BbUfXo}tubD2H4z*LZ^7TWJ~VbE+Q= zWX7&?0Y3%gD=Os+Qf_nB@#Bg(c57=L+tf#|yU2w==57o9ZAKJCDQ+w=Gn|#47%tG) z6{I#X{6tqvPie!jbK3kHCb2NMS;THiSYz7bO!GK>3rrp>AlJ`T?yASFPovQfiS?FQ zO|DrlUs!?ux!+}!t%93EG}tuws10mB#sadxjV5_Yxe*RTG)-_c4xie@L1>8rMv6kL zJT^~57_FBdq+9c50ANoCSFk6LQwlx56`{3I7a)rveia>&Hz4CKuMshr(^VXJ1%s{zh+vUHMd`Q&8Y%9qF^ z@6k>7p^cWTG*DX>9IuaB|4Y^TxuZ&RJ#pt`lM`s&D4T#uImY{q=H~1utkGsz|HU z!M6G*eckkxM^LAM5+D2D!+Sc@BQJ(ge25V*W#W?SjAxJb8L;x4gSTx&M(JdxZ8WXt zd%?x4Z!CknPiWf4ZX<-^aLkUksKS!dxPKVWI{-#{x5jz^zIV z$*szJECp8&oY=m9-_=2syJi~4`O4yDK3}+drrg>2L#Jv>tu$&>B7}6gY-qoMQ*dNu zrG9`@2KvIIQdJ@ESB`?V*m_BoS6&v?#j#^DvLhf6ICIzeo^;AgJq^qH__=)G32J>( ztLQ`^Gq`w6wMC0AVBl+bz3;W?IF&21^R$jc+Bp6<=@`1CvBlOiWYmV?V920>kVE~_ zzv@gTMdRW@gNe3c9piCK#b3}RrzqmE6uy%BQ4ZM}SA{L-HUhVMWhnvzp_UTm04+q! zTL%jf%~D>NQ9xNw6|1uF&z(1!>nA0}r|NN=G7i{2t#T($6^{Aw$-Q)%vKg6)Q;jqx zuMhNXax*4lCQeJk3Hi8+R%Ub(O6Af+sxEsMCJt!4h!AaO!}Fz>Ntb{PHcQ};p(EZ|9;5P=GUd~*=n4~U9`tF)W`H$%Yf8mT4q4uu;f`u;MS9s z#N6)p=O?SzcF7G8t_IByuP-O_R~{k8w};=nYOXQ&-ZIB@%~@T`{PRU}zxoq3LM7}G zIMH_1jLlpP3IcI54v|kEKPZmiPR<0;*1z0g*lc9VJTha>qDZVaAkNeMrI57ZFvbf6 zERn=+YIDL+-87r#$x!RqF1d#?JuRa9s)g^A`G7jCDybWx=j4j(ukP2pGWM>vluC_P z#FVVXqj@tSqe~ppzv#oHrpSaS%`qr-e{r7Yv_1;uk9J@GX7u)cwXZmhYry{A=;NWB z3nM?sSkz~8aV1OhoKzW+IX?@lgpHb8x~7VM(U|z{%Jrk=rFe%(f9T4HfvA>3#OLFi z#1?>Z9@|M10E>xvezMs(n+`B$4eg)Gr84HQs=-^ZyDt_$U&)B5O@9zufe4+y@>yQh zS-nd4H|yx}c=-*qvQRh9A2T~~!IZy|srMRLr$ zYhMCK0?U2EMkqY)9bxSEX9k|owYHwDNse1q;!X_8I8U9oLCYr=$xzr`_+ECuq_Qn5 zCE_P4pVLcYd4NRqjFDkw|3u$5nW)4-mYl-Pz^x%5VxQEz26g@#n>IcGghdZ>-E&4M zxe{bd-P)L`8mhCtea!DLYGXl~iz;rJu`fMV(%g9l6W4qW-m*YlHM&26WuE# zw6bH-r%wTyTDIkR#$_0X7mffVwJ=Z%%tZTCr6%#pzYpqSIT-#F!5pi@Ozv~0GhAf4 zFSq(rmR9x=L{(0$i=D1lRcfiYzb`**)bq#7R5BZF^_xuB1qK%q(RZw$C{tx|oK0PN zkk{v4jAt*D1A#O#Y54Hn8EX?15PbIBQgU{pLik*DK zFXeKJe*~V9sa$Fqx~S#N%Bi=7|8V@e**$IRvYFmjNu%^1GPp_qI)jOt-qvid)k}X! zVUzbLAP#=f(I7lQAodSRy(x2ZLIn;s%+*)82p{?Er)E(|oQA3#hNje@MbT=4Y;We4 zQCP{J{?V^1^Q2Z5o{;rF&^@L20cZKmvWewHX6#{FoG8e$)F6ubyJ64n+^_k^J0!F3 zH2Vuu^&gD5TJ+ z!l9jpjhm7HYgRNhpa^xAI>d6SICnca-K7+>42`1B_4*UNsWD4=N1QK{_mi&b`kV5j z(*F!h$9puL6g)+?t$D&BEKt8@wPeOwXiXoCKl5wdGWo}mr;3@Egnt6E zYh>?@v`1_$z!R|;fP0KQr>H?B(PaPV--!JDQ>WV9lDl$NiO>J;GQi%79**;@O*j)& z_j~nWW!v{h?`7-(VT;4VXR73+%_hzIB0Z(8M5ib>fCun*u#d1kbH^?np-!x6!Ym*_ za#rL?4px+if=gk235wv<<7}=KtLC!!T684k!K|Aiuli$>)I?85hA>ZxWbuFIV6x{} zvK`SXBGU!blx1j!*!sQ??`Ry`5 za+9(s9`7{(dU)<7&ZrB0-zcsNP5~?kengr(K6p?4oR*r*atTWKK28O#r5fxDeWNwK zt>`9d-oEiu^NzQB80^1ob$pBO)uZ?~t$zM74{$sIgU$1LM?aTwGrkWwu-}c08~Hl_ zw6^jTz(S=Q3X{U%`g7|xS5CB7=cT>PREQqq==Z9q_x`L^h74Az)8vR2xOG3Ci;T+G zLHwHmyso(?>O$1~z}nAYq_cEgmd@piL)tkgAy%9!IE?vEa;b_Z|Q2^7#65C_@%~zm{|Nf7izzb?;$CZYrc|9!I!&1cs_n+- zN}aGLa0wzo@OU|Hu{Gls_Wk>)zpcdw^kS*q_ePK^7Ms^qlqpeTl6JfVLkv-#8X1#j zfUo)Q0?ku?zrm>!!HRNvOC6jRo^y}2U){YTi@ zVyPU7-TW31v#Igvi&*Wk+k+UuYTOZ4sUliiR59O=D*S7M=t!&+hKlGV_U z*OAyM$&p;1i?GQr?|jXD=ESoXrI6&0G#&P8Fb0FOXV57CY7@)f5pF2NGU-88s67Mg z$a6u~F#x3VT`bT=H=m1-ogg5#Go}v@-BJyVRqo2GxnNgJ&dsA#4~8)BNqQ<+{1=Tv zWzOZeOofxw_)0>;obn!hZE5+PsxlJ1FygCF=AFYzIB)|FJ;R6M$6Fh4N+wh3W2ov` z3@=NAhL%uFwpNpv*|Xo<^N19Eem)oJWmDYCcqdQz*hh5GaZ8Pkl|$|i8;i8}Y}3f4 zh&;JM<>7e>MWJT_Usq+rphsCB^M*wG2)QGEGWh)$gJF+3KjZt4=ZeCg0#&~ZuR=$vL;BZ9w!xpakl{_`$>YxT6Cr9%X!*7YvRx4i#r;i*P=M_F z57VjHmR-f_OLG`~=#(z5etFS6twfTVCcxJlxtCozJ&k8Djd(M?dtDx=~KwpDXto?hFi|xG0 zMDaJH%{*FZeSX@-zWt`gaOsvLfIG4D*9gN{J*hhRu~1fvSl!Am5eLH~``nI1gO-me zA1ygU{79XewiTblBwjtA;thZt&Y9gjNcdB&t(O~2T>S681-J^_q6S$Q)bRPf++b(R zRQi~$JQz^`PfH@Dyoh`VouOr-sVX3xXSA4&rG)hItcM5VRq3(vNxNPF*rjLM;sLx# zjj_f6(v(<`m>9cIC5b4}FU6^OMYwn(uSvVK%BFKI#VuJ3-Nh|>OfyAr;?nF>C?poY z-$Vn4^M84z0W6GOw@-8;AK#vnx}@MTKHDU5$<+5D2*VB?1Dr0Bi>w+>@pX%q zvXj-~TA4-afY5_sKkx)IyZ*-UCmaQ-OE<|XZ^JSfsMz30$JrC#rf5v}TB_mMb_(;^BWYl!s>r+lh7G)|{yil(kqU>=z zY)}(ZfjeTkTM?^Xl>@O)W3`I6)+`mmu|?UG{f=?`)w_yaczT! z6g)HdeMcD!A5jPu;YT55+K2M`$q#B!mt_8oo_W)U(|Fhji+^D;*mcCTDH4fw(yL~i zO0H^fv|Uet*S5mNRKQuDcKq)p!<1wc)|WVG^oIn?tT+MO7Y)v@g2ZPgq}7Iv3ojo; zfS3mJ7Ziickbcu+L;xbqPyE3d;BV%c9=$uaxOn#SY7IZGg>f)=NW1?!X0_X~MT$Yz zvivuul_J&FRtmS6`?HznKYf4m?UdU2_B&zDcb`m(Ue0k@$>Z$ZHBWAUYAqp41XL5oTQ^T#XC9yu%mgwZ5LO^pfgDGMn(}_n3C36Yqx^Z9cG&3e$gi z4`9yWpARi;>#9fJpj1pe>zIs{C2BzZ#iJz&2lD;JWut!Q3)ro>;ZiKhHEZ6m*UQW##*(wFw+?M zJ#8&`7}H5}acz(tOHJiLu$DC}A|P6Yh=n`tr*WmMTR%7LJnR2FM@DeL>lw27Ug!OE+!tmY)v45|nD@EtF;#tF@eZkbgQ{S$WqPR#M?WOUH?% zvS9wrcS^G4%Fp7ix#F7&xi{l<&nve?jpB)R> zjlg?6#Yhch#bF!dG_>6RfbxXlP_*(%e z--;g>#M`W~t}^P2-(elenAi7k!3@@2FjH+-j?L+W$ATpbY6^-%@Q4o+A#ni=5w~Ai z1>RKX87i24)(_nK(xE~xJ-3-kpTw3KKTqObGk@6o_;oRE+(I4|z%2cxg5@%vYfj(S zH1Y9HKq5UUdin)5(0K@GqITK##B0x{A%Ojrx3kt9{ot=1agg+>Y^HO;?&B?wS#pSa z8oh9QLA@MmL@bA4+j;AAV{2bz1;FQQ1J(IA*EAQb2a{XDoh^I_Z2Q>l_{x(@{n8PZ z*%2^`?Loc)3ebm-!@nPDV+vL%9xgxL3u6rY_)xUR?mF!4y~%Pa{!~xs{hs3UJ<{VD zUa|5djQBEcxAoP~y6}sg!PwacA19Gd2PckC?SK{{3t8YXw@dfKRv75Xe1a~Ms(CQm z$lwE(&jr(Rni3DGpu|zz6W1eG_N&2|E<3AiG}HEMJWAF40EFnN>keDWLCy)Q^DM|? zpV)vJQOXpIxO?(-=kdynrlm}LfA|QN+PgOpBCfXuQJGnj0u0F%4kVB^sW19o78~qz zjGB^LC@1RHNYeG)EvoVaO)Oy+5tOQb<#GOAY(sE}hks)16~5C`&lRZYRY2AooW^#N}$_%lzACI~=_$y@r@e$7)OI-bpnP z0ahdLpY{U0Ppi8rR*(GA2q^4-MnQ2Wcf-ZrrW7~z#|6hoPQI(Wy_0OS+x#$?b4GRJ z&vrSkU$IZMdP_-i_1-L&Mxs{g;8@gtC5TI+%KT{gDXHB0GxF%=vM#kdEI8r~y!>Sk zOx^*N*1W{jM++`hA$!E|qRT!>Gev#j2<$qczscfP`AAJn^u?hA+1AukBXm|qluBv@ zeEy8jU{}exg65=qkdtFVzEGsxFi7psScyFzO`UF;566gEjfEOp77C>~qSd>u*-^(; zDGHpAfFP5d>+&k?u)(LBt>GrATZBxYb!oZiX9626Pb6qe8(8aaK)(8-#{&&mIc?I+ z2&|_z0I6jH-`|mEfga>{wP)p%&RGC?>c?t_+xQKa^Wj@Zsy2E>^ReJ{_YUG=9!5jR z9ZM#AjMvj=CQ>z@`)PHCfGEt^d<01O;)jQ?ZwEpmdk(#Yg`axI2_Z2ed@3q0AV%cI zj`*KYMxPzr(AhhmwNpXO<5V=v=O_>&fT8GN7n?|a@8hqYCtDjjbgYu>%kmYudAeR- z-y%LVi;7pw^Kd$}f1)vhItfQJUPpI8o{w|g^PFFgQ>Um7plmkbJ<}YWX&HN43_ka< zdWgPVqVjY!apfrkG_}->nRyMw--lEf-I|^|mr@D&q5!mjuIlZNQGP+;?Yj%727%Mp zt)R(R^!(FA)u%$Vu9D8K%!Wh#`?uUr7{$tI;1>h#(l)r_@SvNjOb{?ZFCD(4FYs~% zwOFi~Hy=Nad+s1*k~J5L;+Aix?PM$DfNo~qrn@ChP#pEMmvpsU-;MM?bzVqcfOmi? z`v~ZpgLm>YF*ejWH9CwTHrJUbEyIlf$Tlm&BhpA~P+YY}4dk|iPtL?m3Us}gt6KaEor1`RZYr?V`tlIR_?h#DGJ*Nb|fKtgM22;$T7s z!gePw%LxD5;@h ze?^1edJ5`FhhbeemV{3gv5*-bydW2M&dMj>uw2|g1&FlhS?RXXK0?v6D9s7jOT;cw zr(Uxu$?EOhg4q9r+0O(8iLE8$!1-D)8GSt6ELp=uMBz1D4pmKC4y|KfCKu^E+?skz zXmn=bB1{vgQ9%Vg3@H)YytE^*<_9AR@dPodB4 zf+R>~^@`GA&r`J0?w)c-!)_(Z;N0V-gjI)kjeT2O3l%1+tl?5!9tZy7<)G0+`1AN+ zwTmYGF<5=&&EcccY?v>{!zB~*=q$fw`O#H=ftzB$=Jfu<&mG6|sF??gU!T{BD$hPI zH9@V8TJJWZ`fo}Cs8@Z@qWw~|?PL^;dZ<3#Wr27?q9E*IMoyItnNcpWP8gT-fZ*lM zVvpCVJoUJ82gYna^r$A&RtIUpM+#w};*PAOI?8Q9%%>)2mY9ib;7siH>(w3qtclk{ zCI9wXsz=Bl<;V_|_V)Vuag`f1wLb-@kg>W2jynkgh_pXtsYM+K9+FrUJ5It+H^V_b z&8>2ANvt4+3e=5%iPP&6^9y7xDguIZpt;JMU#?-xC3Ydk>{C~)FL~dMUQ%H+#z63j z>%=EAv0iX+1U1eEpjWodOU1GDS)z*$0Fy~FZX(Jl zyoWwCy1X(!>%)MZr!yZ;nc?}BNAMG2zwx-2NxNvrG98hLn^L5}(S58)(G+4daZ_$G zj0Z3kN^2aKvXnuki)pMKL*|;n%Kb%1hDMe^GXL(ynFw)Ak_zEYrQgZgS`d!sOE~{b z(oqN%4B~qtWp>a$*YskLi*459o|peY00SJLTPwVC1@~!P#z)s+rw$94C@mPdK(0K= z>yGWRzSxhFM?f_I|B;g3PYe9T?C%svP?_6ejD-M*+_0S4;xr$NgKeAb6*krJ};kI4vZ^p@!TZ+zu z?AK=-ogrOTgyS_KPrFS0$J9SGKtBg5a*lF3bJo*ue*`(zF3+H`8Rd{^s^7uxR1=Lr zq1s1Om7kN@-9Dt+>L(|ChO6p-%hom7u4V2c$WL9(gE$ifJtdF$ywJMS>8|*@vG>ed zGuFiaY*jKbM_;=R?V;~+;3Ac)L+fKfq|oS}_8F*c7NOZrqwn2Trqv&O_3@q3I}@)% z%08k-lk5-XsN*ef0~pe{0S>4{Iom4bI8w{o5htQ@7n%(U12px!FOXELvZy`^t^}p- zfmNA|h?H_s1=1vHW4zsl3XS+m=dx7~R@3*9O%ASN1PYm;ff5UYpB}11I{n@R9aYJt zBE^)DR(BxCFg+7*+C=-rCY(PpCv~fh?)wEWL&JANctzuQ9F{-~%9c~d>xz4(CU0`c zr{rMjg{3?SF2cvO-Vrl%f*wxa()CcQ`Z^}R;Fyq0G{$(dtA7aBF563)o4;!u`3q53 z^427~1wr~`iry=JeU8PI94~C!F87-qA!>7g3?bXTsd@Ioj`|&Z7c}Kl16;rX_emjm zq4|Eh8FD*IAPw(u&`C!j;4lZixQ_ALx@bYH`QZtkGbD1*3R@5IBQPe-Hmv*IZ`}-J z4k?p)?BStQuDVaQ5*Mnf$JK6P-`Scl21Oxn`QEW(1k*?YmL)0@5)cJ1VHjBnlVy_M zGL${}$27PIm9qhPtM8(T1WyDOCUzPO2wO4kF*me3D%?*gzW)haAM|K5WcF#}cnW^- zD9rz1CwW`q2HE!terO!wD?eUytY9nu<-5Ulw)=oolaoyTlkcJJ{I+lyn%mjc01>+f z{9bfTaXjw+y|2T6Ay9cvben8hx_bkEDakN0JTE}yvG`v|_CJX~z~K_q}v z&h;$D;97eMG`+2CWR2%9CA^yLjU**DZ?|jT59W~{mxRt!3d7P8NTOXxM5eTJN@JK; zpnow?+d#cd&x-5aH$m+HnG4^(Dtl#fp{6=^e|t_C4DW*k{gn%DP&ZT(tvywf{3m;R2l-F9PvhZ<4p;B4{zgR$xm z7@dTjC{*lgYY%ieI&6nUC)J2Pf6Oksd@<=`qMXIQHS6Vsk&k*Cbtq2zM_1EMR^Scx zB;z1bf8RyNi`gQ4mH|#TjWe?tk)x-k%d8cGgOyK_6Di3WVZtJg6nR*;-l4*Rt-Ja7 zj9o_y2@G~pr0D?c$_&%LGso~tHIIFt>B?Hs+#(H^*%>5Qd!_VED<2+TSS>2DabUcWz@UDIPTvp)5?y3tpTN4$5VBIScP^M44T0 z#^lIf{m~pyhK(McJ|l)+ujhfBMFbzKoCcE&1TNgDcG7;2e=#2TwovE8`QGM2%Bp&e zzg;(L*5u*cO_$kt$nAX0XIVR=;d;WWG$g`7nJY07(4Q9Wqwkl)!VZl%{xF@;lqcY4+`?#3ZbD@9G!^up%=cyxqM#9zI+Zp|-uX)YwlWl)^{bXyUosLZX5_(jet_lQ zE|_D~PBbgc&jvjS8ZTbItn{jKgP25i*Op(Qb>=@X1RMU@dZ;b))Kw;CDj`!@}v|>lJYi2>H_*fz6WL;zcr%`pfLa zn+bY@QnvioX2HDh(Wp+|Uqu}6Y;h0S04t=1nMRm9}xCf1`lb0XVWK_l1VZ^R< z1RiR#C0B2GSNJF-%&LI5*(ffcqg;hFZ$zk>RX)?%?Gg64w!$gL*5NREgmIcF`1Bx> zcPodK6Lo<^p>YwhBv|1r@({B0@bOtyJ=$Vl$|=)LZd5E>qwa{)SgTALT*YC zeSp@S@L35pixLYpex`6ZJh@QWOSkGV@xbt8Ua9fI@m_S4BVMeg)6>v$zUr#C<_?7y zCFotX{3@%dnK0+To=in1LzEhDl{5HXY5DQ6JRGTs3Cw!=ByKF*@gC z0T^#NF4B{D%HR|+Up9Ox_tq=6 z3YQ#$?G&d)RIjEuf_h>`!W}Bto5jj2)k?c#A&tZw7^$j2jMDnaf(7A1_~m@1k-ysm z)>0J@=aTngr6qCf9n7a;iU{lqJ}#4?8*RH&x}Imjz& zJkARD^+HnYOWkes0GRWzpg448Ne4;A)7LT@Owuc_cZez*&uo&$V7+okTy}@J^+@UT z=e5kHr(#%=f4R5F{etc7G}5z9$&sjuElPd`JSNYgXh`CVsMBe=7moNhtf+!{5Cw{tjsCN_{(-Ok^clN_a8 z2)b|&Ju`(oAm8C#X$q~3(+#Y!%n)-Wl*`2S@Tg8xE#QjtZc|>Xq2`v0Q<(4r;y%ee zxM|F6xm$Jdfvl-V4tU5V2Y1a)xfyx%mf71R+9?x$1$2OKPd*3Ay!W%8eO7l`0oPU+ zzdGS%I<2ksfQW~)?ea@C4K-h8KBf4xycjoG&#iW3XPpOcPzLHe)zmi?!tZ6?n{EXq zID2qZT$3c{t(ZfA6VV?ZH}@b)W%zdM9(tx=rjAG+&OPJ~HsSME_2>?vC{u!?7M81t z9&cs{OSm`H&z---1;)J?AR^jvO{@l}p5_N>SLtBm_gODGo?_<%4rd1srxgc-r_G4r z?jFKGF*3zfG%W>_(xBbX3LT+*?M?nTc(Y-W`ZKpT>eB9eIYi9czEG^4ZB+ukprSjI zT#J$5t|VLvb%T0qs{_Fv;enPn?p0A)SDv73gZkj$P7syn^>-MHnu2$;W3F|f0X+&- z{jGd2a^faG&P{pYE}^#+w;)=8Q&7gk`0ix0xeeVv)GAey&^Uu_^1nh1eG@mHaeHG3 z2pRg!i^_sV+2C_k+ZU@K2w$c;yQi(hiNU5p_U8|=4_n6=G}6BVro;FY8_d?tK8Wp= z1FZK0x9knGi-|YQ?>EzXy{sXPG_wnHd>>D-AuXEOF)TA)!W9BJmRU|eHAs#0)m$ld zInGQ36NV;nGZEuEaL8VQ%L?PNh*>*!+Ng)rY{PE>4+B00g0sQ}%Cb+Mb!d_{EZ`CY z1-+L|v5a4Vdy2VU-kH>c57F#DYR}4)I2e}hO_CJ&vQ8Z8vL-JBU_@%zZHzaNSk-En z`M`>hP1!iIH4&;xZbF&*{`Rbxg$W40-RbI30qmZuZ|pB@n(!*PcpBTq=oduI#xDjG zxC}#0BIV)&XH(d`QVhr0PRpf>!P&$~jPppJ)_y4y+oznrBXssTaN?p*XFb)mdUqUr z1~Ac#;6#63vV+|-8n8@*yX44qRmQ?9=|iZ z`>3V+#vr!2AvUGxQ* z3wgogc-J563tgWv%$^t#&0F4*Nh6M^u0dlZ2jQa^Gb6vd&Ar-VQkfyqd*Bn^;pZJX zJEiB79as{}#tP}--zWmmtlK=PleM1%uRcQS0jS{wrA^Yl&4HVgXRwkoRz?zaJg1~} zZA2LkKc2)r&ayvc8i`jCOiwr|B=a$!(A@9Y9de&Tfi$M`6w^IE!jrA z$cTx34mJ$`DD{Xs#%V)0g~w=xo;L{JB~%^Fs@ok z7l=c87T)rw>Mn;|QcMz2F&$K_55aO2BsdTXg_D#?2Q``~ z6ok6Y#0kgf1v@#lN68&GOyEjFYZPz_TDP&$*USb9C$Ah)|BtAzjEXB*x*Z7a?yf-s zL4y-4NN{(z;O;KLg1bAxHE3`rxDM{F!DWDXL+*F)>$T?mm_KKq>gq1rT|EcK;_FwL zkgoVnjDJGq0_O2jAyV|-xpj9h(T@z|+TL=Jr$=z4uSH<n{B5kDL|G zQSlA3$+KBvLa~W;PoS{^dmjn!-Oh%+9URX$oMx|VXEDKx;J4$8sVvmjA)tq8Q#sNQ z*P^?dYxfD>Kxd6XM~~P=amgvhL+7(~Zz0}CpU+>Glz2YhyjY&MlzrJ?ig6l~twvke z?fyc12Hk^*m5o=2VTt7N)=4y`1!mbq@v6R{VN>ylH!+(397Krb z0bp9dQGGUMEU!?#Sfo@#DLCf^YFxg_Or)vAiqrd2)G**Vs>e=e^I*|MGiQMBT zhh0igP;A>$j}UI;^slei)_`hMzS^uIwVQ-~{uwMXg+5k|m<-^di~> zm!zZm>)qZ_$u9D09IxCD75KAGgGZ+T--%c@I^;syNry3DylSA$yk=F}+f`w&?mQy< zSwqYDZfWT{pGSwrI!bm4o%F_1v|vBP)4+|_Z65&6YP@p!P|9-axD9JV67TOcTeJ=O zRI(yx;uCsWe$;utTSC>ovLAh)yK|A=2&oBdebiUuww|4Gsu*SOiIIUj`FJkbb|J}Y zPN#ub0nNgn4W(?Zo+n=#(I~njn%tk9gLj6QoyM$&ieY9gbuzs~T78(ofLyJ!=gbf+ zVM`lZ-1`-k(iHS>@pTU#JhsHp5|o5~!IYyHLeX2)<);#DV}#>Sz7|7@Im$i>&c!nC0zVC&+JU$|XeFg(*365cTk2DH&huhBcEJlOI%-;z>XUH!;lHUS~cPEL*` zX{IRUn`Lfx&tR_93)9Z{E_tO8-lh_YP1eM{OfP@pI}ytrHOZSi$*~3uOqpe39IY|V zR8AiNsW)D$wZ6xgE)dc#BRq>Hd0Mjpp_-y)*CYogB=nGnEi{?gg0@I{A20s`!KM_f z?;^O4!i4UepQ3x4oF>Kntt?`M{2kC_ZLJ+-Vc>fr2&OyGOt3VbNDLP6^X@x%pwvak zsZagmEnrN5^NjZlzi5YCvX==pznl}R08_XPC*#o*ZTq;T!5Jz)Jj~v{; z44hCZEG|qDB#*gzsCE+Wb$lx^7@VqP-#X5jm^-;1>XCDZ=&DE5ia?K!szkgKTL;t1 z^_2!lE~4V)-aiYJ$4Fu|#I+SyCr!G^K=q}G&KF352@nZvmt=Lb@p@0uMVrX}^>^Lo zXghI&31&Gp%WO+_`zw9yKNk!|ADqrpE0v((<(a$RX7ELO(I+#$M=^5Oq2#D^TJRVQ z_Eo`Qqc(-rR)!j-LTF@jFE>Zf-#w4{4&T0+PjI(5dR@qN%u8U$nx+9ht-D6E`^Hy3}%H$%$0WWsvwAq`}w;o{Xf z94MLA`q4YubX1fOIOBxB{F!2fV!(Z9IY}r=#F@0#zJHj>w}k~y%0BSONvOA!%lt6u zh4M=c-xcWzuH?Mt8N5xZP}A=Kp;wbZKHW)`g94$UpCtHBew&)QnmhznL(nlhddHn` z@8;O)DPpiu!b53vU5YGkJlS0*D<>~qNzk11^YcJyvzF&CI`|Yqj?WJ>%-L)=T+CNL z=;>(A9CEQna?3zTs~6(NHhR150ocYi1_CuCi9;5{_z^{99_9sj%D(p9YzB=}Pux_4 z_itsMw<4Tj4AQAi<+~HUKgLT>epkCH3S0+0kXUGOD2pPk`r@|A`wzj>a*r#A+xp10 zIKMV`H1A}XnMrb=VKOM5hy7Ma?>5Ifj*X-B3MSned#_%NP9mv0q2REt)6)xVKccf8X-1 z2N(So$Ct7YI}u!9nI82HgV5oIVWlWG5YviOoyf^^6B9Yl2tXrU{H?pLD;E#NBwMJF zno9~nD|xvVhWebnFjD;eaq1P@PejhEd<#}3phx^*dqOtUQP9twuO!{0JHENENm>^C z;SXB6Gc#Hls4$5=YBR~p6ggG2su-o=Gp_X3DfM-a4P6IH=M z-e-^w7$9xt{U6>ha~)7aK8X#&XxIYOral4A7@+%FYxO)|M|rQIhiw9ZXGsG#$sVxP z#j~+lYdJ@k8&?o~wLunqH3zmN(F(dW&Byoz6aq;^k;N~Lp988KdtqvErXVgYwh9Y zZfKEYKfanh-0zkiaDl6@E?nf>;;zs4o74Eg2RuMcB% zXko8`Z;xa}QBiU#2zsFC*Wnwa=l+T`wVy+1Lu@{nV@v+`ErU0{0RApX@>jzq`9-Nb zo6F1TSYH8n*!_Bb-aIz<%Q4V)_v(QV7~bd}DwE%u+O-w_9<2M{J+)qk zzLMy#8vf}dBZM`1>ULQtkDla0ofFD6jCnnG_-K+@d5?{yc<>n;-cwd=I zwI7eQ!Q^e(y()32u+Qtp}AmCWf2fLi-O)>P#GPVdL*!!nz$NlG) zlSFqr0pSPTo$gFBY>s>Wf}#7E+XJU-N@EHCoR2;+k9p|@U4;kGbfy4e? zS~yEL{9_J^ueJ9!#J>pnIOd1GwQn$Gbh$d`_B3692TgSBL1RyXmam;-KB=Sss z#3@q#LbkIw&!vC8j}BnyV~xoD3>b^pp7a*_7A)J(jW)U_58C(dQ?L8?(-jtIt{KOE>Q3iD_tV=v7eDueog>HQA}7 z@Wj3)k;#lv+#|>Ti8GFupe^Z{z^1aR4Ns_$lx5yZjtXFdIXj>nBw!gMQbMGcLzb_p2Bb{rk}xm9!{ z)i@s&r$)xUxT@a?4=Fr9#O@hV!V^s72wDfibs{{+lfUNs^bA3@9$?RH?M$0Ir2}7Y z22GxNM*X|>uNA7_*<{{TywE;Xs=SWxnfODlICf9(?1|ZtM8^#C@(}RN&G9;B@VZ;F zxOO5tS!nJOgrC=c-o{_4p8<4sPAJDaaI<=^OoD%t2<+B9C`>nZ-n!_Ay_2%h8Wc(U zq}$cHF^XQjL5=!Z=zg_<8_wVEnatnC_fik0=#J}z?bvamgRa`V`1UjusX zyybSD+o-r(zjJ( z|C1@OTDPmI^;%ij+3#gi=$=Hd!!I`WsyQF*D}358b1DJl z^~H1iV1yXxufd%ST*>qAyKz4_^?Kc$&C1TFW-~J+9jU$N|A#Hhq?piX%7`GXUZ?!{|dHUZqyo z%*%*hK~hV-Mk%)t6KmCK=W+Q3J)j#I|L&v32|?$_T&pXj3G%G`s-=2^mp`fTp@@LD z@#T39`)8FXwMO8sU+zvh%Gsqz#BwLGaWd`~x8=4UK&@6XQZ9L=VZx;7(NKja6uaR1 z$w%NelPJ*+69NU`RIs)i+A#K8WhGyHVPjoJU8~GA9AS+~0~%Iw&~OA{=Py-|zh&a} z>3A6^=G#?E)QQ^1{5~D4CHCxH(@6!(MgYJezeVAc;pxlXKRkf<%RAJZZVS(2dDc>9 zL)s);W=`L7X^<0kV3~tFQX^~- z&_Dpdd-M>weNz2UhVO-1$9ey&P_cU4l(YnkH0iE_q)Eg4-B~yvFQO?nQTANv`+{Cc zOdA^HkgT&5vO^;dTnLVXXpkPZGA9M>KTO11Ctwc>-o$)Nv8&nhC*de^ua_EJDywL@ z0bQL$)+*%?tNGzPHiXtanz2^%{S1O~YJ8KnC#j*E6fHRvSVsf^-a8l!0G^0tSC*c1 znZ?zK4juZQU1@QFAOGb#ij{Y9lh%a$?D=oRJ}b)xmS4|Fu<^>Y%Jkg3&%B<`d`lwO zE&xDF+$xh?+>#Z_Jo!IRhIsfqnvS$mGo~^fudISXU;D1L_eAms5ofdoMySG1m@=rL znC&ddF}`4Zn2*V17)igZ6{Ehbt1ZAPr;^qO(mF5f%FP7;YH=vu9(>4^UtAW&%TfDF znv}XGo;NcJB1TmvWhv2bn8lkAd@q?1zXv8&C|l;hL#EK@ z;TYYn8tEUfZf0YP0pJmRBw)NEtYmMQ+hk7(w~V z5xQ}Su3UYs$X8NNKon@JFGK$w07&^Ktw00bUKL* zj!9=2eVi_kMyYz2ux#l0)Dq!O(ss5=2>{&vz{dm_LebRd+Pq(q)vJh8toZ0sZzw9! zSj0})zhuTXt$;ID!?8aSrKNuqz1}>Ax-vCrZrjg#w+;VC5ek4I7(?DZ^be4sj&bBn zSn#0wvYC-ydd-E}!Eoo|IRm->u&jH){e*|L~xOYJe1LH8D;LMbk9 zNrISU^pw~|E)-z#lVKoiH&v+?o{Uq9@`7SJXwa^LZS`r_%MnLqLU)8s3LT@dgh=1FV#R=TeEGX0k zJL^*31S?K_r*SPt;9bbu(U~c#CKIKvrD

@BLnLi!hfIXCvaYpcN+sSoBwfg6_t0 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 V<(DadHDw9~G=4{tr1G`R4!t literal 272988 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%0AKvdsNc5Mq>U!c4PdoFXE8#W|l%*xUgF; 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 Ss7u^XQCHDXE?0c=>VE)uh~pyw From 99fccbbffc7e1040a3f3ca1df0813a09e6cc4ffb Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Thu, 1 Aug 2024 12:05:14 +0900 Subject: [PATCH 17/88] updated archival note (#20927) Update archive notice on deployment guides. --- articles/deploy-fleet-on-aws-ecs.md | 2 +- articles/deploy-fleet-on-aws-with-terraform.md | 2 +- articles/deploy-fleet-on-centos.md | 2 +- articles/deploy-fleet-on-cloudgov.md | 2 +- articles/deploy-fleet-on-hetzner-cloud.md | 2 +- articles/deploy-fleet-on-kubernetes.md | 2 +- articles/deploy-fleet-on-render.md | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/articles/deploy-fleet-on-aws-ecs.md b/articles/deploy-fleet-on-aws-ecs.md index ac9428865b..38b802fb9b 100644 --- a/articles/deploy-fleet-on-aws-ecs.md +++ b/articles/deploy-fleet-on-aws-ecs.md @@ -1,6 +1,6 @@ # Deploy Fleet on AWS ECS -> **This article was archived on May 16, 2024,** and may be outdated. Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for our recommended deployment method. +> **This article was archived on May 16, 2024.** Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for the most up to date deployment method. ![Deploy Fleet on AWS ECS](../website/assets/images/articles/deploy-fleet-on-aws-ecs-800x450@2x.png) diff --git a/articles/deploy-fleet-on-aws-with-terraform.md b/articles/deploy-fleet-on-aws-with-terraform.md index 6853032a50..38f8de9b95 100644 --- a/articles/deploy-fleet-on-aws-with-terraform.md +++ b/articles/deploy-fleet-on-aws-with-terraform.md @@ -1,6 +1,6 @@ # Deploy Fleet on AWS with Terraform -> **This article was archived on May 16, 2024,** and may be outdated. Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for our recommended deployment method. +> **This article was archived on May 16, 2024.** Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for the most up to date deployment method. ![Deploy Fleet on AWS ECS](../website/assets/images/articles/deploy-fleet-on-aws-with-terraform-800x450@2x.png) diff --git a/articles/deploy-fleet-on-centos.md b/articles/deploy-fleet-on-centos.md index b832e0f4f1..f9439d5773 100644 --- a/articles/deploy-fleet-on-centos.md +++ b/articles/deploy-fleet-on-centos.md @@ -1,6 +1,6 @@ # Deploy Fleet on CentOS -> **This article was archived on May 16, 2024,** and may be outdated. Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for our recommended deployment method. +> **This article was archived on May 16, 2024.** Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for the most up to date deployment method. ![Deploy Fleet on CentOS](../website/assets/images/articles/deploy-fleet-on-centos-800x450@2x.png) diff --git a/articles/deploy-fleet-on-cloudgov.md b/articles/deploy-fleet-on-cloudgov.md index 5e5e2b1644..c075ab6c9b 100644 --- a/articles/deploy-fleet-on-cloudgov.md +++ b/articles/deploy-fleet-on-cloudgov.md @@ -1,6 +1,6 @@ # Deploy Fleet on Cloud.gov (Cloud Foundry) -> **This article was archived on May 16, 2024,** and may be outdated. Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for our recommended deployment method. +> **This article was archived on May 16, 2024.** Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for the most up to date deployment method. ![Deploy Fleet on Cloud.gov](../website/assets/images/articles/deploy-fleet-on-cloudgov-800x450@2x.png) diff --git a/articles/deploy-fleet-on-hetzner-cloud.md b/articles/deploy-fleet-on-hetzner-cloud.md index a7cd76f1c4..ec6c7da9a9 100644 --- a/articles/deploy-fleet-on-hetzner-cloud.md +++ b/articles/deploy-fleet-on-hetzner-cloud.md @@ -1,6 +1,6 @@ # Deploy Fleet on Hetzner Cloud -> **This article was archived on May 16, 2024,** and may be outdated. Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for our recommended deployment method. +> **This article was archived on May 16, 2024.** Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for the most up to date deployment method. ![Deploy Fleet on Hetzner Cloud](../website/assets/images/articles/deploy-fleet-on-hetzner-cloud-800x450@2x.png) diff --git a/articles/deploy-fleet-on-kubernetes.md b/articles/deploy-fleet-on-kubernetes.md index ea85bbb07d..5e5144efc5 100644 --- a/articles/deploy-fleet-on-kubernetes.md +++ b/articles/deploy-fleet-on-kubernetes.md @@ -1,6 +1,6 @@ # Deploy Fleet on Kubernetes -> **This article was archived on May 16, 2024,** and may be outdated. Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for our recommended deployment method. +> **This article was archived on May 16, 2024.** Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for the most up to date deployment method. ![Deploy Fleet on Kubernetes](../website/assets/images/articles/deploy-fleet-on-kubernetes-800x450@2x.png) diff --git a/articles/deploy-fleet-on-render.md b/articles/deploy-fleet-on-render.md index 1b5ba740b9..703d872cf6 100644 --- a/articles/deploy-fleet-on-render.md +++ b/articles/deploy-fleet-on-render.md @@ -1,6 +1,6 @@ # Deploy Fleet on Render -> **This article was archived on May 16, 2024,** and may be outdated. Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for our recommended deployment method. +> **This article was archived on May 16, 2024.** Check out [Deploy Fleet](https://fleetdm.com/docs/deploy/deploy-fleet) for the most up to date deployment method. ![Deploy Fleet on Render](../website/assets/images/articles/deploy-fleet-on-render-800x450@2x.png) From 0b2369b9638b9ee674913eb1708460a5ba34c057 Mon Sep 17 00:00:00 2001 From: Victor Lyuboslavsky Date: Thu, 1 Aug 2024 07:42:38 +0200 Subject: [PATCH 18/88] Added null checks to GoogleCalendarLowLevelAPI (#20887) # Checklist for submitter Fixing unreleased bug for #19352 - [x] Manual QA for all new/changed functionality --- ee/server/calendar/google_calendar.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ee/server/calendar/google_calendar.go b/ee/server/calendar/google_calendar.go index 713ea9af52..73c47d5cde 100644 --- a/ee/server/calendar/google_calendar.go +++ b/ee/server/calendar/google_calendar.go @@ -144,6 +144,9 @@ func adjustEmail(email string) string { func (lowLevelAPI *GoogleCalendarLowLevelAPI) GetSetting(name string) (*calendar.Setting, error) { result, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Settings == nil { + return nil, errors.New("calendar service or settings not initialized") + } return lowLevelAPI.service.Settings.Get(name).Do() }, ) @@ -153,6 +156,9 @@ func (lowLevelAPI *GoogleCalendarLowLevelAPI) GetSetting(name string) (*calendar func (lowLevelAPI *GoogleCalendarLowLevelAPI) CreateEvent(event *calendar.Event) (*calendar.Event, error) { result, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Events == nil { + return nil, errors.New("calendar service or events not initialized (CreateEvent)") + } return lowLevelAPI.service.Events.Insert(calendarID, event).Do() }, ) @@ -162,6 +168,9 @@ func (lowLevelAPI *GoogleCalendarLowLevelAPI) CreateEvent(event *calendar.Event) func (lowLevelAPI *GoogleCalendarLowLevelAPI) UpdateEvent(event *calendar.Event) (*calendar.Event, error) { result, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Events == nil { + return nil, errors.New("calendar service or events not initialized (UpdateEvent)") + } return lowLevelAPI.service.Events.Update(calendarID, event.Id, event).Do() }, ) @@ -171,6 +180,9 @@ func (lowLevelAPI *GoogleCalendarLowLevelAPI) UpdateEvent(event *calendar.Event) func (lowLevelAPI *GoogleCalendarLowLevelAPI) GetEvent(id, eTag string) (*calendar.Event, error) { result, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Events == nil { + return nil, errors.New("calendar service or events not initialized (GetEvent)") + } return lowLevelAPI.service.Events.Get(calendarID, id).IfNoneMatch(eTag).Do() }, ) @@ -180,6 +192,9 @@ func (lowLevelAPI *GoogleCalendarLowLevelAPI) GetEvent(id, eTag string) (*calend func (lowLevelAPI *GoogleCalendarLowLevelAPI) ListEvents(timeMin, timeMax string) (*calendar.Events, error) { result, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Events == nil { + return nil, errors.New("calendar service or events not initialized (ListEvents)") + } // Default maximum number of events returned is 250, which should be sufficient for most calendars. return lowLevelAPI.service.Events.List(calendarID). EventTypes("default"). @@ -197,6 +212,9 @@ func (lowLevelAPI *GoogleCalendarLowLevelAPI) ListEvents(timeMin, timeMax string func (lowLevelAPI *GoogleCalendarLowLevelAPI) DeleteEvent(id string) error { _, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Events == nil { + return nil, errors.New("calendar service or events not initialized (DeleteEvent)") + } return nil, lowLevelAPI.service.Events.Delete(calendarID, id).Do() }, ) @@ -206,6 +224,9 @@ func (lowLevelAPI *GoogleCalendarLowLevelAPI) DeleteEvent(id string) error { func (lowLevelAPI *GoogleCalendarLowLevelAPI) Watch(eventUUID string, channelID string, ttl uint64) (resourceID string, err error) { resp, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Events == nil { + return nil, errors.New("calendar service or events not initialized (Watch)") + } return lowLevelAPI.service.Events.Watch(calendarID, &calendar.Channel{ Id: channelID, // channelID is also used for authentication -- it should be a random value Type: "web_hook", @@ -226,6 +247,9 @@ func (lowLevelAPI *GoogleCalendarLowLevelAPI) Watch(eventUUID string, channelID func (lowLevelAPI *GoogleCalendarLowLevelAPI) Stop(channelID string, resourceID string) error { _, err := lowLevelAPI.withRetry( func() (any, error) { + if lowLevelAPI.service == nil || lowLevelAPI.service.Channels == nil { + return nil, errors.New("calendar service or channels not initialized (Stop)") + } return nil, lowLevelAPI.service.Channels.Stop(&calendar.Channel{ Id: channelID, ResourceId: resourceID, From 1dbdb57d7687ff54c51a85d9a9f1123bf0f8d5dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 09:17:15 -0300 Subject: [PATCH 19/88] Bump google.golang.org/grpc from 1.64.0 to 1.64.1 (#20852) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.64.1.

Release notes

Sourced from google.golang.org/grpc's releases.

Release 1.64.1

Dependencies

  • Update x/net/http2 to address CVE-2023-45288 (#7352)
  • metadata: remove String method from MD to make printing consistent (#7374)
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/grpc&package-manager=go_modules&previous-version=1.64.0&new-version=1.64.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/fleetdm/fleet/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f08fad8627..f735a2244b 100644 --- a/go.mod +++ b/go.mod @@ -126,7 +126,7 @@ require ( golang.org/x/text v0.16.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d google.golang.org/api v0.169.0 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.64.1 gopkg.in/guregu/null.v3 v3.5.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 diff --git a/go.sum b/go.sum index f0d7931bb3..7eceaae2aa 100644 --- a/go.sum +++ b/go.sum @@ -1755,8 +1755,8 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From feb32a274a9e3424cee70e68b9af5f3d7853652b Mon Sep 17 00:00:00 2001 From: Dante Catalfamo <43040593+dantecatalfamo@users.noreply.github.com> Date: Thu, 1 Aug 2024 10:27:17 -0400 Subject: [PATCH 20/88] Linux Mask `systemd-user-sessions` (#20877) #20370 Part 2 to #20699. Apparently `systemd` now automatically deletes `/etc/nologin` on startup. In the previous PR, rebooting the machine would remove the nologin file and allow users to login. This PR masks the service that performs the deletion, preventing it from running. The message displayed to the user will be what is specified in [this file](https://github.com/systemd/systemd/blob/7767896d127264f660e1e8a714e5cd760840921f/tmpfiles.d/systemd-nologin.conf#L10). It's not the best, but I suspect messing with too many systemd files could come back to bite us in the future if things change, so I'll leave it as-is. --- ee/server/service/embedded_scripts/linux_lock.sh | 8 +++++++- ee/server/service/embedded_scripts/linux_unlock.sh | 9 ++++++++- scripts/mdm/linux/linux-lock.sh | 8 +++++++- scripts/mdm/linux/linux-unlock.sh | 9 ++++++++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/ee/server/service/embedded_scripts/linux_lock.sh b/ee/server/service/embedded_scripts/linux_lock.sh index f6961f3b42..227b05fd73 100644 --- a/ee/server/service/embedded_scripts/linux_lock.sh +++ b/ee/server/service/embedded_scripts/linux_lock.sh @@ -38,6 +38,12 @@ for user in $logged_in; do done # Create the pam_nologin file -touch /etc/nologin +echo "Locked by administrator" > /etc/nologin + +# Disable systemd-user-sessions, a service that deletes /etc/nologin +if [ -f /usr/lib/systemd/system/systemd-user-sessions.service ]; then + systemctl mask systemd-user-sessions + systemctl daemon-reload +fi echo "All non-root users have been logged out and their accounts locked." diff --git a/ee/server/service/embedded_scripts/linux_unlock.sh b/ee/server/service/embedded_scripts/linux_unlock.sh index b9d0554f7a..6e6880c542 100644 --- a/ee/server/service/embedded_scripts/linux_unlock.sh +++ b/ee/server/service/embedded_scripts/linux_unlock.sh @@ -21,4 +21,11 @@ do done # Remove the pam_nologin file -rm /etc/nologin +[ -f /etc/nologin ] && rm /etc/nologin + +# Enable systemd-user-sessions, a service that deletes /etc/nologin +if [ -f /usr/lib/systemd/system/systemd-user-sessions.service ]; then + systemctl unmask systemd-user-sessions + systemctl daemon-reload + /usr/lib/systemd/systemd-user-sessions start +fi diff --git a/scripts/mdm/linux/linux-lock.sh b/scripts/mdm/linux/linux-lock.sh index f6961f3b42..227b05fd73 100644 --- a/scripts/mdm/linux/linux-lock.sh +++ b/scripts/mdm/linux/linux-lock.sh @@ -38,6 +38,12 @@ for user in $logged_in; do done # Create the pam_nologin file -touch /etc/nologin +echo "Locked by administrator" > /etc/nologin + +# Disable systemd-user-sessions, a service that deletes /etc/nologin +if [ -f /usr/lib/systemd/system/systemd-user-sessions.service ]; then + systemctl mask systemd-user-sessions + systemctl daemon-reload +fi echo "All non-root users have been logged out and their accounts locked." diff --git a/scripts/mdm/linux/linux-unlock.sh b/scripts/mdm/linux/linux-unlock.sh index b9d0554f7a..6e6880c542 100644 --- a/scripts/mdm/linux/linux-unlock.sh +++ b/scripts/mdm/linux/linux-unlock.sh @@ -21,4 +21,11 @@ do done # Remove the pam_nologin file -rm /etc/nologin +[ -f /etc/nologin ] && rm /etc/nologin + +# Enable systemd-user-sessions, a service that deletes /etc/nologin +if [ -f /usr/lib/systemd/system/systemd-user-sessions.service ]; then + systemctl unmask systemd-user-sessions + systemctl daemon-reload + /usr/lib/systemd/systemd-user-sessions start +fi From a41fb636bccd65ab7314f584fe627f358189857d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georg=20Sch=C3=B6lly?= Date: Thu, 1 Aug 2024 16:39:01 +0200 Subject: [PATCH 21/88] Detect software from deb_packages which is 'on hold' (#20751) The list of installed software was missing packages put ['on hold'](https://askubuntu.com/questions/18654/how-to-prevent-updating-of-a-specific-package) The reason for this is that the old query looks for the status install ok installed but there are other valid status which are also installed, like `hold ok installed`. The syntax is ` ` so we only need to look at the last or two last parts and ignore the first one. See https://man7.org/linux/man-pages/man1/dpkg-query.1.html for a list of status. # Checklist for submitter - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [X] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) --- changes/20751-detect-held-linux-packages-as-installed | 1 + docs/Using Fleet/Understanding-host-vitals.md | 2 +- server/service/osquery_utils/queries.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changes/20751-detect-held-linux-packages-as-installed diff --git a/changes/20751-detect-held-linux-packages-as-installed b/changes/20751-detect-held-linux-packages-as-installed new file mode 100644 index 0000000000..6aa524ce80 --- /dev/null +++ b/changes/20751-detect-held-linux-packages-as-installed @@ -0,0 +1 @@ +Linux .deb packages 'on hold' are now included in the installed software list. diff --git a/docs/Using Fleet/Understanding-host-vitals.md b/docs/Using Fleet/Understanding-host-vitals.md index 77b9e68ca9..3cdabf2fde 100644 --- a/docs/Using Fleet/Understanding-host-vitals.md +++ b/docs/Using Fleet/Understanding-host-vitals.md @@ -504,7 +504,7 @@ SELECT '' AS arch, '' AS installed_path FROM deb_packages -WHERE status = 'install ok installed' +WHERE status LIKE '% ok installed' UNION SELECT package AS name, diff --git a/server/service/osquery_utils/queries.go b/server/service/osquery_utils/queries.go index b811fc0026..1baa63a9f1 100644 --- a/server/service/osquery_utils/queries.go +++ b/server/service/osquery_utils/queries.go @@ -944,7 +944,7 @@ SELECT '' AS arch, '' AS installed_path FROM deb_packages -WHERE status = 'install ok installed' +WHERE status LIKE '% ok installed' UNION SELECT package AS name, From 5820d028e035a177930edef7b260e7a43ddec35d Mon Sep 17 00:00:00 2001 From: Marko Lisica <83164494+marko-lisica@users.noreply.github.com> Date: Thu, 1 Aug 2024 17:11:07 +0200 Subject: [PATCH 22/88] API design: Improve host identifiers in the docs, CLI and API (#19752) API design for: #19127 --- docs/REST API/rest-api.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/REST API/rest-api.md b/docs/REST API/rest-api.md index 4e711ccb86..e07c86e33f 100644 --- a/docs/REST API/rest-api.md +++ b/docs/REST API/rest-api.md @@ -3102,18 +3102,17 @@ Returns the information of the specified host. ### Get host by identifier -Returns the information of the host specified using the `uuid`, `hardware_serial`, `osquery_host_id`, `hostname`, or -`node_key` as an identifier. +Returns the information of the host specified using the `hostname`, `uuid`, or `hardware_serial` as an identifier. -If `hostname` is specified when there is more than one host with the same hostname, the endpoint returns the first matching host. In Fleet, hostnames are fully qualified domain names (FQDNs). +If `hostname` is specified when there is more than one host with the same hostname, the endpoint returns the first matching host. In Fleet, hostnames are fully qualified domain names (FQDNs). `hostname` (e.g. johns-macbook-air.local) is not the same as `display_name` (e.g. John's MacBook Air). `GET /api/v1/fleet/hosts/identifier/:identifier` #### Parameters -| Name | Type | In | Description | -| ---------- | ----------------- | ---- | ----------------------------------------------------------------------------- | -| identifier | integer or string | path | **Required**. The host's `hardware_serial`, `uuid`, `osquery_host_id`, `hostname`, or `node_key` | +| Name | Type | In | Description | +| ---------- | ----------------- | ---- | ------------------------------------------------------------------ | +| identifier | string | path | **Required**. The host's `hostname`, `uuid`, or `hardware_serial`. | | exclude_software | boolean | query | If `true`, the response will not include a list of installed software for the host. | #### Example From e761543262f41fd7a40be80ab9daac096a85b1e3 Mon Sep 17 00:00:00 2001 From: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com> Date: Thu, 1 Aug 2024 11:08:30 -0500 Subject: [PATCH 23/88] Fix unreleased bugs related to VPP app install details UI (#20952) --- .../AppInstallDetails/AppInstallDetails.tsx | 39 +++++++++++-------- .../InstallDetails/constants.ts | 2 +- .../HostDetailsPage/HostDetailsPage.tsx | 20 ++++++++-- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx b/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx index dd1de5a727..f6ed1a97be 100644 --- a/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx +++ b/frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx @@ -13,7 +13,6 @@ import Spinner from "components/Spinner/Spinner"; import { IMdmCommandResult } from "interfaces/mdm"; import { IActivityDetails } from "interfaces/activity"; -import { IconNames } from "components/icons"; import { getInstallDetailsStatusPredicate, INSTALL_DETAILS_STATUS_ICONS, @@ -46,7 +45,10 @@ export const AppInstallDetails = ({ return mdmApi.getCommandResults(command_uuid).then((response) => { const results = response.results?.[0]; if (!results) { - return Promise.reject(new Error("No data returned")); + // FIXME: It's currently possible that the command results API response is empty for pending + // commands. As a temporary workaround to handle this case, we'll ignore the empty response and + // display some minimal pending UI. This should be removed once the API response is fixed. + return {} as IMdmCommandResult; } return { ...results, @@ -66,27 +68,28 @@ export const AppInstallDetails = ({ } else if (isError) { return ; } else if (!result) { - // FIXME: Find a better solution for this. - return ; + // FIXME: It's currently possible that the command results API response is empty for pending + // commands. As a temporary workaround to handle this case, we'll ignore the empty response and + // display some minimal pending UI. This should be updated once the API response is fixed. } + const displayStatus = (status as SoftwareInstallStatus) || "pending"; + const iconName = INSTALL_DETAILS_STATUS_ICONS[displayStatus]; + // Note: We need to reconcile status values from two different sources. From props, we // get the status from the activity item details (which can be "failed", "pending", or // "installed"). From the command results API response, we also receive the raw status // from the MDM protocol, e.g., "NotNow" or "Acknowledged". We need to display some special // messaging for the "NotNow" status, which otherwise would be treated as "pending". - const isStatusNotNow = result.status === "NotNow"; - let iconName: IconNames; + const isStatusNotNow = result?.status === "NotNow"; let predicate: string; let subordinate: string; if (isStatusNotNow) { - iconName = INSTALL_DETAILS_STATUS_ICONS.pending; predicate = "tried to install"; subordinate = " but couldn’t because the host was locked or was running on battery power while in Power Nap. Fleet will try again"; } else { - iconName = INSTALL_DETAILS_STATUS_ICONS[status as SoftwareInstallStatus]; - predicate = getInstallDetailsStatusPredicate(status); + predicate = getInstallDetailsStatusPredicate(displayStatus); subordinate = status === "pending" ? " when it comes online" : ""; } @@ -96,7 +99,9 @@ export const AppInstallDetails = ({ "the host" ); - const showCommandResponse = isStatusNotNow || status !== "pending"; + const showCommandPayload = !!result?.payload; + const showCommandResponse = + !!result?.result && (isStatusNotNow || status !== "pending"); return ( <> @@ -108,12 +113,14 @@ export const AppInstallDetails = ({ {subordinate}.
-
- Request payload: - -
+ {showCommandPayload && ( +
+ Request payload: + +
+ )} {showCommandResponse && (
The response from {formattedHost}: diff --git a/frontend/components/ActivityDetails/InstallDetails/constants.ts b/frontend/components/ActivityDetails/InstallDetails/constants.ts index b3cd75cf79..c4c1ae8cb7 100644 --- a/frontend/components/ActivityDetails/InstallDetails/constants.ts +++ b/frontend/components/ActivityDetails/InstallDetails/constants.ts @@ -14,7 +14,7 @@ const INSTALL_DETAILS_STATUS_PREDICATES: Record< SoftwareInstallStatus, string > = { - pending: "will install", + pending: "is installing or will install", installed: "installed", failed: "failed to install", } as const; diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index a55744bc33..0c4b9c9c3c 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -583,15 +583,29 @@ const HostDetailsPage = ({ setScriptDetailsId(details?.script_execution_id || ""); break; case "installed_software": - setPackageInstallDetails({ ...details }); + setPackageInstallDetails({ + ...details, + // FIXME: It seems like the backend is not using the correct display name when it returns + // upcoming install activities. As a workaround, we'll prefer the display name from + // the host object if it's available. + host_display_name: + host?.display_name || details?.host_display_name || "", + }); break; case "installed_app_store_app": - setAppInstallDetails({ ...details }); + setAppInstallDetails({ + ...details, + // FIXME: It seems like the backend is not using the correct display name when it returns + // upcoming install activities. As a workaround, we'll prefer the display name from + // the host object if it's available. + host_display_name: + host?.display_name || details?.host_display_name || "", + }); break; default: // do nothing } }, - [] + [host?.display_name] ); const onLabelClick = (label: ILabel) => { From 08d08d5602d29d98138340915e1657e212d53ecf Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Fri, 2 Aug 2024 01:09:51 +0900 Subject: [PATCH 24/88] Homepage tagline update (#20931) Updated homepage to include the new tagline that was settled in [this design review](https://us-65885.app.gong.io/call?id=186190266621232138&highlights=%5B%7B%22type%22%3A%22SHARE%22%2C%22from%22%3A2009%2C%22to%22%3A2061%7D%5D). --------- Co-authored-by: Eric --- website/assets/styles/pages/homepage.less | 4 ++++ website/views/pages/homepage.ejs | 4 ++-- website/views/partials/primary-tagline.partial.ejs | 8 +++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/website/assets/styles/pages/homepage.less b/website/assets/styles/pages/homepage.less index bffa783ff5..72c04a9868 100644 --- a/website/assets/styles/pages/homepage.less +++ b/website/assets/styles/pages/homepage.less @@ -60,7 +60,11 @@ min-width: 540px; text-align: center; h1 { + max-width: 640px; margin-bottom: 16px; + &.vm { + max-width: unset; + } } p { margin-bottom: 32px; diff --git a/website/views/pages/homepage.ejs b/website/views/pages/homepage.ejs index e068fde91b..d07b372d36 100644 --- a/website/views/pages/homepage.ejs +++ b/website/views/pages/homepage.ejs @@ -6,8 +6,8 @@
<%/* Hero text */%>
-

<%- partial('../partials/primary-tagline.partial.ejs') %>

-

Replace the sprawl with <%= primaryBuyingSituation === 'vm'? 'secure, open-source reporting that works the way you want' : primaryBuyingSituation === 'eo-security'? 'universal, open-source endpoint visibility' : 'secure, open-source device management that works the way you want' %>.

+

<%- partial('../partials/primary-tagline.partial.ejs') %>

+

Replace the sprawl with <%= primaryBuyingSituation === 'vm'? 'secure, open-source reporting that works the way you want' : primaryBuyingSituation === 'eo-security'? 'universal, open-source endpoint visibility' : 'a modern device management platform that works the way you want' %>.

Learn how Talk to us diff --git a/website/views/partials/primary-tagline.partial.ejs b/website/views/partials/primary-tagline.partial.ejs index 52bd6fc370..869c05f94f 100644 --- a/website/views/partials/primary-tagline.partial.ejs +++ b/website/views/partials/primary-tagline.partial.ejs @@ -1 +1,7 @@ -<%= typeof primaryBuyingSituation !== 'undefined' ? (primaryBuyingSituation === 'vm' ? 'Focus on vulnerabilities, not vendors' : primaryBuyingSituation === 'eo-security' ? 'Light in every corner' : primaryBuyingSituation === 'eo-it' ? 'Untangle your endpoints' : 'Your easiest MDM migration') : 'Your easiest MDM migration' %> +<%= + typeof primaryBuyingSituation === 'undefined' ? 'Open-source device management for everyone' // Default (no buying situation) + : primaryBuyingSituation === 'vm' ? 'Focus on vulnerabilities, not vendors' // vm + : primaryBuyingSituation === 'eo-security' ? 'Light in every corner'// eo-security + : primaryBuyingSituation === 'eo-it' ? 'Untangle your endpoints' : // eo-it + 'Open-source device management for everyone'// mdm +%> From 2ccc0f79e7a8ff3c07f6ffea7f2fa41c7ee48f80 Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Thu, 1 Aug 2024 09:17:57 -0700 Subject: [PATCH 25/88] =?UTF-8?q?UI=20=E2=80=93=20Follow-ups=20for=20iPadO?= =?UTF-8?q?S/iPadOS=20VPP=20(#20916)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Follow ups to #20467, part 4 of #20917 - Use combination of apps' fields to uniquely identify them – [bug and fix demo/explanation](https://www.loom.com/share/2e5f088677604f04927bce8d9dacf8fe?sid=d946bea5-11a9-419a-b946-962829a53adc) - Add new field to vpp `POST` requests for correct add VPP software functionality ![Screenshot-2024-07-31-at-50131PM](https://github.com/user-attachments/assets/57c925f9-53cb-4860-b6b6-475b6d5cb2a5) - Implement desired states for software action dropdown ![Screenshot-2024-07-31-at-45556PM](https://github.com/user-attachments/assets/b6d3db97-dea2-43bb-9662-29256e87fbf0) - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling --- .../components/AppStoreVpp/AppStoreVpp.tsx | 55 ++++++++++++------- .../components/AppStoreVpp/helpers.tsx | 4 ++ .../details/DeviceUserPage/DeviceUserPage.tsx | 2 +- .../HostDetailsPage/HostDetailsPage.tsx | 4 +- .../details/cards/Software/HostSoftware.tsx | 14 ++--- .../Software/HostSoftwareTableConfig.tsx | 32 ++++++----- frontend/services/entities/mdm_apple.ts | 3 +- 7 files changed, 71 insertions(+), 43 deletions(-) diff --git a/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx b/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx index b6191d228b..874d2d8849 100644 --- a/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx +++ b/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx @@ -22,7 +22,7 @@ import { NotificationContext } from "context/notification"; import { getErrorReason } from "interfaces/errors"; import { buildQueryStringFromParams } from "utilities/url"; import SoftwareIcon from "../icons/SoftwareIcon"; -import { getErrorMessage } from "./helpers"; +import { getErrorMessage, getUniqueAppId } from "./helpers"; const baseClass = "app-store-vpp"; @@ -64,10 +64,16 @@ const NoVppAppsCard = () => ( interface IVppAppListItemProps { app: IVppApp; selected: boolean; + uniqueAppId: string; onSelect: (software: IVppApp) => void; } -const VppAppListItem = ({ app, selected, onSelect }: IVppAppListItemProps) => { +const VppAppListItem = ({ + app, + selected, + uniqueAppId, + onSelect, +}: IVppAppListItemProps) => { return (
  • { {app.name}
  • } - id={`vppApp-${app.app_store_id}`} + id={`vppApp-${uniqueAppId}`} checked={selected} - value={app.app_store_id.toString()} + value={uniqueAppId} name="vppApp" onChange={() => onSelect(app)} /> @@ -98,20 +104,27 @@ interface IVppAppListProps { onSelect: (app: IVppApp) => void; } -const VppAppList = ({ apps, selectedApp, onSelect }: IVppAppListProps) => ( -
    -
      - {apps.map((app) => ( - - ))} -
    -
    -); +const VppAppList = ({ apps, selectedApp, onSelect }: IVppAppListProps) => { + const uniqueSelectedAppId = selectedApp ? getUniqueAppId(selectedApp) : null; + return ( +
    +
      + {apps.map((app) => { + const uniqueAppId = getUniqueAppId(app); + return ( + + ); + })} +
    +
    + ); +}; interface IAppStoreVppProps { teamId: number; @@ -160,7 +173,11 @@ const AppStoreVpp = ({ teamId, router, onExit }: IAppStoreVppProps) => { } try { - await mdmAppleAPI.addVppApp(teamId, selectedApp.app_store_id); + await mdmAppleAPI.addVppApp( + teamId, + selectedApp.app_store_id, + selectedApp.platform + ); renderFlash( "success", <> diff --git a/frontend/pages/SoftwarePage/components/AppStoreVpp/helpers.tsx b/frontend/pages/SoftwarePage/components/AppStoreVpp/helpers.tsx index f359a6441d..a0130de802 100644 --- a/frontend/pages/SoftwarePage/components/AppStoreVpp/helpers.tsx +++ b/frontend/pages/SoftwarePage/components/AppStoreVpp/helpers.tsx @@ -1,5 +1,6 @@ import React from "react"; import { getErrorReason } from "interfaces/errors"; +import { IVppApp } from "services/entities/mdm_apple"; const ADD_SOFTWARE_ERROR_PREFIX = "Couldn’t add software."; const DEFAULT_ERROR_MESSAGE = `${ADD_SOFTWARE_ERROR_PREFIX} Please try again.`; @@ -40,3 +41,6 @@ export const getErrorMessage = (e: unknown) => { } return DEFAULT_ERROR_MESSAGE; }; + +export const getUniqueAppId = (app: IVppApp) => + `${app.app_store_id}_${app.platform}`; diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 189c8ae488..ba78e6ab25 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -415,7 +415,7 @@ const DeviceUserPage = ({ ; pathname: string; @@ -83,7 +83,7 @@ export const parseHostSoftwareQueryParams = (queryParams: { const HostSoftware = ({ id, softwareUpdatedAt, - isFleetdHost, + hostCanInstallSoftware, router, queryParams, pathname, @@ -169,7 +169,7 @@ const HostSoftware = ({ [isMyDevicePage, refetchDeviceSoftware, refetchHostSoftware] ); - const canInstallSoftware = Boolean( + const userHasSWInstallPermission = Boolean( isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer ); @@ -213,19 +213,19 @@ const HostSoftware = ({ : generateHostSoftwareTableConfig({ router, installingSoftwareId, - canInstall: canInstallSoftware, + userHasSWInstallPermission, onSelectAction, teamId: hostTeamId, - isFleetdHost, + hostCanInstallSoftware, }); }, [ isMyDevicePage, router, installingSoftwareId, - canInstallSoftware, + userHasSWInstallPermission, onSelectAction, hostTeamId, - isFleetdHost, + hostCanInstallSoftware, ]); const isLoading = isMyDevicePage diff --git a/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx b/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx index b01806032f..66777b1ed3 100644 --- a/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx +++ b/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx @@ -50,17 +50,17 @@ type IVulnerabilitiesCellProps = IInstalledVersionsCellProps; // type IActionsCellProps = CellProps; const generateActions = ({ - canInstall, + userHasSWInstallPermission, + hostCanInstallSoftware, installingSoftwareId, - isFleetdHost, softwareId, status, software_package, app_store_app, }: { - canInstall: boolean; + userHasSWInstallPermission: boolean; + hostCanInstallSoftware: boolean; installingSoftwareId: number | null; - isFleetdHost: boolean; softwareId: number; status: SoftwareInstallStatus | null; software_package: IHostSoftwarePackage | null; @@ -78,14 +78,18 @@ const generateActions = ({ } const hasSoftwareToInstall = !!software_package || !!app_store_app; - // remove install if there is no package to install - if (!hasSoftwareToInstall || !canInstall) { + // remove install if there is no package to install or if the software is already installed + if ( + !hasSoftwareToInstall || + !userHasSWInstallPermission || + status === "installed" + ) { actions.splice(indexInstallAction, 1); return actions; } - // disable install option if not a fleetd host - if (!isFleetdHost) { + // disable install option if not a fleetd, iPad, or iOS host + if (!hostCanInstallSoftware) { actions[indexInstallAction].disabled = true; actions[indexInstallAction].tooltipContent = "To install software on this host, deploy the fleetd agent with --enable-scripts and refetch host vitals."; @@ -102,9 +106,9 @@ const generateActions = ({ }; interface ISoftwareTableHeadersProps { - canInstall: boolean; + userHasSWInstallPermission: boolean; + hostCanInstallSoftware: boolean; installingSoftwareId: number | null; - isFleetdHost: boolean; router: InjectedRouter; teamId: number; onSelectAction: (software: IHostSoftware, action: string) => void; @@ -113,9 +117,9 @@ interface ISoftwareTableHeadersProps { // NOTE: cellProps come from react-table // more info here https://react-table.tanstack.com/docs/api/useTable#cell-properties export const generateSoftwareTableHeaders = ({ - canInstall, + userHasSWInstallPermission, + hostCanInstallSoftware, installingSoftwareId, - isFleetdHost, router, teamId, onSelectAction, @@ -202,8 +206,8 @@ export const generateSoftwareTableHeaders = ({ { + addVppApp: (teamId: number, appStoreId: string, platform: ApplePlatform) => { const { MDM_APPLE_VPP_APPS } = endpoints; return sendRequest("POST", MDM_APPLE_VPP_APPS, { app_store_id: appStoreId, team_id: teamId, + platform, }); }, }; From 81af71b80a221859a3109a115de143f35b4db7be Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 1 Aug 2024 11:24:07 -0500 Subject: [PATCH 26/88] Website: Update questionnaire pre-filling. (#20953) Changes: - Updated the /start questionnaire to not prefill the "What will you use Fleet for?" question if the user has a primaryBuyingSituation set to `vm` --- website/assets/js/pages/start.page.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/assets/js/pages/start.page.js b/website/assets/js/pages/start.page.js index 191a445f99..e6f9514e05 100644 --- a/website/assets/js/pages/start.page.js +++ b/website/assets/js/pages/start.page.js @@ -85,7 +85,9 @@ parasails.registerPage('start', { } // If this user has not completed the 'what are you using fleet for' step, and has a primaryBuyingSituation set by an ad. prefill the formData for this step. if(this.primaryBuyingSituation && _.isEmpty(this.formData['what-are-you-using-fleet-for'])){ - this.formData['what-are-you-using-fleet-for'] = {primaryBuyingSituation: this.primaryBuyingSituation}; + if(this.primaryBuyingSituation !== 'vm') { + this.formData['what-are-you-using-fleet-for'] = {primaryBuyingSituation: this.primaryBuyingSituation}; + } } if(window.location.hash) { if(typeof analytics !== 'undefined') { From 7a4773cd0a355ac0c4d149d661436d5664696685 Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Thu, 1 Aug 2024 13:56:09 -0300 Subject: [PATCH 27/88] escape % in query (#20954) for https://github.com/fleetdm/fleet/issues/20940. Ran `make generate-doc` as well but docs don't change with this. --- server/service/osquery_utils/queries.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/service/osquery_utils/queries.go b/server/service/osquery_utils/queries.go index 1baa63a9f1..59b2430b54 100644 --- a/server/service/osquery_utils/queries.go +++ b/server/service/osquery_utils/queries.go @@ -944,7 +944,7 @@ SELECT '' AS arch, '' AS installed_path FROM deb_packages -WHERE status LIKE '% ok installed' +WHERE status LIKE '%% ok installed' UNION SELECT package AS name, From 30cbaf0a74e11e38d30c98b8e0976d094129b028 Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Thu, 1 Aug 2024 14:04:54 -0300 Subject: [PATCH 28/88] address PR feedback for FileVault improvements (#20935) feedback left by @mna and @gillespi314 in https://github.com/fleetdm/fleet/pull/20842 also fixes a bug found by @PezHub https://github.com/fleetdm/fleet/issues/13157#issuecomment-2261615471 related to https://github.com/fleetdm/fleet/issues/13157 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --- orbit/cmd/orbit/orbit.go | 14 ++++++++----- orbit/pkg/update/escrow_buddy.go | 2 +- orbit/pkg/update/update.go | 2 +- server/service/hosts_test.go | 35 ++++++++++++++++++++++++-------- server/service/orbit.go | 2 +- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/orbit/cmd/orbit/orbit.go b/orbit/cmd/orbit/orbit.go index d124a47d57..40d1d5283f 100644 --- a/orbit/cmd/orbit/orbit.go +++ b/orbit/cmd/orbit/orbit.go @@ -870,11 +870,6 @@ func main() { orbitClient.RegisterConfigReceiver(update.ApplyNudgeConfigReceiverMiddleware(update.NudgeConfigFetcherOptions{ UpdateRunner: updateRunner, RootDir: c.String("root-dir"), Interval: nudgeLaunchInterval, })) - if orbitClient.GetServerCapabilities().Has(fleet.CapabilityEscrowBuddy) { - orbitClient.RegisterConfigReceiver(update.NewEscrowBuddyRunner(updateRunner, 5*time.Minute)) - } else { - orbitClient.RegisterConfigReceiver(update.ApplyDiskEncryptionRunnerMiddleware()) - } orbitClient.RegisterConfigReceiver(update.ApplySwiftDialogDownloaderMiddleware(updateRunner)) case "windows": orbitClient.RegisterConfigReceiver(update.ApplyWindowsMDMEnrollmentFetcherMiddleware(windowsMDMEnrollmentCommandFrequency, orbitHostInfo.HardwareUUID, orbitClient)) @@ -1224,6 +1219,15 @@ func main() { softwareRunner := installer.NewRunner(orbitClient, r.ExtensionSocketPath(), scriptsEnabledFn) orbitClient.RegisterConfigReceiver(softwareRunner) + if runtime.GOOS == "darwin" { + log.Info().Msgf("orbitClient.GetServerCapabilities() %+v", orbitClient.GetServerCapabilities()) + if orbitClient.GetServerCapabilities().Has(fleet.CapabilityEscrowBuddy) { + orbitClient.RegisterConfigReceiver(update.NewEscrowBuddyRunner(updateRunner, 5*time.Minute)) + } else { + orbitClient.RegisterConfigReceiver(update.ApplyDiskEncryptionRunnerMiddleware()) + } + } + // Install a signal handler ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/orbit/pkg/update/escrow_buddy.go b/orbit/pkg/update/escrow_buddy.go index 72ef1fab5a..e1f6fdf116 100644 --- a/orbit/pkg/update/escrow_buddy.go +++ b/orbit/pkg/update/escrow_buddy.go @@ -43,7 +43,7 @@ func (e *EscrowBuddyRunner) Run(cfg *fleet.OrbitConfig) error { log.Debug().Msgf("EscrowBuddyRunner: notification: %t", cfg.Notifications.RotateDiskEncryptionKey) if e.updateRunner == nil { - log.Debug().Msg("EscrowBuddyRunner: received nil UpdateRunner, this probably indicates that updates are turned off. Skipping any actions related to Disk encryption") + log.Info().Msg("EscrowBuddyRunner: received nil UpdateRunner, this probably indicates that updates are turned off. Skipping any actions related to Disk encryption") return nil } diff --git a/orbit/pkg/update/update.go b/orbit/pkg/update/update.go index f9bee2413f..f1803ec787 100644 --- a/orbit/pkg/update/update.go +++ b/orbit/pkg/update/update.go @@ -384,7 +384,7 @@ func (u *Updater) get(target string) (*LocalTarget, error) { return nil, fmt.Errorf("failed to remove old extracted dir: %q: %w", localTarget.DirPath, err) } } - if strings.HasSuffix(localTarget.Path, ".pkg") { + if strings.HasSuffix(localTarget.Path, ".pkg") && runtime.GOOS == "darwin" { cmd := exec.Command("installer", "-pkg", localTarget.Path, "-target", "/") if out, err := cmd.CombinedOutput(); err != nil { return nil, fmt.Errorf("running pkgutil to install %s: %s: %w", localTarget.Path, string(out), err) diff --git a/server/service/hosts_test.go b/server/service/hosts_test.go index b0f6dc7529..b2765516e2 100644 --- a/server/service/hosts_test.go +++ b/server/service/hosts_test.go @@ -1876,7 +1876,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }{ { name: "no MDM configured", - host: &fleet.Host{ID: 1, Platform: "darwin"}, + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: false}, }, @@ -1889,7 +1889,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, { name: "not connected to Fleet MDM", - host: &fleet.Host{ID: 1, Platform: "darwin"}, + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, @@ -1915,7 +1915,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, { name: "disk encryption not configured", - host: &fleet.Host{ID: 1, Platform: "darwin"}, + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, @@ -1928,7 +1928,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, { name: "darwin with decryptable key", - host: &fleet.Host{ID: 1, Platform: "darwin"}, + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, @@ -1943,9 +1943,26 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, expectedError: false, }, + { + name: "darwin needs rotation", + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: nil, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return &fleet.HostDiskEncryptionKey{Decryptable: ptr.Bool(false)}, nil + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + RotateDiskEncryptionKey: true, + }, + expectedError: false, + }, { name: "windows server with no encryption needed", - host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true)}, + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true), OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, @@ -1962,7 +1979,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, { name: "windows with encryption enabled but key missing", - host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true)}, + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true), OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, @@ -1979,7 +1996,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, { name: "darwin with missing encryption key", - host: &fleet.Host{ID: 1, Platform: "darwin"}, + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, @@ -1996,7 +2013,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, { name: "windows with encryption key and not decryptable", - host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true)}, + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(true), OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, @@ -2013,7 +2030,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, { name: "windows with enforce BitLocker", - host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(false)}, + host: &fleet.Host{ID: 1, Platform: "windows", DiskEncryptionEnabled: ptr.Bool(false), OsqueryHostID: ptr.String("foo")}, appConfig: &fleet.AppConfig{ MDM: fleet.MDM{EnabledAndConfigured: true}, }, diff --git a/server/service/orbit.go b/server/service/orbit.go index 40f64ef2d3..1ee8725a08 100644 --- a/server/service/orbit.go +++ b/server/service/orbit.go @@ -428,7 +428,7 @@ func (svc *Service) setDiskEncryptionNotifications( switch host.FleetPlatform() { case "darwin": - notifs.RotateDiskEncryptionKey = encryptionKey.Decryptable != nil && !*encryptionKey.Decryptable + notifs.RotateDiskEncryptionKey = encryptionKey != nil && encryptionKey.Decryptable != nil && !*encryptionKey.Decryptable case "windows": isServer := mdmInfo != nil && mdmInfo.IsServer needsEncryption := host.DiskEncryptionEnabled != nil && !*host.DiskEncryptionEnabled From a28e4d800ba27dec651f5fa4bb64de6f534b939b Mon Sep 17 00:00:00 2001 From: Noah Talerman <47070608+noahtalerman@users.noreply.github.com> Date: Thu, 1 Aug 2024 13:43:07 -0400 Subject: [PATCH 29/88] Supported operating systems docs (#20679) - Google Chrome and a gnome extension have to be installed to use Fleet Desktop + Firefox on Fedora. - You don't have to set Google Chrome as the default browser. --- docs/Using Fleet/Supported-host-operating-systems.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Using Fleet/Supported-host-operating-systems.md b/docs/Using Fleet/Supported-host-operating-systems.md index c7adedff89..ff8cd5480c 100644 --- a/docs/Using Fleet/Supported-host-operating-systems.md +++ b/docs/Using Fleet/Supported-host-operating-systems.md @@ -28,7 +28,7 @@ Fleet's agent (fleetd) generated for MacOS by `fleetctl package` does not includ > Ubuntu 24.04 comes with Wayland enabled by default. To use X11 instead of Wayland you can set > `WaylandEnable=false` in `/etc/gdm3/custom.conf` and reboot. -> Fedora, CentOS 8 and 9 require a [gnome extension](https://extensions.gnome.org/extension/615/appindicator-support/) and Google Chrome set to the default browser for Fleet Desktop. +> Fedora, CentOS 8 and 9 require a [gnome extension](https://extensions.gnome.org/extension/615/appindicator-support/) and Google Chrome for Fleet Desktop. > The `fleetctl package` command is not supported on DISA-STIG distribution. From 580a81ded55a017de5028c750271d6c4bf7d2027 Mon Sep 17 00:00:00 2001 From: Victor Lyuboslavsky Date: Thu, 1 Aug 2024 20:32:45 +0200 Subject: [PATCH 30/88] Fixed duplicate app install activity on host (#20944) Unreleased bug for iOS/iPadOS VPP #19447 # Checklist for submitter - [x] Added/updated tests - [x] If database migrations are included, checked table schema to confirm autoupdate - For database migrations: - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`). - [x] Manual QA for all new/changed functionality --- ee/server/service/software_installers.go | 2 +- server/datastore/mysql/activities.go | 2 +- server/datastore/mysql/hosts.go | 2 +- ...59_AddPlatformToHostVPPSoftwareInstalls.go | 60 ++++++++++++++++ ...dPlatformToHostVPPSoftwareInstalls_test.go | 68 +++++++++++++++++++ server/datastore/mysql/schema.sql | 11 +-- server/datastore/mysql/software.go | 6 +- server/datastore/mysql/software_installers.go | 9 +-- server/datastore/mysql/software_titles.go | 2 +- server/datastore/mysql/vpp.go | 20 +++--- server/datastore/mysql/vpp_test.go | 29 ++++---- server/fleet/datastore.go | 4 +- server/mock/datastore_mock.go | 12 ++-- server/service/integration_mdm_test.go | 21 ++++-- server/service/software_titles.go | 2 +- 15 files changed, 198 insertions(+), 52 deletions(-) create mode 100644 server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls.go create mode 100644 server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls_test.go diff --git a/ee/server/service/software_installers.go b/ee/server/service/software_installers.go index 06ffb9f941..b17eee2b73 100644 --- a/ee/server/service/software_installers.go +++ b/ee/server/service/software_installers.go @@ -425,7 +425,7 @@ func (svc *Service) installSoftwareFromVPP(ctx context.Context, host *fleet.Host return ctxerr.Wrapf(ctx, err, "sending command to install VPP %s application to host with serial %s", vppApp.AdamID, host.HardwareSerial) } - err = svc.ds.InsertHostVPPSoftwareInstall(ctx, host.ID, user.ID, vppApp.AdamID, cmdUUID, eventID) + err = svc.ds.InsertHostVPPSoftwareInstall(ctx, host.ID, user.ID, vppApp.VPPAppID, cmdUUID, eventID) if err != nil { return ctxerr.Wrapf(ctx, err, "inserting host vpp software install for host with serial %s and app with adamID %s", host.HardwareSerial, vppApp.AdamID) } diff --git a/server/datastore/mysql/activities.go b/server/datastore/mysql/activities.go index 1fbc21a99a..d0e6dee037 100644 --- a/server/datastore/mysql/activities.go +++ b/server/datastore/mysql/activities.go @@ -368,7 +368,7 @@ LEFT OUTER JOIN LEFT OUTER JOIN host_display_names hdn ON hdn.host_id = hvsi.host_id LEFT OUTER JOIN - vpp_apps vpa ON hvsi.adam_id = vpa.adam_id + vpp_apps vpa ON hvsi.adam_id = vpa.adam_id AND hvsi.platform = vpa.platform LEFT OUTER JOIN software_titles st ON st.id = vpa.title_id WHERE diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index f5ed94d2f4..47125e16c8 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -1045,7 +1045,7 @@ func (ds *Datastore) applyHostFilters( if err != nil { return "", nil, ctxerr.Wrap(ctx, err, "get vpp app by team and title id") } - vppAppJoin, vppAppParams, err := ds.vppAppJoin(vppApp.AdamID, *opt.SoftwareStatusFilter) + vppAppJoin, vppAppParams, err := ds.vppAppJoin(vppApp.VPPAppID, *opt.SoftwareStatusFilter) if err != nil { return "", nil, ctxerr.Wrap(ctx, err, "vpp app join") } diff --git a/server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls.go b/server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls.go new file mode 100644 index 0000000000..6b70578339 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls.go @@ -0,0 +1,60 @@ +package tables + +import ( + "database/sql" + "fmt" +) + +func init() { + MigrationClient.AddMigration(Up_20240801115359, Down_20240801115359) +} + +func Up_20240801115359(tx *sql.Tx) error { + if columnExists(tx, "host_vpp_software_installs", "platform") { + return nil + } + + _, err := tx.Exec(` + ALTER TABLE host_vpp_software_installs + ADD COLUMN platform VARCHAR(10) COLLATE utf8mb4_unicode_ci NOT NULL`) + if err != nil { + return fmt.Errorf("adding platform to host_vpp_software_installs: %w", err) + } + + updateStmt := ` + UPDATE host_vpp_software_installs hvsi INNER JOIN hosts h ON h.id = hvsi.host_id + SET hvsi.platform = h.platform, hvsi.updated_at = hvsi.updated_at` + + _, err = tx.Exec(updateStmt) + if err != nil { + return fmt.Errorf("updating platform in host_vpp_software_installs: %w", err) + } + + // Since hosts may be missing, we need to update the platform for records that were not updated + updateStmt2 := ` + UPDATE host_vpp_software_installs hvsi INNER JOIN vpp_apps vap ON vap.adam_id = hvsi.adam_id + SET hvsi.platform = vap.platform, hvsi.updated_at = hvsi.updated_at + WHERE hvsi.platform = ''` + + _, err = tx.Exec(updateStmt2) + if err != nil { + return fmt.Errorf("updating platform in host_vpp_software_installs part 2: %w", err) + } + + _, err = tx.Exec(`ALTER TABLE host_vpp_software_installs DROP INDEX adam_id, ADD INDEX (adam_id, platform)`) + if err != nil { + return fmt.Errorf("updating key in host_vpp_software_installs: %w", err) + } + _, err = tx.Exec(` + ALTER TABLE host_vpp_software_installs DROP FOREIGN KEY host_vpp_software_installs_ibfk_2, + ADD FOREIGN KEY host_vpp_software_installs_ibfk_3 (adam_id, platform) REFERENCES vpp_apps (adam_id, platform) ON DELETE CASCADE`) + if err != nil { + return fmt.Errorf("updating foreign key in host_vpp_software_installs: %w", err) + } + + return nil +} + +func Down_20240801115359(tx *sql.Tx) error { + return nil +} diff --git a/server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls_test.go b/server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls_test.go new file mode 100644 index 0000000000..98a5a19f26 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20240801115359_AddPlatformToHostVPPSoftwareInstalls_test.go @@ -0,0 +1,68 @@ +package tables + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUp_20240801115359(t *testing.T) { + db := applyUpToPrev(t) + + // Create user + u1 := execNoErrLastID(t, db, `INSERT INTO users (name, email, password, salt) VALUES (?, ?, ?, ?)`, "u1", "u1@b.c", "1234", "salt") + // Create host + insertHostStmt := ` + INSERT INTO hosts ( + hostname, uuid, platform, osquery_version, os_version, build, platform_like, code_name, + cpu_type, cpu_subtype, cpu_brand, hardware_vendor, hardware_model, hardware_version, + hardware_serial, computer_name, team_id + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ` + hostName := "Dummy Hostname" + hostUUID := "12345678-1234-1234-1234-123456789012" + hostPlatform := "ios" + osqueryVer := "5.9.1" + osVersion := "Windows 10" + buildVersion := "10.0.19042.1234" + platformLike := "apple" + codeName := "20H2" + cpuType := "x86_64" + cpuSubtype := "x86_64" + cpuBrand := "Intel" + hwVendor := "Dell Inc." + hwModel := "OptiPlex 7090" + hwVersion := "1.0" + hwSerial := "ABCDEFGHIJ" + computerName := "DESKTOP-TEST" + + hostID := execNoErrLastID(t, db, insertHostStmt, hostName, hostUUID, hostPlatform, osqueryVer, + osVersion, buildVersion, platformLike, codeName, cpuType, cpuSubtype, cpuBrand, hwVendor, hwModel, hwVersion, hwSerial, computerName, nil) + hostIDMissing := hostID + 1 + + // Create VPP app + adamID := "a" + execNoErr( + t, db, `INSERT INTO vpp_apps (adam_id, platform) VALUES (?,?)`, adamID, hostPlatform, + ) + // Create another VPP app for a different platform + execNoErr( + t, db, `INSERT INTO vpp_apps (adam_id, platform) VALUES (?,?)`, adamID, "unused", + ) + + // create an install on a known host + hvsi1 := execNoErrLastID(t, db, `INSERT INTO host_vpp_software_installs (host_id, adam_id, command_uuid, user_id) VALUES (?,?,?,?)`, hostID, adamID, "command_uuid", u1) + // create an install on a missing host + hvsi2 := execNoErrLastID(t, db, `INSERT INTO host_vpp_software_installs (host_id, adam_id, command_uuid, user_id) VALUES (?,?,?,?)`, hostIDMissing, adamID, "command_uuid2", u1) + + // Apply current migration. + applyNext(t, db) + + // Check that the platform column was updated. + var platformResp string + require.NoError(t, db.Get(&platformResp, `SELECT platform FROM host_vpp_software_installs WHERE id = ?`, hvsi1)) + assert.Equal(t, hostPlatform, platformResp) + require.NoError(t, db.Get(&platformResp, `SELECT platform FROM host_vpp_software_installs WHERE id = ?`, hvsi2)) + assert.Equal(t, hostPlatform, platformResp) +} diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index 74f18b3289..9ed81803bd 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -563,13 +563,14 @@ CREATE TABLE `host_vpp_software_installs` ( `associated_event_id` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `platform` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_host_vpp_software_installs_command_uuid` (`command_uuid`), KEY `user_id` (`user_id`), - KEY `adam_id` (`adam_id`), + KEY `adam_id` (`adam_id`,`platform`), CONSTRAINT `host_vpp_software_installs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL, - CONSTRAINT `host_vpp_software_installs_ibfk_2` FOREIGN KEY (`adam_id`) REFERENCES `vpp_apps` (`adam_id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CONSTRAINT `host_vpp_software_installs_ibfk_3` FOREIGN KEY (`adam_id`, `platform`) REFERENCES `vpp_apps` (`adam_id`, `platform`) ON DELETE CASCADE +) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; @@ -968,9 +969,9 @@ CREATE TABLE `migration_status_tables` ( `tstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`) -) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=292 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=293 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'); +INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'),(292,20240801115359,1,'2020-01-01 01:01:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `mobile_device_management_solutions` ( diff --git a/server/datastore/mysql/software.go b/server/datastore/mysql/software.go index b91a38a89d..76ab0da294 100644 --- a/server/datastore/mysql/software.go +++ b/server/datastore/mysql/software.go @@ -2129,7 +2129,7 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id LEFT OUTER JOIN vpp_apps vap ON st.id = vap.title_id LEFT OUTER JOIN - host_vpp_software_installs hvsi ON vap.adam_id = hvsi.adam_id AND hvsi.host_id = :host_id + host_vpp_software_installs hvsi ON vap.adam_id = hvsi.adam_id AND vap.platform = hvsi.platform AND hvsi.host_id = :host_id LEFT OUTER JOIN nano_command_results ncr ON ncr.command_uuid = hvsi.command_uuid WHERE @@ -2143,7 +2143,7 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id ( hvsi.id IS NULL OR hvsi.id = ( SELECT hvsi2.id FROM host_vpp_software_installs hvsi2 - WHERE hvsi2.host_id = hvsi.host_id AND hvsi2.adam_id = hvsi.adam_id + WHERE hvsi2.host_id = hvsi.host_id AND hvsi2.adam_id = hvsi.adam_id AND hvsi2.platform = hvsi.platform ORDER BY hvsi2.created_at DESC LIMIT 1 ) ) AND -- software is installed on host @@ -2159,8 +2159,6 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id ) OR -- or software install has been attempted on host (via installer or VPP app) hsi.host_id IS NOT NULL OR hvsi.host_id IS NOT NULL ) - -- make sure VPP platform matches - AND (vap.platform IS NULL OR vap.platform = :host_platform) %s %s `, softwareInstallerHostStatusNamedQuery("hsi", ""), vppAppHostStatusNamedQuery("hvsi", "ncr", ""), onlySelfServiceClause, onlyVulnerableClause) diff --git a/server/datastore/mysql/software_installers.go b/server/datastore/mysql/software_installers.go index 9539ca371a..51c952151c 100644 --- a/server/datastore/mysql/software_installers.go +++ b/server/datastore/mysql/software_installers.go @@ -421,7 +421,7 @@ WHERE return &dest, nil } -func (ds *Datastore) vppAppJoin(adamID string, status fleet.SoftwareInstallerStatus) (string, []interface{}, error) { +func (ds *Datastore) vppAppJoin(appID fleet.VPPAppID, status fleet.SoftwareInstallerStatus) (string, []interface{}, error) { stmt := fmt.Sprintf(`JOIN ( SELECT host_id @@ -430,13 +430,13 @@ FROM LEFT OUTER JOIN nano_command_results ncr ON ncr.command_uuid = hvsi.command_uuid WHERE - adam_id = :adam_id + adam_id = :adam_id AND platform = :platform AND hvsi.id IN( SELECT max(id) -- ensure we use only the most recent install attempt for each host FROM host_vpp_software_installs WHERE - adam_id = :adam_id + adam_id = :adam_id AND platform = :platform GROUP BY host_id, adam_id) AND (%s) = :status) hss ON hss.host_id = h.id @@ -444,7 +444,8 @@ WHERE return sqlx.Named(stmt, map[string]interface{}{ "status": status, - "adam_id": adamID, + "adam_id": appID.AdamID, + "platform": appID.Platform, "software_status_installed": fleet.SoftwareInstallerInstalled, "software_status_failed": fleet.SoftwareInstallerFailed, "software_status_pending": fleet.SoftwareInstallerPending, diff --git a/server/datastore/mysql/software_titles.go b/server/datastore/mysql/software_titles.go index c73bc4e37f..2c214616dc 100644 --- a/server/datastore/mysql/software_titles.go +++ b/server/datastore/mysql/software_titles.go @@ -40,7 +40,7 @@ FROM software_titles st LEFT JOIN software_titles_host_counts sthc ON sthc.software_title_id = st.id LEFT JOIN software_installers si ON si.title_id = st.id AND si.global_or_team_id = ? LEFT JOIN vpp_apps vap ON vap.title_id = st.id -LEFT JOIN vpp_apps_teams vat ON vat.global_or_team_id = ? AND vat.adam_id = vap.adam_id +LEFT JOIN vpp_apps_teams vat ON vat.global_or_team_id = ? AND vat.adam_id = vap.adam_id AND vat.platform = vap.platform WHERE st.id = ? AND ((sthc.hosts_count > 0 AND %s) OR vat.adam_id IS NOT NULL OR si.id IS NOT NULL) GROUP BY diff --git a/server/datastore/mysql/vpp.go b/server/datastore/mysql/vpp.go index ddc5bdcde7..72bc53ecd7 100644 --- a/server/datastore/mysql/vpp.go +++ b/server/datastore/mysql/vpp.go @@ -45,7 +45,8 @@ WHERE return &app, nil } -func (ds *Datastore) GetSummaryHostVPPAppInstalls(ctx context.Context, teamID *uint, adamID string) (*fleet.VPPAppStatusSummary, error) { +func (ds *Datastore) GetSummaryHostVPPAppInstalls(ctx context.Context, teamID *uint, appID fleet.VPPAppID) (*fleet.VPPAppStatusSummary, + error) { var dest fleet.VPPAppStatusSummary stmt := fmt.Sprintf(` @@ -63,7 +64,7 @@ INNER JOIN LEFT OUTER JOIN nano_command_results ncr ON ncr.id = h.uuid AND ncr.command_uuid = hvsi.command_uuid WHERE - hvsi.adam_id = :adam_id AND + hvsi.adam_id = :adam_id AND hvsi.platform = :platform AND (h.team_id = :team_id OR (h.team_id IS NULL AND :team_id = 0)) AND hvsi.id IN ( SELECT @@ -71,7 +72,7 @@ WHERE FROM host_vpp_software_installs hvsi2 WHERE - hvsi2.adam_id = :adam_id + hvsi2.adam_id = :adam_id AND hvsi2.platform = :platform GROUP BY hvsi2.host_id ) @@ -83,7 +84,8 @@ WHERE } query, args, err := sqlx.Named(stmt, map[string]interface{}{ - "adam_id": adamID, + "adam_id": appID.AdamID, + "platform": appID.Platform, "team_id": tmID, "mdm_status_acknowledged": fleet.MDMAppleStatusAcknowledged, "mdm_status_error": fleet.MDMAppleStatusError, @@ -430,15 +432,17 @@ WHERE vat.global_or_team_id = ? AND va.title_id = ? return &dest, nil } -func (ds *Datastore) InsertHostVPPSoftwareInstall(ctx context.Context, hostID, userID uint, adamID, commandUUID, associatedEventID string) error { +func (ds *Datastore) InsertHostVPPSoftwareInstall(ctx context.Context, hostID, userID uint, appID fleet.VPPAppID, + commandUUID, associatedEventID string) error { stmt := ` INSERT INTO host_vpp_software_installs - (host_id, adam_id, command_uuid, user_id, associated_event_id) + (host_id, adam_id, platform, command_uuid, user_id, associated_event_id) VALUES - (?,?,?,?,?) + (?,?,?,?,?,?) ` - if _, err := ds.writer(ctx).ExecContext(ctx, stmt, hostID, adamID, commandUUID, userID, associatedEventID); err != nil { + if _, err := ds.writer(ctx).ExecContext(ctx, stmt, hostID, appID.AdamID, appID.Platform, commandUUID, userID, + associatedEventID); err != nil { return ctxerr.Wrap(ctx, err, "insert into host_vpp_software_installs") } diff --git a/server/datastore/mysql/vpp_test.go b/server/datastore/mysql/vpp_test.go index 449789ebe1..27fce609d3 100644 --- a/server/datastore/mysql/vpp_test.go +++ b/server/datastore/mysql/vpp_test.go @@ -188,15 +188,15 @@ func testVPPAppStatus(t *testing.T, ds *Datastore) { va1, err := ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp1", BundleIdentifier: "com.app.vpp1", VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_1", Platform: fleet.MacOSPlatform}}, nil) require.NoError(t, err) - vpp1 := va1.AdamID + vpp1 := va1.VPPAppID va2, err := ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp2", BundleIdentifier: "com.app.vpp2", VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.MacOSPlatform}}, &team1.ID) require.NoError(t, err) - vpp2 := va2.AdamID + vpp2 := va2.VPPAppID va3, err := ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp3", BundleIdentifier: "com.app.vpp3", VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_3", Platform: fleet.MacOSPlatform}}, nil) require.NoError(t, err) - vpp3 := va3.AdamID + vpp3 := va3.VPPAppID _, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp3", BundleIdentifier: "com.app.vpp3", VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_3", Platform: fleet.MacOSPlatform}}, &team1.ID) require.NoError(t, err) @@ -251,7 +251,7 @@ func testVPPAppStatus(t *testing.T, ds *Datastore) { require.NoError(t, err) // simulate an install request of vpp1 on h1 - cmd1 := createVPPAppInstallRequest(t, ds, h1, vpp1, user.ID) + cmd1 := createVPPAppInstallRequest(t, ds, h1, vpp1.AdamID, user.ID) summary, err = ds.GetSummaryHostVPPAppInstalls(ctx, nil, vpp1) require.NoError(t, err) @@ -266,8 +266,8 @@ func testVPPAppStatus(t *testing.T, ds *Datastore) { // create a new request for h1 that supercedes the failed on, and a request // for h2 with a successful result. - cmd2 := createVPPAppInstallRequest(t, ds, h1, vpp1, user.ID) - cmd3 := createVPPAppInstallRequest(t, ds, h2, vpp1, user.ID) + cmd2 := createVPPAppInstallRequest(t, ds, h1, vpp1.AdamID, user.ID) + cmd3 := createVPPAppInstallRequest(t, ds, h2, vpp1.AdamID, user.ID) createVPPAppInstallResult(t, ds, h2, cmd3, fleet.MDMAppleStatusAcknowledged) actUser, act, err := ds.GetPastActivityDataForVPPAppInstall(ctx, &mdm.CommandResults{CommandUUID: cmd3}) @@ -293,7 +293,7 @@ func testVPPAppStatus(t *testing.T, ds *Datastore) { require.Equal(t, &fleet.VPPAppStatusSummary{Pending: 0, Failed: 0, Installed: 0}, summary) // simulate a successful request for team app vpp2 on h3 - cmd4 := createVPPAppInstallRequest(t, ds, h3, vpp2, user.ID) + cmd4 := createVPPAppInstallRequest(t, ds, h3, vpp2.AdamID, user.ID) createVPPAppInstallResult(t, ds, h3, cmd4, fleet.MDMAppleStatusAcknowledged) summary, err = ds.GetSummaryHostVPPAppInstalls(ctx, &team1.ID, vpp2) @@ -302,11 +302,11 @@ func testVPPAppStatus(t *testing.T, ds *Datastore) { // simulate a successful, failed and pending request for app vpp3 on team // (h3) and no team (h1, h2) - cmd5 := createVPPAppInstallRequest(t, ds, h3, vpp3, user.ID) + cmd5 := createVPPAppInstallRequest(t, ds, h3, vpp3.AdamID, user.ID) createVPPAppInstallResult(t, ds, h3, cmd5, fleet.MDMAppleStatusAcknowledged) - cmd6 := createVPPAppInstallRequest(t, ds, h1, vpp3, user.ID) + cmd6 := createVPPAppInstallRequest(t, ds, h1, vpp3.AdamID, user.ID) createVPPAppInstallResult(t, ds, h1, cmd6, fleet.MDMAppleStatusCommandFormatError) - createVPPAppInstallRequest(t, ds, h2, vpp3, user.ID) + createVPPAppInstallRequest(t, ds, h2, vpp3.AdamID, user.ID) // for no team, it sees the failed and pending counts summary, err = ds.GetSummaryHostVPPAppInstalls(ctx, nil, vpp3) @@ -330,8 +330,9 @@ func createVPPAppInstallRequest(t *testing.T, ds *Datastore, host *fleet.Host, a require.NoError(t, err) ExecAdhocSQL(t, ds, func(q sqlx.ExtContext) error { - _, err := q.ExecContext(ctx, `INSERT INTO host_vpp_software_installs (host_id, adam_id, command_uuid, user_id) VALUES (?, ?, ?, ?)`, - host.ID, adamID, cmdUUID, userID) + _, err := q.ExecContext(ctx, + `INSERT INTO host_vpp_software_installs (host_id, adam_id, platform, command_uuid, user_id) VALUES (?, ?, ?, ?, ?)`, + host.ID, adamID, host.Platform, cmdUUID, userID) return err }) return cmdUUID @@ -401,10 +402,10 @@ func testVPPApps(t *testing.T, ds *Datastore) { GlobalRole: ptr.String(fleet.RoleAdmin), }) require.NoError(t, err) - err = ds.InsertHostVPPSoftwareInstall(ctx, 1, u.ID, app1.AdamID, "a", "b") + err = ds.InsertHostVPPSoftwareInstall(ctx, 1, u.ID, app1.VPPAppID, "a", "b") require.NoError(t, err) - err = ds.InsertHostVPPSoftwareInstall(ctx, 2, u.ID, app2.AdamID, "c", "d") + err = ds.InsertHostVPPSoftwareInstall(ctx, 2, u.ID, app2.VPPAppID, "c", "d") require.NoError(t, err) var results []struct { diff --git a/server/fleet/datastore.go b/server/fleet/datastore.go index 7c61870d68..6847f398af 100644 --- a/server/fleet/datastore.go +++ b/server/fleet/datastore.go @@ -1572,7 +1572,7 @@ type Datastore interface { // GetSummaryHostVPPAppInstalls returns the VPP app install summary for the // given team and VPP app adam_id. - GetSummaryHostVPPAppInstalls(ctx context.Context, teamID *uint, adamID string) (*VPPAppStatusSummary, error) + GetSummaryHostVPPAppInstalls(ctx context.Context, teamID *uint, appID VPPAppID) (*VPPAppStatusSummary, error) GetSoftwareInstallResults(ctx context.Context, resultsUUID string) (*HostSoftwareInstallerResult, error) @@ -1591,7 +1591,7 @@ type Datastore interface { SetTeamVPPApps(ctx context.Context, teamID *uint, appIDs []VPPAppID) error InsertVPPAppWithTeam(ctx context.Context, app *VPPApp, teamID *uint) (*VPPApp, error) - InsertHostVPPSoftwareInstall(ctx context.Context, hostID, userID uint, adamID, commandUUID, associatedEventID string) error + InsertHostVPPSoftwareInstall(ctx context.Context, hostID, userID uint, appID VPPAppID, commandUUID, associatedEventID string) error GetPastActivityDataForVPPAppInstall(ctx context.Context, commandResults *mdm.CommandResults) (*User, *ActivityInstalledAppStoreApp, error) } diff --git a/server/mock/datastore_mock.go b/server/mock/datastore_mock.go index 7c9523da38..e062476d60 100644 --- a/server/mock/datastore_mock.go +++ b/server/mock/datastore_mock.go @@ -988,7 +988,7 @@ type DeleteVPPAppFromTeamFunc func(ctx context.Context, teamID *uint, appID flee type GetSummaryHostSoftwareInstallsFunc func(ctx context.Context, installerID uint) (*fleet.SoftwareInstallerStatusSummary, error) -type GetSummaryHostVPPAppInstallsFunc func(ctx context.Context, teamID *uint, adamID string) (*fleet.VPPAppStatusSummary, error) +type GetSummaryHostVPPAppInstallsFunc func(ctx context.Context, teamID *uint, appID fleet.VPPAppID) (*fleet.VPPAppStatusSummary, error) type GetSoftwareInstallResultsFunc func(ctx context.Context, resultsUUID string) (*fleet.HostSoftwareInstallerResult, error) @@ -1006,7 +1006,7 @@ type SetTeamVPPAppsFunc func(ctx context.Context, teamID *uint, appIDs []fleet.V type InsertVPPAppWithTeamFunc func(ctx context.Context, app *fleet.VPPApp, teamID *uint) (*fleet.VPPApp, error) -type InsertHostVPPSoftwareInstallFunc func(ctx context.Context, hostID uint, userID uint, adamID string, commandUUID string, associatedEventID string) error +type InsertHostVPPSoftwareInstallFunc func(ctx context.Context, hostID uint, userID uint, appID fleet.VPPAppID, commandUUID string, associatedEventID string) error type GetPastActivityDataForVPPAppInstallFunc func(ctx context.Context, commandResults *mdm.CommandResults) (*fleet.User, *fleet.ActivityInstalledAppStoreApp, error) @@ -5887,11 +5887,11 @@ func (s *DataStore) GetSummaryHostSoftwareInstalls(ctx context.Context, installe return s.GetSummaryHostSoftwareInstallsFunc(ctx, installerID) } -func (s *DataStore) GetSummaryHostVPPAppInstalls(ctx context.Context, teamID *uint, adamID string) (*fleet.VPPAppStatusSummary, error) { +func (s *DataStore) GetSummaryHostVPPAppInstalls(ctx context.Context, teamID *uint, appID fleet.VPPAppID) (*fleet.VPPAppStatusSummary, error) { s.mu.Lock() s.GetSummaryHostVPPAppInstallsFuncInvoked = true s.mu.Unlock() - return s.GetSummaryHostVPPAppInstallsFunc(ctx, teamID, adamID) + return s.GetSummaryHostVPPAppInstallsFunc(ctx, teamID, appID) } func (s *DataStore) GetSoftwareInstallResults(ctx context.Context, resultsUUID string) (*fleet.HostSoftwareInstallerResult, error) { @@ -5950,11 +5950,11 @@ func (s *DataStore) InsertVPPAppWithTeam(ctx context.Context, app *fleet.VPPApp, return s.InsertVPPAppWithTeamFunc(ctx, app, teamID) } -func (s *DataStore) InsertHostVPPSoftwareInstall(ctx context.Context, hostID uint, userID uint, adamID string, commandUUID string, associatedEventID string) error { +func (s *DataStore) InsertHostVPPSoftwareInstall(ctx context.Context, hostID uint, userID uint, appID fleet.VPPAppID, commandUUID string, associatedEventID string) error { s.mu.Lock() s.InsertHostVPPSoftwareInstallFuncInvoked = true s.mu.Unlock() - return s.InsertHostVPPSoftwareInstallFunc(ctx, hostID, userID, adamID, commandUUID, associatedEventID) + return s.InsertHostVPPSoftwareInstallFunc(ctx, hostID, userID, appID, commandUUID, associatedEventID) } func (s *DataStore) GetPastActivityDataForVPPAppInstall(ctx context.Context, commandResults *mdm.CommandResults) (*fleet.User, *fleet.ActivityInstalledAppStoreApp, error) { diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index 44b1e95271..b4180fb2b2 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -10290,7 +10290,6 @@ func (s *integrationMDMTestSuite) TestVPPApps() { extraAvailable: 1}, } - expectedInstalls := 1 for name, install := range installs { t.Run(name, func(t *testing.T) { @@ -10307,6 +10306,21 @@ func (s *integrationMDMTestSuite) TestVPPApps() { strconv.Itoa(int(team.ID)), "software_title_id", strconv.Itoa(int(titleID))) require.Equal(t, 1, countResp.Count) + // Get pending activity + var hostActivitiesResp listHostUpcomingActivitiesResponse + s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/hosts/%d/activities/upcoming", installHost.ID), + nil, http.StatusOK, &hostActivitiesResp) + activitiesToString := func(activities []*fleet.Activity) []string { + var res []string + for _, activity := range activities { + res = append(res, fmt.Sprintf("%+v", activity)) + } + return res + } + require.Len(t, hostActivitiesResp.Activities, 1, "got activities: %v", activitiesToString(hostActivitiesResp.Activities)) + assert.Equal(t, hostActivitiesResp.Activities[0].Type, fleet.ActivityInstalledAppStoreApp{}.ActivityName()) + assert.EqualValues(t, 1, hostActivitiesResp.Count) + // Simulate successful installation on the host cmd, err = mdmClient.Idle() require.NoError(t, err) @@ -10324,12 +10338,11 @@ func (s *integrationMDMTestSuite) TestVPPApps() { listResp = listHostsResponse{} s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &listResp, "software_status", "installed", "team_id", strconv.Itoa(int(team.ID)), "software_title_id", strconv.Itoa(int(titleID))) - assert.Len(t, listResp.Hosts, expectedInstalls) + assert.Len(t, listResp.Hosts, 1) countResp = countHostsResponse{} s.DoJSON("GET", "/api/latest/fleet/hosts/count", nil, http.StatusOK, &countResp, "software_status", "installed", "team_id", strconv.Itoa(int(team.ID)), "software_title_id", strconv.Itoa(int(titleID))) - assert.Equal(t, expectedInstalls, countResp.Count) - expectedInstalls++ + assert.Equal(t, 1, countResp.Count) s.lastActivityMatches( fleet.ActivityInstalledAppStoreApp{}.ActivityName(), diff --git a/server/service/software_titles.go b/server/service/software_titles.go index 82e367c7e6..39f38177ae 100644 --- a/server/service/software_titles.go +++ b/server/service/software_titles.go @@ -198,7 +198,7 @@ func (svc *Service) SoftwareTitleByID(ctx context.Context, id uint, teamID *uint return nil, ctxerr.Wrap(ctx, err, "get VPP app metadata") } if meta != nil { - summary, err := svc.ds.GetSummaryHostVPPAppInstalls(ctx, teamID, meta.VPPAppID.AdamID) + summary, err := svc.ds.GetSummaryHostVPPAppInstalls(ctx, teamID, meta.VPPAppID) if err != nil { return nil, ctxerr.Wrap(ctx, err, "get VPP app status summary") } From 7abae84be5f1db4974b3d164a674379baf5f99aa Mon Sep 17 00:00:00 2001 From: Dante Catalfamo <43040593+dantecatalfamo@users.noreply.github.com> Date: Thu, 1 Aug 2024 14:36:40 -0400 Subject: [PATCH 31/88] Use gitops format for software installer query (#20891) #20747 --- changes/20747-gitops-software-query | 1 + cmd/fleetctl/gitops_test.go | 28 +++++++---- .../testdata/gitops/lib/query_multiple.yml | 11 +---- .../gitops/lib/query_multiple_apply.yml | 11 +++++ .../testdata/gitops/lib/query_ruby.yml | 5 +- .../testdata/gitops/lib/query_ruby_apply.yml | 5 ++ .../testdata/gitops/lib/query_ruby_env.yml | 2 + ...r_pre_condition_multiple_queries_apply.yml | 23 +++++++++ .../team_software_installer_valid_apply.yml | 25 ++++++++++ ...eam_software_installer_valid_env_query.yml | 25 ++++++++++ server/service/client.go | 47 +++++++++++++++---- 11 files changed, 154 insertions(+), 29 deletions(-) create mode 100644 changes/20747-gitops-software-query create mode 100644 cmd/fleetctl/testdata/gitops/lib/query_multiple_apply.yml create mode 100644 cmd/fleetctl/testdata/gitops/lib/query_ruby_apply.yml create mode 100644 cmd/fleetctl/testdata/gitops/lib/query_ruby_env.yml create mode 100644 cmd/fleetctl/testdata/gitops/team_software_installer_pre_condition_multiple_queries_apply.yml create mode 100644 cmd/fleetctl/testdata/gitops/team_software_installer_valid_apply.yml create mode 100644 cmd/fleetctl/testdata/gitops/team_software_installer_valid_env_query.yml diff --git a/changes/20747-gitops-software-query b/changes/20747-gitops-software-query new file mode 100644 index 0000000000..100efc17f3 --- /dev/null +++ b/changes/20747-gitops-software-query @@ -0,0 +1 @@ +- Use new gitops format for software pre install query diff --git a/cmd/fleetctl/gitops_test.go b/cmd/fleetctl/gitops_test.go index 5f504a8106..826dd43374 100644 --- a/cmd/fleetctl/gitops_test.go +++ b/cmd/fleetctl/gitops_test.go @@ -1215,7 +1215,9 @@ func TestTeamSofwareInstallersGitOps(t *testing.T) { {"testdata/gitops/team_software_installer_unsupported.yml", "The file should be .pkg, .msi, .exe or .deb."}, {"testdata/gitops/team_software_installer_too_large.yml", "The maximum file size is 500 MB"}, {"testdata/gitops/team_software_installer_valid.yml", ""}, + {"testdata/gitops/team_software_installer_valid_apply.yml", ""}, {"testdata/gitops/team_software_installer_pre_condition_multiple_queries.yml", "should have only one query."}, + {"testdata/gitops/team_software_installer_pre_condition_multiple_queries_apply.yml", "should have only one query."}, {"testdata/gitops/team_software_installer_pre_condition_not_found.yml", "no such file or directory"}, {"testdata/gitops/team_software_installer_install_not_found.yml", "no such file or directory"}, {"testdata/gitops/team_software_installer_post_install_not_found.yml", "no such file or directory"}, @@ -1224,14 +1226,7 @@ func TestTeamSofwareInstallersGitOps(t *testing.T) { } for _, c := range cases { t.Run(filepath.Base(c.file), func(t *testing.T) { - ds, _, _ := setupFullGitOpsPremiumServer(t) - - ds.SetTeamVPPAppsFunc = func(ctx context.Context, teamID *uint, adamIDs []fleet.VPPAppID) error { - return nil - } - ds.BatchInsertVPPAppsFunc = func(ctx context.Context, apps []*fleet.VPPApp) error { - return nil - } + setupFullGitOpsPremiumServer(t) _, err := runAppNoChecks([]string{"gitops", "-f", c.file}) if c.wantErr == "" { @@ -1243,6 +1238,23 @@ func TestTeamSofwareInstallersGitOps(t *testing.T) { } } +func TestTeamSoftwareInstallersGitopsQueryEnv(t *testing.T) { + startSoftwareInstallerServer(t) + ds, _, _ := setupFullGitOpsPremiumServer(t) + + t.Setenv("QUERY_VAR", "IT_WORKS") + + ds.BatchSetSoftwareInstallersFunc = func(ctx context.Context, tmID *uint, installers []*fleet.UploadSoftwareInstallerPayload) error { + if installers[0].PreInstallQuery != "select IT_WORKS" { + return fmt.Errorf("Missing env var, got %s", installers[0].PreInstallQuery) + } + return nil + } + + _, err := runAppNoChecks([]string{"gitops", "-f", "testdata/gitops/team_software_installer_valid_env_query.yml"}) + require.NoError(t, err) +} + func TestTeamVPPAppsGitOps(t *testing.T) { config := &appleVPPConfigSrvConf{ Assets: []vpp.Asset{ diff --git a/cmd/fleetctl/testdata/gitops/lib/query_multiple.yml b/cmd/fleetctl/testdata/gitops/lib/query_multiple.yml index c3109b5f71..f14ea9ea0e 100644 --- a/cmd/fleetctl/testdata/gitops/lib/query_multiple.yml +++ b/cmd/fleetctl/testdata/gitops/lib/query_multiple.yml @@ -1,11 +1,4 @@ -apiVersion: v1 -kind: query -spec: - name: query_ruby +- name: query_ruby query: select 1 ---- -apiVersion: v1 -kind: query -spec: - name: query_ruby2 +- name: query_ruby2 query: select 2 diff --git a/cmd/fleetctl/testdata/gitops/lib/query_multiple_apply.yml b/cmd/fleetctl/testdata/gitops/lib/query_multiple_apply.yml new file mode 100644 index 0000000000..c3109b5f71 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/lib/query_multiple_apply.yml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: query +spec: + name: query_ruby + query: select 1 +--- +apiVersion: v1 +kind: query +spec: + name: query_ruby2 + query: select 2 diff --git a/cmd/fleetctl/testdata/gitops/lib/query_ruby.yml b/cmd/fleetctl/testdata/gitops/lib/query_ruby.yml index 28714447bf..bb61c6b32a 100644 --- a/cmd/fleetctl/testdata/gitops/lib/query_ruby.yml +++ b/cmd/fleetctl/testdata/gitops/lib/query_ruby.yml @@ -1,5 +1,2 @@ -apiVersion: v1 -kind: query -spec: - name: query_ruby +- name: query_ruby query: select 1 diff --git a/cmd/fleetctl/testdata/gitops/lib/query_ruby_apply.yml b/cmd/fleetctl/testdata/gitops/lib/query_ruby_apply.yml new file mode 100644 index 0000000000..28714447bf --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/lib/query_ruby_apply.yml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: query +spec: + name: query_ruby + query: select 1 diff --git a/cmd/fleetctl/testdata/gitops/lib/query_ruby_env.yml b/cmd/fleetctl/testdata/gitops/lib/query_ruby_env.yml new file mode 100644 index 0000000000..c9b15ff229 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/lib/query_ruby_env.yml @@ -0,0 +1,2 @@ +- name: query_ruby + query: select ${QUERY_VAR} diff --git a/cmd/fleetctl/testdata/gitops/team_software_installer_pre_condition_multiple_queries_apply.yml b/cmd/fleetctl/testdata/gitops/team_software_installer_pre_condition_multiple_queries_apply.yml new file mode 100644 index 0000000000..7c88f9963d --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/team_software_installer_pre_condition_multiple_queries_apply.yml @@ -0,0 +1,23 @@ +name: "${TEST_TEAM_NAME}" +team_settings: + secrets: + - secret: "ABC" + features: + enable_host_users: true + enable_software_inventory: true + host_expiry_settings: + host_expiry_enabled: true + host_expiry_window: 30 +agent_options: +controls: +policies: +queries: +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/install_ruby.sh + pre_install_query: + path: lib/query_multiple_apply.yml + post_install_script: + path: lib/post_install_ruby.sh diff --git a/cmd/fleetctl/testdata/gitops/team_software_installer_valid_apply.yml b/cmd/fleetctl/testdata/gitops/team_software_installer_valid_apply.yml new file mode 100644 index 0000000000..9fd14c4922 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/team_software_installer_valid_apply.yml @@ -0,0 +1,25 @@ +name: "${TEST_TEAM_NAME}" +team_settings: + secrets: + - secret: "ABC" + features: + enable_host_users: true + enable_software_inventory: true + host_expiry_settings: + host_expiry_enabled: true + host_expiry_window: 30 +agent_options: +controls: +policies: +queries: +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/install_ruby.sh + pre_install_query: + path: lib/query_ruby_apply.yml + post_install_script: + path: lib/post_install_ruby.sh + - url: ${SOFTWARE_INSTALLER_URL}/other.deb + self_service: true diff --git a/cmd/fleetctl/testdata/gitops/team_software_installer_valid_env_query.yml b/cmd/fleetctl/testdata/gitops/team_software_installer_valid_env_query.yml new file mode 100644 index 0000000000..1c60d3f469 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/team_software_installer_valid_env_query.yml @@ -0,0 +1,25 @@ +name: "${TEST_TEAM_NAME}" +team_settings: + secrets: + - secret: "ABC" + features: + enable_host_users: true + enable_software_inventory: true + host_expiry_settings: + host_expiry_enabled: true + host_expiry_window: 30 +agent_options: +controls: +policies: +queries: +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/install_ruby.sh + pre_install_query: + path: lib/query_ruby_env.yml + post_install_script: + path: lib/post_install_ruby.sh + - url: ${SOFTWARE_INSTALLER_URL}/other.deb + self_service: true diff --git a/server/service/client.go b/server/service/client.go index 73515d0211..09ab08e031 100644 --- a/server/service/client.go +++ b/server/service/client.go @@ -14,6 +14,7 @@ import ( "time" "golang.org/x/text/unicode/norm" + "gopkg.in/yaml.v2" "github.com/fleetdm/fleet/v4/pkg/optjson" "github.com/fleetdm/fleet/v4/pkg/spec" @@ -620,20 +621,50 @@ func (c *Client) ApplyGroup( return nil, fmt.Errorf("reading pre-install query: %w", err) } - group, err := spec.GroupFromBytes(rawSpec) + rawSpecExpanded, err := spec.ExpandEnvBytes(rawSpec) if err != nil { - return nil, fmt.Errorf("Couldn't edit software (%s). Unable to parse pre-install query YAML file %s: %w", si.URL, queryFile, err) + return nil, fmt.Errorf("Couldn't exit software (%s). Unable to expand environment variable in YAML file %s: %w", si.URL, queryFile, err) } - if len(group.Queries) > 1 { - return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s should have only one query.", si.URL, queryFile) + var top any + + if err := yaml.Unmarshal(rawSpecExpanded, &top); err != nil { + return nil, fmt.Errorf("Couldn't exit software (%s). Unable to expand environment variable in YAML file %s: %w", si.URL, queryFile, err) } - if len(group.Queries) == 0 { - return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s doesn't have a query defined.", si.URL, queryFile) - } + if _, ok := top.(map[any]any); ok { + // Old apply format + group, err := spec.GroupFromBytes(rawSpecExpanded) + if err != nil { + return nil, fmt.Errorf("Couldn't edit software (%s). Unable to parse pre-install apply format query YAML file %s: %w", si.URL, queryFile, err) + } - qc = group.Queries[0].Query + if len(group.Queries) > 1 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s should have only one query.", si.URL, queryFile) + } + + if len(group.Queries) == 0 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s doesn't have a query defined.", si.URL, queryFile) + } + + qc = group.Queries[0].Query + } else { + // Gitops format + var querySpecs []fleet.QuerySpec + if err := yaml.Unmarshal(rawSpecExpanded, &querySpecs); err != nil { + return nil, fmt.Errorf("Couldn't edit software (%s). Unable to parse pre-install query YAML file %s: %w", si.URL, queryFile, err) + } + + if len(querySpecs) > 1 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s should have only one query.", si.URL, queryFile) + } + + if len(querySpecs) == 0 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s doesn't have a query defined.", si.URL, queryFile) + } + + qc = querySpecs[0].Query + } } var ic []byte From 8fb64cdd0049aebecd84f84307011de1035173af Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Fri, 2 Aug 2024 04:04:18 +0900 Subject: [PATCH 32/88] Banner update (#20925) Updated the banner image on https://github.com/fleetdm/fleet/tree/main/tools/fleetctl-npm --------- Co-authored-by: Mike McNeil --- tools/fleetctl-npm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/fleetctl-npm/README.md b/tools/fleetctl-npm/README.md index ecb4499e93..8ac619853d 100644 --- a/tools/fleetctl-npm/README.md +++ b/tools/fleetctl-npm/README.md @@ -1,4 +1,4 @@ -[![banner-fleet-cloud-city](https://user-images.githubusercontent.com/618009/98254443-eaf21100-1f41-11eb-9e2c-63a0545601f3.jpg)](https://fleetdm.com) +![fleet-banner](https://github.com/user-attachments/assets/fa90b8b2-cb3e-4277-a561-5719968c4bbd) Use the `fleetctl` CLI to interact with Fleet, the lightweight telemetry platform for servers and workstations. Have a look at the [Fleet README](https://github.com/fleetdm/fleet#readme) for more information. @@ -8,4 +8,4 @@ From the command line, install `fleetctl` with `npm install -g fleetctl`. ## Usage -See the [fleetctl documentation](https://fleetdm.com/docs/using-fleet/fleetctl-CLI) or `fleetctl --help` for usage instructions. \ No newline at end of file +See the [fleetctl documentation](https://fleetdm.com/docs/using-fleet/fleetctl-cli) or `fleetctl --help` for usage instructions. From 3df700b1e6d9a4594a3eef07df6c4c031ab3a16b Mon Sep 17 00:00:00 2001 From: Luke Heath Date: Thu, 1 Aug 2024 12:18:59 -0700 Subject: [PATCH 33/88] Update release script to branch off main for minor releases (#20956) --- tools/release/publish_release.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/release/publish_release.sh b/tools/release/publish_release.sh index ea15c37499..6aec1605e7 100755 --- a/tools/release/publish_release.sh +++ b/tools/release/publish_release.sh @@ -628,6 +628,8 @@ start_ver_tag=fleet-$start_version if [[ "$minor" == "true" ]]; then echo "Minor release from $start_version to $next_ver" + # For scheduled minor releases, we want to branch off of main + start_ver_tag="main" else echo "Patch release from $start_version to $next_ver" fi @@ -699,7 +701,7 @@ if [ "$cherry_pick_resolved" = "false" ]; then git checkout $start_ver_tag git pull origin $start_ver_tag else - echo "DRYRUN: Would have checked out starting tag $start_ver_tag" + echo "DRYRUN: Would have checked out starting at $start_ver_tag" fi local_exists=$(git branch | $GREP_CMD $target_branch) @@ -730,7 +732,7 @@ if [ "$cherry_pick_resolved" = "false" ]; then prs_for_issue=$(gh api repos/fleetdm/fleet/issues/$issue/timeline --paginate | jq -r '.[]' | $GREP_CMD "fleetdm/fleet/" | $GREP_CMD -oP "pulls\/\K(?:\d+)") echo -n "https://github.com/fleetdm/fleet/issues/$issue" if [[ "$prs_for_issue" == "" ]]; then - echo -n " NO PR's found, please verify they are not missing in the issue, if no PR's were required for this ticket please reconsider adding it to this release." + echo -n " - No PRs found, please verify they are not missing in the issue." fi for val in $prs_for_issue; do echo -n " $val" From d95a12bda647933a8cb4351670d2f861b756a5d1 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 1 Aug 2024 14:23:28 -0500 Subject: [PATCH 34/88] Website: update homepage and endpoint ops personalization (#20961) Closes: #20736 Changes: - Updated the category switcher on the (buying situation agnostic) homepage to be MDM, IT engineering and Security engineering. - Updated the personalization of the product category sections of the homepage - Updated the tagline for the endpoint ops page. --- website/assets/styles/pages/homepage.less | 8 ++-- website/views/pages/endpoint-ops.ejs | 2 +- website/views/pages/homepage.ejs | 46 +++++++++++------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/website/assets/styles/pages/homepage.less b/website/assets/styles/pages/homepage.less index 72c04a9868..b9f9f5b262 100644 --- a/website/assets/styles/pages/homepage.less +++ b/website/assets/styles/pages/homepage.less @@ -338,10 +338,10 @@ .selected { font-weight: 700; } - .eo-selected { + .it-selected { transform: translateX(100%); } - .vm-selected { + .security-selected { transform: translateX(200%); } } @@ -999,11 +999,11 @@ height: 56px; width: 100%; } - .eo-selected { + .it-selected { width: 100%; transform: translateY(56px); } - .vm-selected { + .security-selected { width: 100%; transform: translateY(113px); } diff --git a/website/views/pages/endpoint-ops.ejs b/website/views/pages/endpoint-ops.ejs index dc107d725d..c9cfbb40fa 100644 --- a/website/views/pages/endpoint-ops.ejs +++ b/website/views/pages/endpoint-ops.ejs @@ -3,7 +3,7 @@
    -

    Endpoint operations

    +

    Endpoint operations <%= ['eo-security', 'vm'].includes(primaryBuyingSituation) ? 'for security' : ['eo-it', 'mdm'].includes(primaryBuyingSituation) ? 'for IT' : '' %>

    <%= primaryBuyingSituation==='eo-security'? 'Instrument your endpoints' : 'Understand your computers'%>

    diff --git a/website/views/pages/homepage.ejs b/website/views/pages/homepage.ejs index d07b372d36..99d70bfbaa 100644 --- a/website/views/pages/homepage.ejs +++ b/website/views/pages/homepage.ejs @@ -27,9 +27,9 @@ <% if(!primaryBuyingSituation){ %>
    Device management
    -
    Endpoint ops
    -
    Vulnerability management
    -
    +
    IT engineering
    +
    Security engineering
    +
    <%/* Device management block */%>
    @@ -49,38 +49,38 @@
    - <%/* Endpoint ops block */%> -
    + <%/* IT engineering block */%> +
    Endpoint ops
    - Pulse check anything -

    Use a live connection to every endpoint to simplify audit, compliance, and reporting from workstations to data centers.

    + Automate anything +

    Remotely run scripts and prompts to complete tasks on every kind of computer, including Linux.

    Ship data to any platform

    Ship logs to any platform like Splunk, Snowflake, or any streaming infrastructure like AWS Kinesis and Apache Kafka.

    Osquery on easy mode

    Use "read-only" mode or enable remote scripting to automate anything on every operating system, including Linux.

    - <%/* Vulnerability management block */%> -
    + <%/* Security engineering block */%> +
    An orb being scanned for vulnerabilities
    - Report what matters -

    Let's face it, most built-in graphs leave you wanting more. Report MTTR and any other custom metrics exactly the way you want to using fresh data from real computers.

    - Deep context from the environment -

    Fleet gives you data down to the chip level on every endpoint to help you make sense of which vulnerabilities to prioritize.

    - Untangle your security stack -

    Use open data and APIs to connect your vulnerability solution with osquery, the agent you might already have deployed.

    + Osquery on easy mode +

    Use "read-only" mode or enable remote scripting to automate anything on every operating system, including Linux.

    + Pulse check anything +

    Use a live connection to every endpoint to simplify audit, compliance, and reporting from workstations to data centers.

    + Ship data to any platform +

    Ship logs to any platform like Splunk, Snowflake, or any streaming infrastructure like AWS Kinesis and Apache Kafka.

    @@ -104,11 +104,11 @@ <% } %>
    -

    Endpoint ops

    +

    <%= primaryBuyingSituation==='eo-security'? 'Security engineering' : 'IT engineering'%>

    <%= primaryBuyingSituation==='eo-security'? 'Instrument your endpoints' : 'Understand your computers'%>

    A <%= primaryBuyingSituation==='eo-security'? 'lightweight' : 'quick-fast' %> way to gather <%= primaryBuyingSituation==='vm'? 'patch level and custom reports across all your computing devices, even in OT and production environments' : primaryBuyingSituation==='eo-security'? 'deep context and custom telemetry across all your endpoints, even servers' : primaryBuyingSituation==='mdm'||primaryBuyingSituation==='eo-it'? 'compliance and inventory data across all your devices' : 'device data across all your computers' %>. Pulse check or automate anything on any platform.

    - Start with endpoint ops + Start with <%= primaryBuyingSituation==='eo-security' ? 'security engineering' : 'IT engineering'%>
    @@ -171,11 +171,11 @@ Endpoint ops
    -

    Endpoint ops

    -

    <%= primaryBuyingSituation==='eo-security'? 'Instrument your endpoints' : 'Understand your computers'%>

    -

    A <%= primaryBuyingSituation==='eo-security'? 'lightweight' : 'quick-fast' %> way to gather <%= primaryBuyingSituation==='vm'? 'patch level and custom reports across all your computing devices, even in OT and production environments' : primaryBuyingSituation==='eo-security'? 'deep context and custom telemetry across all your endpoints, even servers' : primaryBuyingSituation==='mdm'||primaryBuyingSituation==='eo-it'? 'compliance and inventory data across all your devices' : 'device data across all your computers' %>. Pulse check or automate anything on any platform.

    +

    <%= primaryBuyingSituation==='mdm' ? 'IT engineering' : 'Security engineering'%>

    +

    <%= primaryBuyingSituation==='vm'? 'Instrument your endpoints' : 'Understand your computers'%>

    +

    A <%= primaryBuyingSituation==='vm'? 'lightweight' : 'quick-fast' %> way to gather <%= primaryBuyingSituation==='vm'? 'patch level and custom reports across all your computing devices, even in OT and production environments' : primaryBuyingSituation==='vm'? 'deep context and custom telemetry across all your endpoints, even servers' : primaryBuyingSituation==='mdm'||primaryBuyingSituation==='eo-it'? 'compliance and inventory data across all your devices' : 'device data across all your computers' %>. Pulse check or automate anything on any platform.

    - Start with endpoint ops + Start with <%= primaryBuyingSituation==='mdm' ? 'IT engineering' : 'security engineering'%>
    From bf3d849bd01434c090b2bc9ed973ffb2c45ff36b Mon Sep 17 00:00:00 2001 From: Dante Catalfamo <43040593+dantecatalfamo@users.noreply.github.com> Date: Thu, 1 Aug 2024 15:41:37 -0400 Subject: [PATCH 35/88] Fix Deleted Host Software Installs Details (#20820) #20271 This fix requires an accompanying front end fix to pass the `display_name` from the activity feed to the modal when displaying the install results. --- changes/20271-deleted-host-software-installs | 1 + ee/server/service/software_installers.go | 34 +++++++++++++++-- server/datastore/mysql/hosts.go | 5 ++- server/datastore/mysql/hosts_test.go | 9 +++++ ...20947_AddSoftwareInstallResultDeletedAt.go | 38 +++++++++++++++++++ server/datastore/mysql/schema.sql | 5 ++- server/datastore/mysql/software_installers.go | 7 ++-- .../mysql/software_installers_test.go | 1 - server/fleet/software_installer.go | 8 ++-- server/service/integration_enterprise_test.go | 16 ++++++++ 10 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 changes/20271-deleted-host-software-installs create mode 100644 server/datastore/mysql/migrations/tables/20240729120947_AddSoftwareInstallResultDeletedAt.go diff --git a/changes/20271-deleted-host-software-installs b/changes/20271-deleted-host-software-installs new file mode 100644 index 0000000000..674b8a823f --- /dev/null +++ b/changes/20271-deleted-host-software-installs @@ -0,0 +1 @@ +- Fig bug where software install results could not be retrieved for deleted hosts in the activity feed diff --git a/ee/server/service/software_installers.go b/ee/server/service/software_installers.go index b17eee2b73..8754879992 100644 --- a/ee/server/service/software_installers.go +++ b/ee/server/service/software_installers.go @@ -463,12 +463,38 @@ func (svc *Service) GetSoftwareInstallResults(ctx context.Context, resultUUID st res, err := svc.ds.GetSoftwareInstallResults(ctx, resultUUID) if err != nil { - return nil, err + if fleet.IsNotFound(err) { + if err := svc.authz.Authorize(ctx, &fleet.HostSoftwareInstallerResultAuthz{}, fleet.ActionRead); err != nil { + return nil, err + } + } + svc.authz.SkipAuthorization(ctx) + return nil, ctxerr.Wrap(ctx, err, "get software install result") } - // Team specific auth check - if err := svc.authz.Authorize(ctx, &fleet.HostSoftwareInstallerResultAuthz{HostTeamID: res.HostTeamID}, fleet.ActionRead); err != nil { - return nil, err + if res.HostDeletedAt == nil { + // host is not deleted, get it and authorize for the host's team + host, err := svc.ds.HostLite(ctx, res.HostID) + // if error is because the host does not exist, check first if the user + // had access to run a script (to prevent leaking valid host ids). + if err != nil { + if fleet.IsNotFound(err) { + if err := svc.authz.Authorize(ctx, &fleet.HostSoftwareInstallerResultAuthz{}, fleet.ActionRead); err != nil { + return nil, err + } + } + svc.authz.SkipAuthorization(ctx) + return nil, ctxerr.Wrap(ctx, err, "get host lite") + } + // Team specific auth check + if err := svc.authz.Authorize(ctx, &fleet.HostSoftwareInstallerResultAuthz{HostTeamID: host.TeamID}, fleet.ActionRead); err != nil { + return nil, err + } + } else { + // host was deleted, authorize for no-team as a fallback + if err := svc.authz.Authorize(ctx, &fleet.HostSoftwareInstallerResultAuthz{}, fleet.ActionRead); err != nil { + return nil, err + } } res.EnhanceOutputDetails() diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index 47125e16c8..fb4b88f077 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -541,7 +541,8 @@ var additionalHostRefsByUUID = map[string]string{ // the rows are not deleted when the host is deleted, only a soft delete is // performed by setting a timestamp column to the current time. var additionalHostRefsSoftDelete = map[string]string{ - "host_script_results": "host_deleted_at", + "host_script_results": "host_deleted_at", + "host_software_installs": "host_deleted_at", } func (ds *Datastore) DeleteHost(ctx context.Context, hid uint) error { @@ -4943,7 +4944,7 @@ func (ds *Datastore) ListUpcomingHostMaintenanceWindows(ctx context.Context, hid WHERE hce.host_id = ? AND - ce.start_time > NOW() + ce.start_time > NOW() ORDER BY ce.start_time ` diff --git a/server/datastore/mysql/hosts_test.go b/server/datastore/mysql/hosts_test.go index ed703b0f54..379adf166d 100644 --- a/server/datastore/mysql/hosts_test.go +++ b/server/datastore/mysql/hosts_test.go @@ -6743,6 +6743,15 @@ func testHostsDeleteHosts(t *testing.T, ds *Datastore) { `, host.ID, calendarEventID) require.NoError(t, err) + softwareInstaller, err := ds.MatchOrCreateSoftwareInstaller(context.Background(), &fleet.UploadSoftwareInstallerPayload{ + InstallScript: "", + PreInstallQuery: "", + Title: "ChocolateRain", + }) + require.NoError(t, err) + _, err = ds.InsertSoftwareInstallRequest(context.Background(), host.ID, softwareInstaller, false) + require.NoError(t, err) + // Check there's an entry for the host in all the associated tables. for _, hostRef := range hostRefs { var ok bool diff --git a/server/datastore/mysql/migrations/tables/20240729120947_AddSoftwareInstallResultDeletedAt.go b/server/datastore/mysql/migrations/tables/20240729120947_AddSoftwareInstallResultDeletedAt.go new file mode 100644 index 0000000000..bd4219364d --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20240729120947_AddSoftwareInstallResultDeletedAt.go @@ -0,0 +1,38 @@ +package tables + +import ( + "database/sql" + "fmt" +) + +func init() { + MigrationClient.AddMigration(Up_20240729120947, Down_20240729120947) +} + +func Up_20240729120947(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE host_software_installs ADD COLUMN host_deleted_at timestamp NULL DEFAULT NULL") + if err != nil { + return fmt.Errorf("failed to create host_deleted_at column on host_software_installs table: %w", err) + } + _, err = tx.Exec(` +UPDATE + host_software_installs i +LEFT JOIN + hosts h + ON i.host_id = h.id +SET + i.host_deleted_at = NOW() +WHERE + i.host_deleted_at IS NULL +AND + h.id IS NULL +`) + if err != nil { + return fmt.Errorf("failed to update host_software_installs.host_deleted_at for hosts that no longer exist: %w", err) + } + return nil +} + +func Down_20240729120947(tx *sql.Tx) error { + return nil +} diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index 9ed81803bd..73e02ac322 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -519,6 +519,7 @@ CREATE TABLE `host_software_installs` ( `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `self_service` tinyint(1) NOT NULL DEFAULT '0', + `host_deleted_at` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_host_software_installs_execution_id` (`execution_id`), KEY `fk_host_software_installs_installer_id` (`software_installer_id`), @@ -969,9 +970,9 @@ CREATE TABLE `migration_status_tables` ( `tstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`) -) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=293 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=294 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'),(292,20240801115359,1,'2020-01-01 01:01:01'); +INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240729120947,1,'2020-01-01 01:01:01'),(289,20240730171504,1,'2020-01-01 01:01:01'),(290,20240730174056,1,'2020-01-01 01:01:01'),(291,20240730215453,1,'2020-01-01 01:01:01'),(292,20240730374423,1,'2020-01-01 01:01:01'),(293,20240801115359,1,'2020-01-01 01:01:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `mobile_device_management_solutions` ( diff --git a/server/datastore/mysql/software_installers.go b/server/datastore/mysql/software_installers.go index 51c952151c..c491d38139 100644 --- a/server/datastore/mysql/software_installers.go +++ b/server/datastore/mysql/software_installers.go @@ -337,19 +337,17 @@ SELECT hsi.post_install_script_output, hsi.install_script_output, hsi.host_id AS host_id, - h.computer_name AS host_display_name, st.name AS software_title, st.id AS software_title_id, COALESCE(%s, '') AS status, si.filename AS software_package, - h.team_id AS host_team_id, hsi.user_id AS user_id, hsi.post_install_script_exit_code, hsi.install_script_exit_code, - hsi.self_service + hsi.self_service, + hsi.host_deleted_at FROM host_software_installs hsi - JOIN hosts h ON h.id = hsi.host_id JOIN software_installers si ON si.id = hsi.software_installer_id JOIN software_titles st ON si.title_id = st.id WHERE @@ -400,6 +398,7 @@ WHERE FROM host_software_installs WHERE software_installer_id = :installer_id + AND host_deleted_at IS NULL GROUP BY host_id)) s`, softwareInstallerHostStatusNamedQuery("hsi", "status")) diff --git a/server/datastore/mysql/software_installers_test.go b/server/datastore/mysql/software_installers_test.go index be7fbbb69f..f2630770a7 100644 --- a/server/datastore/mysql/software_installers_test.go +++ b/server/datastore/mysql/software_installers_test.go @@ -328,7 +328,6 @@ func testGetSoftwareInstallResult(t *testing.T, ds *Datastore) { require.Equal(t, tc.expectedStatus, res.Status) require.Equal(t, swFilename, res.SoftwarePackage) require.Equal(t, host.ID, res.HostID) - require.Equal(t, host.DisplayName(), res.HostDisplayName) require.Equal(t, tc.preInstallQueryOutput, res.PreInstallQueryOutput) require.Equal(t, tc.postInstallScriptOutput, res.PostInstallScriptOutput) require.Equal(t, tc.installScriptOutput, res.Output) diff --git a/server/fleet/software_installer.go b/server/fleet/software_installer.go index 85cb4aa6a9..d542840989 100644 --- a/server/fleet/software_installer.go +++ b/server/fleet/software_installer.go @@ -155,8 +155,6 @@ type HostSoftwareInstallerResult struct { SoftwarePackage string `json:"software_package" db:"software_package"` // HostID is the ID of the host. HostID uint `json:"host_id" db:"host_id"` - // HostDisplayName is the display name of the host. - HostDisplayName string `json:"host_display_name" db:"host_display_name"` // Status is the status of the software installer package on the host. Status SoftwareInstallerStatus `json:"status" db:"status"` // Detail is the detail of the software installer package on the host. TODO: does this field @@ -172,9 +170,6 @@ type HostSoftwareInstallerResult struct { CreatedAt time.Time `json:"created_at" db:"created_at"` // UpdatedAt is the time the software installer request was last updated. UpdatedAt *time.Time `json:"updated_at" db:"updated_at"` - // HostTeamID is the team ID of the host on which this software install was attempted. This - // field is not sent in the response, it is only used for internal authorization. - HostTeamID *uint `json:"-" db:"host_team_id"` // UserID is the user ID that requested the software installation on that host. UserID *uint `json:"-" db:"user_id"` // InstallScriptExitCode is used internally to determine the output displayed to the user. @@ -184,6 +179,9 @@ type HostSoftwareInstallerResult struct { // SelfService indicates that the installation was queued by the // end user and not an administrator SelfService bool `json:"self_service" db:"self_service"` + // HostDeletedAt indicates if the data is associated with a + // deleted host + HostDeletedAt *time.Time `json:"-" db:"host_deleted_at"` } const ( diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index afbb7aa39f..32420f39d6 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -10619,6 +10619,22 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerHostRequests() { require.Contains(t, extractServerErrorText(r.Body), "Invalid parameters. The combination of software_version_id and software_title_id is not allowed.") r = s.Do("GET", "/api/latest/fleet/hosts", nil, http.StatusBadRequest, "software_status", "installed", "team_id", "1", "software_title_id", "1", "software_id", "1") require.Contains(t, extractServerErrorText(r.Body), "Invalid parameters. The combination of software_id and software_title_id is not allowed.") + + // Access software install result after host is deleted + err = s.ds.DeleteHost(context.Background(), h.ID) + require.NoError(t, err) + + instResult, err := s.ds.GetSoftwareInstallResults(context.Background(), installUUID) + require.NoError(t, err) + require.NotNil(t, instResult.HostDeletedAt) + + gsirr = getSoftwareInstallResultsResponse{} + s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/install/results/%s", installUUID), nil, http.StatusOK, &gsirr) + require.NoError(t, gsirr.Err) + require.NotNil(t, gsirr.Results) + results = gsirr.Results + require.Equal(t, installUUID, results.InstallUUID) + require.Equal(t, fleet.SoftwareInstallerPending, results.Status) } func (s *integrationEnterpriseTestSuite) TestSelfServiceSoftwareInstall() { From e2fcb44d76473a8d97dc5c316af12d399ed71fd9 Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Thu, 1 Aug 2024 15:53:43 -0400 Subject: [PATCH 36/88] Fleet UI: multiple unreleased and released bugs (#20951) --- frontend/components/Editor/Editor.tsx | 2 +- .../OSSettings/cards/CustomSettings/_styles.scss | 4 ++++ .../ProfileUploader/components/AddProfileModal/_styles.scss | 6 +++--- .../SoftwareTable/SoftwareTitlesTableConfig.tsx | 4 +++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/components/Editor/Editor.tsx b/frontend/components/Editor/Editor.tsx index c9bd360508..e8f230e379 100644 --- a/frontend/components/Editor/Editor.tsx +++ b/frontend/components/Editor/Editor.tsx @@ -75,7 +75,7 @@ const Editor = ({ {labelText} diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss index 81c563065c..14828cfb9d 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss @@ -99,6 +99,10 @@ flex-direction: column; align-items: center; gap: $pad-small; + + &--message { + text-align: center; + } } &__button-wrap { diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/_styles.scss index 222268e7db..087e2a54d1 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/_styles.scss @@ -57,10 +57,10 @@ flex-direction: column; align-items: center; gap: $pad-small; - } - &__profile-graphic--message { - text-align: center; + &--message { + text-align: center; + } } &__button-wrap { diff --git a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTitlesTableConfig.tsx b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTitlesTableConfig.tsx index 213cc1ec46..ea31ff42d4 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTitlesTableConfig.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTitlesTableConfig.tsx @@ -76,11 +76,13 @@ const getSoftwareNameCellData = ( iconUrl = app_store_app.icon_url; } + const isAllTeams = teamId === undefined; + return { name: softwareTitle.name, source: softwareTitle.source, path: softwareTitleDetailsPath, - hasPackage: hasPackage && !!teamId, + hasPackage: hasPackage && !isAllTeams, isSelfService, iconUrl, }; From a49c23e74bfa71930c7349043ef32258bc53d854 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 1 Aug 2024 15:24:21 -0500 Subject: [PATCH 37/88] Website: update open positions template page to include a salary range (#20968) Closes: https://github.com/fleetdm/confidential/issues/7200 Changes: - Updated the open positions template page to include a salary range. --- website/scripts/build-static-content.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/scripts/build-static-content.js b/website/scripts/build-static-content.js index 470da38f6c..03050e00f0 100644 --- a/website/scripts/build-static-content.js +++ b/website/scripts/build-static-content.js @@ -602,7 +602,7 @@ module.exports = { let pageTitle = openPosition.jobTitle; - let mdStringForThisOpenPosition = `# ${openPosition.jobTitle}\n\n## Let's start with why we exist. 📡\n\nEver wondered if your employer is monitoring your work computer?\n\nOrganizations make huge investments every year to keep their laptops and servers online, secure, compliant, and usable from anywhere. This is called "device management".\n\nAt Fleet, we think it's time device management became [transparent](https://fleetdm.com/transparency) and [open source](https://fleetdm.com/handbook/company#open-source).\n\n\n## About the company 🌈\n\nYou can read more about the company in our [handbook](https://fleetdm.com/handbook/company), which is public and open to the world.\n\ntldr; Fleet Device Management Inc. is a [recently-funded](https://techcrunch.com/2022/04/28/fleet-nabs-20m-to-enable-enterprises-to-manage-their-devices/) Series A startup founded and backed by the same people who created osquery, the leading open source security agent. Today, osquery is installed on millions of laptops and servers, and it is especially popular with [enterprise IT and security teams](https://www.linuxfoundation.org/press/press-release/the-linux-foundation-announces-intent-to-form-new-foundation-to-support-osquery-community).\n\n\n## Your primary responsibilities 🔭\n${openPosition.responsibilities}\n\n## Are you our new team member? 🧑‍🚀\nIf most of these qualities sound like you, we would love to chat and see if we're a good fit.\n\n${openPosition.experience}\n\n## Why should you join us? 🛸\n\nLearn more about the company and [why you should join us here](https://fleetdm.com/handbook/company#is-it-any-good).\n\n
    Deloitte logo

    “One of the best teams out there to go work for and help shape security platforms.”

    Dhruv Majumdar

    Director Of Cyber Risk & Advisory

    \n\n\n## Want to join the team?\n\nWant to join the team?\n\nReach out to [${openPosition.hiringManagerName} on Linkedin](${openPosition.hiringManagerLinkedInUrl}).`; + let mdStringForThisOpenPosition = `# ${openPosition.jobTitle}\n\n## Let's start with why we exist. 📡\n\nEver wondered if your employer is monitoring your work computer?\n\nOrganizations make huge investments every year to keep their laptops and servers online, secure, compliant, and usable from anywhere. This is called "device management".\n\nAt Fleet, we think it's time device management became [transparent](https://fleetdm.com/transparency) and [open source](https://fleetdm.com/handbook/company#open-source).\n\n\n## About the company 🌈\n\nYou can read more about the company in our [handbook](https://fleetdm.com/handbook/company), which is public and open to the world.\n\ntldr; Fleet Device Management Inc. is a [recently-funded](https://techcrunch.com/2022/04/28/fleet-nabs-20m-to-enable-enterprises-to-manage-their-devices/) Series A startup founded and backed by the same people who created osquery, the leading open source security agent. Today, osquery is installed on millions of laptops and servers, and it is especially popular with [enterprise IT and security teams](https://www.linuxfoundation.org/press/press-release/the-linux-foundation-announces-intent-to-form-new-foundation-to-support-osquery-community).\n\n\n## Your primary responsibilities 🔭\n${openPosition.responsibilities}\n\n## Are you our new team member? 🧑‍🚀\nIf most of these qualities sound like you, we would love to chat and see if we're a good fit.\n\n${openPosition.experience}\n\n## Why should you join us? 🛸\n\nLearn more about the company and [why you should join us here](https://fleetdm.com/handbook/company#is-it-any-good).\n\n
    Deloitte logo

    “One of the best teams out there to go work for and help shape security platforms.”

    Dhruv Majumdar

    Director Of Cyber Risk & Advisory

    \n\n\n## Want to join the team?\n\nWant to join the team?\n\nReach out to [${openPosition.hiringManagerName} on Linkedin](${openPosition.hiringManagerLinkedInUrl}). \n\n\n >The salary range for this role is $48,000 - $480,000. Fleet provides competitive compensation based on our [compensation philosophy](https://fleetdm.com/handbook/company/communications#compensation), as well as comprehensive [benefits](https://fleetdm.com/handbook/company/communications#benefits).`; let htmlStringForThisPosition = await sails.helpers.strings.toHtml.with({mdString: mdStringForThisOpenPosition}); From 45b61c508545e35dca1ec6eff6197b50492cb045 Mon Sep 17 00:00:00 2001 From: Luke Heath Date: Thu, 1 Aug 2024 13:47:17 -0700 Subject: [PATCH 38/88] Change freeze process to release candidate process (#20857) --- handbook/engineering/README.md | 127 +++++++++++++++---- handbook/engineering/engineering.rituals.yml | 6 +- 2 files changed, 107 insertions(+), 26 deletions(-) diff --git a/handbook/engineering/README.md b/handbook/engineering/README.md index 7e1d08e84b..d6f18bde2c 100644 --- a/handbook/engineering/README.md +++ b/handbook/engineering/README.md @@ -1,7 +1,10 @@ # Engineering + This handbook page details processes specific to working [with](#contact-us) and [within](#responsibilities) this department. + ## Team + | Role                            | Contributor(s) | |:--------------------------------|:-----------------------------------------------------------------------------------------------------------| | Chief Technology Officer (CTO) | [Luke Heath](https://www.linkedin.com/in/lukeheath/) _([@lukeheath](https://github.com/lukeheath))_ @@ -10,15 +13,21 @@ This handbook page details processes specific to working [with](#contact-us) and | Quality Assurance Engineer (QA) | _See [🛩️ Product groups](https://fleetdm.com/handbook/company/product-groups#current-product-groups)_ | Software Engineer | _See [🛩️ Product groups](https://fleetdm.com/handbook/company/product-groups#current-product-groups)_ + ## Contact us + - To **make a request** of this department, [create an issue](https://fleetdm.com/handbook/company/product-groups#current-product-groups) and a team member will get back to you within one business day (If urgent, mention a [team member](#team) in the [#help-engineering](https://fleetdm.slack.com/archives/C019WG4GH0A) Slack channel. - Any Fleet team member can [view the kanban boards](https://fleetdm.com/handbook/company/product-groups#current-product-groups) for this department, including pending tasks and the status of new requests. - Please **use issue comments and GitHub mentions** to communicate follow-ups or answer questions related to your request. + ## Responsibilities + The 🚀 Engineering department at Fleet is directly responsible for writing and maintaining the [code](https://github.com/fleetdm/fleet) for Fleet's core product and infrastructure. + ### Record engineering KPIs + We track the success of this process by observing the throughput of issues through the system and identifying where buildups (and therefore bottlenecks) are occurring. The metrics are: * Number of bugs opened this week @@ -28,6 +37,7 @@ The metrics are: Each week these are tracked and shared in the weekly KPI sheet by Luke Heath. + ### Write a feature guide We write [guides](https://fleetdm.com/guides) for all new features. Feature guides are published before the feature is released so that our users understand how the feature is intended to work. A guide is a type of article, so the process for writing a guide and article is the same. @@ -39,6 +49,7 @@ We write [guides](https://fleetdm.com/guides) for all new features. Feature guid ### 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. @@ -53,46 +64,50 @@ If there are no product changes, and the DRI decides to prioritize the story, th > We prefer the term engineering-initiated stories over technical debt because the user story format helps keep us focused on our users and contributors. + ### Fix a bug + All bug fix pull requests should have a mention back to the issue they resolve with # in the description or even in a comment. Please do not use any [automated words](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) since we don't want the tickets auto-closing when PR's are merged. If the bug is labeled `~unreleased bug`, branch off and put your PR into `main`. These issues can be closed as soon as they complete QA. If the bug is labeled `~released bug`, branch off and put your PR into `main`. After merging checkout the latest tag, for example `git checkout fleet-v4.48.2`, then `git fetch; git cherry-pick `. If the cherry-pick fails with a conflict call out in the ticket how to resolve or if it is sufficiently complicated call out this fix is not suited for the patch release process and should only be included in the end of sprint release. This approach makes sure the bug fix is not built on top of unreleased feature code, which can cause merge conflicts during patch releases. -### Begin a merge freeze -To ensure release quality, Fleet has a freeze period for testing beginning the Tuesday before the release at 11:00 AM Pacific. Effective at the start of the freeze period, a release candidate branch is created and frozen at `minor-fleet-v4.x.x` and no additional feature work is merged without approval. -Bugs are exempt from the release freeze period. +### Create a release candidate -Before beginning the freeze, create the release candidate branch. [Run the first step](https://github.com/fleetdm/fleet/tree/main/tools/release#minor-release-typically-end-of-sprint) of the minor release section of the Fleet releases script to create the release candidate branch, the release QA issue, and announce the release candidate in Slack. +All minor releases go through the release candidate process before they are published. A release candidate for the next minor release is created on the Tuesday before the release at 11:00 AM Pacific. A release candidate branch is created at `minor-fleet-v4.x.x` and no additional feature work is merged without EM and QA approval. -After creating the release candidate branch, open the [repo settings on Merge Freeze](https://app.mergefreeze.com/installations/3704/branches/6847/edit) and populate the "Protected branch name" field with the name of the release candidate branch. Then, [open the repo on Merge Freeze](https://www.mergefreeze.com/installations/3704/branches/6847) and click the "Freeze now" button. This will freeze the selected release candidate branch and require any PRs to be manually unfrozen before merging. PRs may be manually unfrozen in Merge Freeze using the PR number. +All bug fixes that are merged into `main` after the release candidate is created are merged into the release candidate by the engineer responsible for the fix. -> Any Fleetie can [unfreeze PRs on Merge Freeze](https://www.mergefreeze.com/installations/3704/branches) if the PR contains documentation changes or bug fixes only. If the PR contains other changes, please confirm with your manager before unfreezing. +[Run the first step](https://github.com/fleetdm/fleet/tree/main/tools/release#minor-release-typically-end-of-sprint) of the minor release section of the Fleet releases script to create the release candidate branch, the release QA issue, and announce the release candidate in Slack. -### Deploy the release candidate to QA Wolf during merge freeze -During merge freeze, deploy the release candidate to our QA Wolf instance every morning instead of `main` to ensure that any new bugs reported by QA Wolf are in the upcoming release and need to be fixed before publishing the release. + +### Deploy the release candidate to QA Wolf + +During the release candidate period, the release candidate is deployed to our QA Wolf instance every morning instead of `main` to ensure that any new bugs reported by QA Wolf are in the upcoming release and need to be fixed before publishing the release. Open the [confidential repo environment variables](https://github.com/fleetdm/confidential/settings/variables/actions) page and update the `QAWOLF_DEPLOY_TAG` repository variable with the name of the release candidate branch. -### Merge a pull request during the freeze period -We merge bug fixes, documentation changes, and website updates during the freeze period, but we do not merge other code changes. This minimizes code churn and helps ensure a stable release. To merge a bug fix, you must first unfreeze the PR in [Merge Freeze](https://app.mergefreeze.com/installations/3704/branches), and click the "Unfreeze 1 pull request" text link. + +### Merge bug fixes into the release candidate + +Only merge bug fixes during the release candidate period to minimize code churn and help ensure a stable release. To merge a bug fix into the release candidate, it should first be merged into `main`. Then, `git checkout` the release candidate branch and create a new local branch. Next, `git cherry-pick` your commit from `main` into your new local branch, then create a pull request from your new branch to the release candidate. This process ensures your bug fix is included in `main` for future releases, as well as the release candidate branch for the pending release. > To allow a stable release test, the final 24 hours before release is a deep freeze when only bugs with the `~release-blocker` or `~unreleased-bug` labels are merged. -If there is partially merged feature work when freeze begins, the previously merged code must be reverted. If there is an exceptional, business-critical need to merge feature work during freeze, as determined by the [release ritual DRI](#rituals), the following exception process may be followed: +If there is partially merged feature work when the release candidate is created, the previously merged code must be reverted. If there is an exceptional, business-critical need to merge feature work into the release candidate, as determined by the [release ritual DRI](#rituals), the release candidate [feature merge exception process](https://fleetdm.com/handbook/engineering#request-release-candidate-feature-merge-exception) may be followed. -1. The engineer requesting the feature work merge exception during freeze notifies their Engineering Manager. -2. The Engineering Manager notifies the QA lead for the product group and the [release ritual DRI](https://fleetdm.com/handbook/engineering#rituals). -3. The Engineering Manager, QA lead, and [release ritual DRI](#rituals) must all approve the feature work PR before it is unfrozen and merged. +### Request release candidate feature merge exception -> This exception process should be avoided whenever possible. Any feature work merged during freeze will likely result in a significant release delay. +1. Notify product group EM that feature work will not merge into `main` before the release candidate is cut and requires a feature merge exception. +2. EM notifies QA lead for the product group and the [release ritual DRI](https://fleetdm.com/handbook/engineering#rituals). +3. EM, QA lead, and [release ritual DRI](#rituals) must all approve the feature work PR before it is merged into the release candidate branch. + +> This exception process should be avoided whenever possible. Any feature work merged into the release candidate will likely result in a significant release delay. -### Merge a bug fix during the freeze period -To merge a bug fix into the release candidate during freeze, it should first be merged into `main`. Then, `git checkout` the release candidate branch and create a new branch. Next, `git cherry-pick` your -commit from `main` into your new branch, then create a pull request from your new branch to the release candidate. This process ensures your bug fix is included in `main` for future releases, as well as the release candidate branch for the next release. ### Confirm latest versions of dependencies + Before kicking off release QA, confirm that we are using the latest versions of dependencies we want to keep up-to-date with each release. Currently, those dependencies are: 1. **Go**: Latest minor release @@ -133,13 +148,19 @@ If an announcement is found for either data source that may impact data feed ava If code changes are found for any `fleetd` components, create a new release QA issue to update `fleetd`. Delete the top section for Fleet core, and retain the bottom section for `fleetd`. Populate the necessary version changes for each `fleetd` component. + ### Indicate your product group is release-ready -Once a product group completes its QA process during the freeze period, its QA lead moves the smoke testing ticket to the "Ready for release" column on their ZenHub board. They then notify the release ritual DRI by tagging them in a comment, indicating that their group is prepared for release. The release ritual DRI starts the [release process](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Releasing-Fleet.md) after all QA leads have made these updates and confirmed their readiness for release. + +Once a product group completes its QA process during the release candidate period, its QA lead moves the smoke testing ticket to the "Ready for release" column on their ZenHub board. They then notify the release ritual DRI by tagging them in a comment, indicating that their group is prepared for release. The release ritual DRI starts the [release process](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Releasing-Fleet.md) after all QA leads have made these updates and confirmed their readiness for release. + ### Prepare Fleet release + Documentation on completing the release process can be found [here](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Releasing-Fleet.md). + ### Deploy a new release to dogfood + After each Fleet release, the new release is deployed to Fleet's "dogfood" (internal) instance. How to deploy a new release to dogfood: @@ -154,7 +175,9 @@ How to deploy a new release to dogfood: > > Note that "fleetdm/fleet:main" is not a image name, instead use the commit hash in place of "main". + ### Conclude current milestone + Immediately after publishing a new release, we close out the associated GitHub issues and milestones. 1. **Rename current milestone**: In GitHub, [change the current milestone name](https://github.com/fleetdm/fleet/milestones) from `4.x.x-tentative` to `4.x.x`. `4.37.0-tentative` becomes `4.37.0`. @@ -175,16 +198,18 @@ Immediately after publishing a new release, we close out the associated GitHub i 10. **Create next milestone**: Create a new milestone for the next versioned release, `4.x.x-tentative`. -11. **Remove the freeze**: [Open the repo in Merge Freeze](https://app.mergefreeze.com/installations/3704/branches/6847) and click the "Unfreeze" button. +11. Announce that the release milestone has been closed in #help-engineering. -12. Announce that `main` is unfrozen and the milestone has been closed in #help-engineering. +12. Visit the [confidential repo variables](https://github.com/fleetdm/confidential/settings/variables/actions) page and update the `QAWOLF_DEPLOY_TAG` repository variable to `main` so that the latest code is deployed to QA Wolf every morning. -13. Visit the [confidential repo variables](https://github.com/fleetdm/confidential/settings/variables/actions) page and update the `QAWOLF_DEPLOY_TAG` repository variable to `main` so that the latest code is deployed to QA Wolf every morning. ### Update the Fleet releases calendar + The [Fleet releases Google calendar](https://calendar.google.com/calendar/embed?src=c_v7943deqn1uns488a65v2d94bs%40group.calendar.google.com&ctz=America%2FChicago) is kept up-to-date by the [release ritual DRI](https://fleetdm.com/handbook/engineering#rituals). Any change to targeted release dates is reflected on this calendar. + ### Secure company-issued equipment for a team member + As soon as an offer is accepted, Fleet provides laptops and YubiKey security keys for core team members to use while working at Fleet. The IT engineer will work with the new team member to get their equipment requested and shipped to them on time. - [**Check the Fleet IT warehouse**](https://docs.google.com/spreadsheets/d/1hFlymLlRWIaWeVh14IRz03yE-ytBLfUaqVz0VVmmoGI/edit#gid=0) before purchasing any equipment including laptops, monitors, and Yubikeys to ensure we efficiently [utilize existing assets before spending money](https://fleetdm.com/handbook/company/why-this-way#why-spend-less). If Fleet IT warehouse inventory can meet the needs of the request, file a [warehouse request](https://github.com/fleetdm/confidential/issues/new?assignees=sampfluger88&labels=%23g-digital-experience&projects=&template=warehouse-request.md&title=%F0%9F%92%BB+Warehouse+request). @@ -202,17 +227,23 @@ As soon as an offer is accepted, Fleet provides laptops and YubiKey security key - Include delivery tracking information when closing the support request so the new employee can be notified. + ### Register a domain for Fleet + Domain name registrations are handled through Namecheap. Access is managed via 1Password. + ### Fix a laptop that's not checking in + It is [possible for end users to remove launch agents](https://github.com/fleetdm/confidential/issues/6088) (this is true not just for osquery, but for anything). If the host has MDM turned on, use the `fleetctl mdm run-command` CLI command to push the XML file located at https://github.com/fleetdm/fleet/blob/main/it-and-security/lib/macos-send-fleetd.xml to the device, which will reinstall fleetd. If the host doesn't have MDM turned on or isn't enrolled to dogfood, it is beyond our ability to control remotely. + ### Enroll a macOS host in dogfood + When a device is purchased using the Apple eCommerce store, the device is automatically enrolled in Apple Business Manager (ABM) and assigned to the correct server to ensure the device is in dogfood. You can confirm that the device has been ordered correctly by following these steps: - Log into ABM @@ -229,14 +260,20 @@ On occasion there will be a need to manually enroll a macOS host in dogfood. Thi - Once complete, follow instructions to reset disk encryption key. - Disk encryption key will now be stored in Fleet dogfood, which signifies that the device is now enrolled in dogfood. + ### Enroll a Windows or Ubuntu Linux device in dogfood + To enroll a windows or Ubuntu Linux device in dogfood, instruct the user to install fleetd for their platform from internal shared drive folder [here](https://drive.google.com/drive/folders/1-hMwk4P7NRzCU5kDxkEcOo8Sluuaux1h?usp=drive_link). Once the user has installed fleetd, verify the device is correctly enrolled by confirming the device encryption key is in dogfood. + ### Enroll a ChromeOS device in dogfood + ChromeOS devices are automatically enrolled in dogfood after the IT admin sets up automatic enrollment. This is done in dogfood by following the steps found in the dialog popup when selecting "Add hosts > ChromeOS" from the dogfood Hosts page. + ### Lock a macOS host in dogfood using fleetctl CLI tool + - Download the lock command XML file from Google Drive [here](https://drive.google.com/file/d/1o6vJ1fHilRtBmyKAj0I5URiKn77qe4gS/view?usp=drive_link). - Customize any messaging that will appear on the locked device, and modify the pin for unlocking the device by editing the file in text editor. - Note you will need to safely store the recovery pin for the device, suggest using 1Password or other secure storage method @@ -252,7 +289,9 @@ ChromeOS devices are automatically enrolled in dogfood after the IT admin sets u - Enter disk encryption key on laptop. This should prompt you to create a new password. - You will then be logged into the default device profile, and can complete any needed actions (wipe, recover data). + ### Book an event + Fleet's Client Platform Engineer & Community Advocate is responsible for booking events that Fleet has chosen to attend and/or sponsor. To book an event, complete the steps in each event issue. Contact the [🫧 Digital Marketing Manager](https://fleetdm.com/handbook/demand#team) as needed with any questions or blockers to booking an event. > Note: The Demand department [settles all event strategy](https://fleetdm.com/handbook/demand#settle-event-strategy) prior to booking an event. @@ -269,6 +308,7 @@ Article creation begins with creation of an issue using the "Article request" te Check the "📃 Planned articles" column in [#g-demand board](https://app.zenhub.com/workspaces/g-demand-64e6c8e2d35c7f001a457b7f/board) and continue to work through steps in each event's issue. --> + ### Order SWAG **To order T-shirts:** @@ -300,14 +340,18 @@ Check the "📃 Planned articles" column in [#g-demand board](https://app.zenhub - [Sharpie Fine Point Markers](https://www.everythingbranded.com/product/sharpie-fine-point-332908) - [Custom sticky note pads](https://www.everythingbranded.com/product/custom-sticky-notes-585601) (design is in the StickerMule [brand kit](https://www.stickermule.com/studio/brand-kits)) + ### Review another product group's pull request + Some code paths require pull request review from multiple product groups to confirm there are no unintended side effects of the change for another product group. All code paths defined in [CODEOWNERS](https://github.com/fleetdm/fleet/blob/main/CODEOWNERS) that are assigned to individual engineers across multiple product groups must be approved by one engineer from each product group before merging. + ### Review a community pull request + If you're assigned a community pull request for review, it is important to keep things moving for the contributor. The goal is to not go more than one business day without following up with the contributor. A PR should be merged if: @@ -334,7 +378,9 @@ For PRs that will not be merged: - Thank the contributor for their effort and explain why the changes won't be merged. - Close the PR. + ### Merge a community pull request + When merging a pull request from a community contributor: - Ensure that the checklist for the submitter is complete. @@ -343,10 +389,14 @@ 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. + ### Close a stale community issue + If a community member opens an issue that we can't reproduce leave a comment asking the author for more context. After one week with no reply, close the issue with a comment letting them know they are welcome to re-open it with any updates. + ### 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. We aspire to clear sprint work for the on-call engineer, but due to capacity or other constraints, sometimes the on-call engineer is required for sprint work. When this is the case, the EM will work with the on-call engineer to take over support requests or @oncall assignment completely when necessary. @@ -361,7 +411,9 @@ Some ideas: - Create a blog post (or other content) for fleetdm.com. - Try out an experimental refactor. + ### Edit a DNS record + We use Cloudflare to manage the DNS records of fleetdm.com and our other domains. To make DNS changes in Cloudflare: 1. Log into your Cloudflare account and select the "Fleet" account. 2. Select the domain you want to change and go to the DNS panel on that domain's dashboard. @@ -369,22 +421,28 @@ We use Cloudflare to manage the DNS records of fleetdm.com and our other domains > If you need access to Fleet's Cloudflare account, please ask the [DRI](https://fleetdm.com/handbook/company/why-this-way#why-direct-responsibility) [Luke Heath](https://fleetdm.com/handbook/engineering#team) in Slack for an invitation. + ### Assume developer on-call alias + The on-call developer is responsible for: - Knowing [the on-call rotation](https://fleetdm.com/handbook/company/product-groups#the-developer-on-call-rotation). - Preforming the [on-call responsibilities](https://fleetdm.com/handbook/company/product-groups#developer-on-call-responsibilities). - [Escalating community questions and issues](https://fleetdm.com/handbook/company/product-groups#escalations). - Successfully [transferring the on-call persona to the next developer](https://fleetdm.com/handbook/company/product-groups#changing-of-the-guard). + ### Notify stakeholders when a user story is pushed to the next release -[User stories](https://fleetdm.com/handbook/company/product-groups#scrum-items) are intended to be completed in a single sprint. When a user story selected for a release has not merged into `main` by the time the [merge freeze](https://fleetdm.com/handbook/engineering#begin-a-merge-freeze) begins, it is the product group EM's responsibility to notify stakeholders: + +[User stories](https://fleetdm.com/handbook/company/product-groups#scrum-items) are intended to be completed in a single sprint. When a user story selected for a release has not merged into `main` by the time the release candidate is created, it is the product group EM's responsibility to notify stakeholders: 1. Add the `~pushed` label to the user story. 2. Update the user story's milestone to the next minor version milestone. 3. Comment on the GitHub issue and at-mention the PM and anyone listed in the requester field. 4. If `customer-` labels are applied to the user story, at-mention the [VP of Customer Success](https://fleetdm.com/handbook/customer-success#team). + ### Run Fleet locally for QA purposes + To try Fleet locally for QA purposes, run `fleetctl preview`, which defaults to running the latest stable release. To target a different version of Fleet, use the `--tag` flag to target any tag in [Docker Hub](https://hub.docker.com/r/fleetdm/fleet/tags?page=1&ordering=last_updated), including any git commit hash or branch name. For example, to QA the latest code on the `main` branch of fleetdm/fleet, you can run: `fleetctl preview --tag=main`. @@ -395,7 +453,9 @@ For each bug found, please use the [bug report template](https://github.com/flee For unreleased bugs in an active sprint, a new bug is created with the `~unreleased bug` label. The `:release` label and associated product group label is added, and the engineer responsible for the feature is assigned. If QA is unsure who the bug should be assigned to, it is assigned to the EM. Fixing the bug becomes part of the story. + ### Accept new Apple developer account terms + Engineering is responsible for managing third-party accounts required to support engineering infrastructure. We use the official Fleet Apple developer account to notarize installers we generate for Apple devices. Whenever Apple releases new terms of service, we are unable to notarize new packages until the new terms are accepted. When this occurs, we will begin receiving the following error message when attempting to notarize packages: "You must first sign the relevant contracts online." To resolve this error, follow the steps below. @@ -410,6 +470,7 @@ When this occurs, we will begin receiving the following error message when attem 5. Accept the new terms of service. + ### Interview a developer candidate Ensure the interview process follows these steps in order. This process must follow [creating a new position](https://fleetdm.com/handbook/company/leadership#creating-a-new-position) through [receiving job applications](https://fleetdm.com/handbook/company/leadership#receiving-job-applications). Once the position is approved manage this process per candidate in a [hiring pipeline](https://drive.google.com/drive/folders/1dLZaor9dQmAxcxyU6prm-MWNd-C-U8_1?usp=drive_link) @@ -424,7 +485,9 @@ Ensure the interview process follows these steps in order. This process must fol If the candidate passes all of these steps then continue with [hiring a new team member](https://fleetdm.com/handbook/company/leadership#hiring-a-new-team-member). + ### Renew MDM certificate signing request (CSR) + The certificate signing request (CSR) certificate expires every year. It needs to be renewed prior to expiring. This is notified to the team by the MDM calendar event [IMPORTANT: Renew MDM CSR certificate](https://calendar.google.com/calendar/u/0/r/eventedit/MmdqNTY4dG9nbWZycnNxbDBzYjQ5dGplM2FfMjAyNDA5MDlUMTczMDAwWiBjXzMyMjM3NjgyZGRlOThlMzI4MjVhNTY1ZDEyZjk0MDEyNmNjMWI0ZDljYjZjNjgyYzQ2MjcxZGY0N2UzNjM5NDZAZw) Steps to renew the certificate: @@ -444,7 +507,9 @@ Steps to renew the certificate: 10. Verify by logging into a normal apple account (not billing@...) and Generate a new Push Certificate following our [setup MDM](https://fleetdm.com/docs/using-fleet/mdm-setup) steps and verify the Expiration date is 1 year from today. 11. Adjust calendar event to be between 2-4 weeks before the next expiration. + ### Perform an incident postmortem + Conduct a postmortem meetings for every service or feature outage and every critical bug, whether it's a customer's environment or on fleetdm.com. 1. Copy this [postmortem template](https://docs.google.com/document/d/1Ajp2LfIclWfr4Bm77lnUggkYNQyfjePiWSnBv1b1nwM/edit?usp=sharing) document and pre-populate where possible. @@ -454,7 +519,9 @@ Conduct a postmortem meetings for every service or feature outage and every crit [Example Finished Document](https://docs.google.com/document/d/1YnETKhH9R7STAY-PaFnPy2qxhNht2EAFfkv-kyEwebQ/edit?usp=share_link) + ### Process incoming equipment + Upon receiving any device, follow these steps to process incoming equipment. 1. Search for the SN of the physical device in the ["Company equipment" spreadsheet](https://docs.google.com/spreadsheets/d/1hFlymLlRWIaWeVh14IRz03yE-ytBLfUaqVz0VVmmoGI/edit#gid=0) to confirm the correct equipment was received. 3. Visibly inspect equipment and all related components (e.g. laptop charger) for damage. @@ -466,7 +533,9 @@ Upon receiving any device, follow these steps to process incoming equipment. 9. Follow the prompts to activate the device and reinstall the appropriate version of macOS. > If you are prevented from completing the steps above, 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, for the device to be scheduled for troubleshooting and remediation. Please note in the issue where you encountered blockers to completing the steps. + ### Ship approved equipment + Once the Business Operations 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). @@ -476,9 +545,12 @@ Once the Business Operations department approves inventory to be shipped from Fl 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. + ## Rituals + + #### Stubs The following stubs are included only to make links backward compatible. @@ -546,6 +618,15 @@ Please see [handbook/engineering#accept-new-apple-developer-account-terms](https ##### Merging during the freeze period Please see [handbook/engineering#merge-a-pull-request-during-the-freeze-period](https://fleetdm.com/handbook/engineering#merge-a-pull-request-during-the-freeze-period) +##### Merge a bug fix during the freeze period +Please see [merge-bug-fixes-into-the-release-candidate](https://fleetdm.com/handbook/engineering#merge-bug-fixes-into-the-release-candidate) + +##### Merge a pull request during the freeze period +Please see [merge-bug-fixes-into-the-release-candidate](https://fleetdm.com/handbook/engineering#merge-bug-fixes-into-the-release-candidate) + +##### Begin a merge freeze +Please see [handbook/engineering#create-a-release-candidate](https://fleetdm.com/handbook/engineering#create-a-release-candidate) + ##### Scrum boards Please see [handbook//product-groups#current-product-groups](https://fleetdm.com/handbook/engineering#contact-us) diff --git a/handbook/engineering/engineering.rituals.yml b/handbook/engineering/engineering.rituals.yml index 4ff04b98b9..62432b78c3 100644 --- a/handbook/engineering/engineering.rituals.yml +++ b/handbook/engineering/engineering.rituals.yml @@ -43,11 +43,11 @@ moreInfoUrl: "https://github.com/fleetdm/fleet/security" dri: "lukeheath" - - task: "Freeze ritual" + task: "Release candidate ritual" startedOn: "2023-08-09" frequency: "Triweekly" - description: "Go through the process of freezing the `main` branch to prepare for the next release." - moreInfoUrl: "https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Releasing-Fleet.md#patch-releases" + description: "Go through the process of create a release candidate." + moreInfoUrl: "https://github.com/fleetdm/fleet/blob/main/tools/release/README.md#minor-release-typically-end-of-sprint" dri: "lukeheath" - task: "Release ritual" From 531b25d2accbfea754bb87f05d029ed1647f59fe Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Thu, 1 Aug 2024 18:15:41 -0300 Subject: [PATCH 39/88] if a PKG is added as a target, always install it (#20971) previously we were only installing on updates fixes a bug found by @PezHub # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [ ] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)). --- orbit/pkg/update/update.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/orbit/pkg/update/update.go b/orbit/pkg/update/update.go index f1803ec787..56e4a79b7f 100644 --- a/orbit/pkg/update/update.go +++ b/orbit/pkg/update/update.go @@ -385,9 +385,8 @@ func (u *Updater) get(target string) (*LocalTarget, error) { } } if strings.HasSuffix(localTarget.Path, ".pkg") && runtime.GOOS == "darwin" { - cmd := exec.Command("installer", "-pkg", localTarget.Path, "-target", "/") - if out, err := cmd.CombinedOutput(); err != nil { - return nil, fmt.Errorf("running pkgutil to install %s: %s: %w", localTarget.Path, string(out), err) + if err := installPKG(localTarget.Path); err != nil { + return nil, fmt.Errorf("updating pkg: %w", err) } } } else { @@ -398,6 +397,11 @@ func (u *Updater) get(target string) (*LocalTarget, error) { if err := u.download(target, repoPath, localTarget.Path, localTarget.Info.CustomCheckExec); err != nil { return nil, fmt.Errorf("download %q: %w", repoPath, err) } + if strings.HasSuffix(localTarget.Path, ".pkg") && runtime.GOOS == "darwin" { + if err := installPKG(localTarget.Path); err != nil { + return nil, fmt.Errorf("installing pkg for the first time: %w", err) + } + } default: return nil, fmt.Errorf("stat %q: %w", localTarget.Path, err) } @@ -647,6 +651,14 @@ func extractTarGz(path string) error { } } +func installPKG(path string) error { + cmd := exec.Command("installer", "-pkg", path, "-target", "/") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("running pkgutil to install %s: %s: %w", path, string(out), err) + } + return nil +} + func (u *Updater) initializeDirectories() error { for _, dir := range []string{ filepath.Join(u.opt.RootDirectory, binDir), From 9e484b46f4f46cbf4feabf1878cf7833d86f6cd5 Mon Sep 17 00:00:00 2001 From: allenhouchins <32207388+allenhouchins@users.noreply.github.com> Date: Thu, 1 Aug 2024 16:56:42 -0500 Subject: [PATCH 40/88] fixed typo in Apple Business Manager (#20915) --- terraform/addons/mdm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/addons/mdm/README.md b/terraform/addons/mdm/README.md index 0cb04aac59..4acccf3d9b 100644 --- a/terraform/addons/mdm/README.md +++ b/terraform/addons/mdm/README.md @@ -1,7 +1,7 @@ # MDM addon Notice: Previous versions of this module referred to `dep`, but to reduce confusion that has been replaces with `abm` -to mach the change to the newer Apple Busines Manager. For each key/value pair below, the key names have been changed +to mach the change to the newer Apple Business Manager. For each key/value pair below, the key names have been changed from previous version to match the name of the env var for easier usability. Older unused env vars were also removed for simplification. This includes removing the need for `extra_environment_variables` completely. From 73c7aa07b9e6533716d962546c48d1496bb945ee Mon Sep 17 00:00:00 2001 From: Noah Talerman <47070608+noahtalerman@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:25:58 -0400 Subject: [PATCH 41/88] =?UTF-8?q?Luke=20is=20DRI=20for=20=F0=9F=A6=A2?= =?UTF-8?q?=F0=9F=8D=8E=20Apple=20MDM=20maturity=20review=20(#20960)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handbook/product-design/product-design.rituals.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handbook/product-design/product-design.rituals.yml b/handbook/product-design/product-design.rituals.yml index c72a9a6207..3ab9203579 100644 --- a/handbook/product-design/product-design.rituals.yml +++ b/handbook/product-design/product-design.rituals.yml @@ -73,4 +73,4 @@ frequency: "Weekly" description: "Review stories in the “In review“ column on the drafting board with the “~apple-mdm-maturity“ label. Would this be usable for an IT admin and how does it compare to Jamf?" moreInfoUrl: - dri: "noahtalerman" + dri: "lukeheath" From 0a5ab1eb31e9f3ee3232d9af0d74b6aabe12d6ef Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:37:27 +0900 Subject: [PATCH 42/88] Footer text style fix (#20976) Footer text style fix --- website/assets/styles/pages/homepage.less | 15 ++++++++++----- website/views/pages/homepage.ejs | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/website/assets/styles/pages/homepage.less b/website/assets/styles/pages/homepage.less index b9f9f5b262..489671a645 100644 --- a/website/assets/styles/pages/homepage.less +++ b/website/assets/styles/pages/homepage.less @@ -643,6 +643,16 @@ } } + [purpose='bottom-cta'] { + h1 { + font-size: 48px; + max-width: 640px; + &.vm { + max-width: unset; + } + } + } + [purpose='video-modal'] { [purpose='modal-dialog'] { width: 100%; @@ -711,11 +721,6 @@ [purpose='integrations-section'] { margin-top: 160px; } - [purpose='bottom-cta'] { - h1 { - font-size: 48px; - } - } [purpose='video-modal'] { [purpose='modal-dialog'] { width: 100%; diff --git a/website/views/pages/homepage.ejs b/website/views/pages/homepage.ejs index 99d70bfbaa..365b33a3ab 100644 --- a/website/views/pages/homepage.ejs +++ b/website/views/pages/homepage.ejs @@ -373,7 +373,7 @@

    For teams with lots of computing devices

    -

    <%- partial('../partials/primary-tagline.partial.ejs') %>

    +

    <%- partial('../partials/primary-tagline.partial.ejs') %>

    Start now Talk to us From 841518f729fc9ec24347d369855e3748a1660e87 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Fri, 2 Aug 2024 03:05:10 -0500 Subject: [PATCH 43/88] Update vulnerability-management.ejs (#20988) --- .../views/pages/vulnerability-management.ejs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/website/views/pages/vulnerability-management.ejs b/website/views/pages/vulnerability-management.ejs index bf571b88ac..adca60393d 100644 --- a/website/views/pages/vulnerability-management.ejs +++ b/website/views/pages/vulnerability-management.ejs @@ -3,8 +3,8 @@
    -

    Vulnerability management

    -

    Build the vulnerability program you actually want

    +

    Open-source vulnerability reporting

    +

    Check vulnerabilities anywhere

    @@ -12,14 +12,14 @@
    Report what matters -

    Let's face it, most built-in graphs leave you wanting more. Report MTTR and any other custom metrics exactly the way you want to using fresh data from real computers.

    +

    Report exactly when CVEs got fixed or mitigated, down to the hour

    Deep context from the environment

    Fleet gives you data down to the chip level on every endpoint to help you make sense of which vulnerabilities to prioritize.

    Untangle your security stack

    Use open data and APIs to connect your vulnerability solution with osquery, the agent you might already have deployed.

    - Start now - Talk to us + Try localhost + Ask us anything
    @@ -140,11 +140,11 @@
    -

    Open-source vulnerability management

    -

    Build the vulnerability program you actually want

    +

    Open-source vulnerability reporting

    +

    Check vulnerabilities anywhere

    - Start now - Talk to us + Try localhost + Get help
    From b1bb4d9dd513c845e168f5a73a2b39e7f6cdd4fe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 06:50:22 -0300 Subject: [PATCH 44/88] Update versions of fleetd components in Fleet's TUF [automated] (#20983) Automated change from [GitHub action](https://github.com/fleetdm/fleet/actions/workflows/fleetd-tuf.yml). Co-authored-by: lucasmrod --- orbit/TUF.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orbit/TUF.md b/orbit/TUF.md index 1671d78545..53be1e46e8 100644 --- a/orbit/TUF.md +++ b/orbit/TUF.md @@ -19,6 +19,6 @@ Following are the currently deployed versions of fleetd components on the `stabl |--------------|--------|--------|---------|---------------| | orbit | 1.29.0 | 1.29.0 | 1.29.0 | 1.29.0 | | desktop | 1.29.0 | 1.29.0 | 1.29.0 | 1.29.0 | -| osqueryd | 5.12.2 | 5.12.2 | 5.12.2 | 5.12.1 | +| osqueryd | 5.13.0 | 5.13.0 | 5.13.0 | 5.13.0 | | nudge | - | - | - | - | | swiftDialog | - | - | - | - | From e3c3c870c9636c09ed561c7ecec07082250990d8 Mon Sep 17 00:00:00 2001 From: Tim Lee Date: Fri, 2 Aug 2024 04:33:57 -0600 Subject: [PATCH 45/88] Ignore Rejected CVEs Test (#19974) #18913 This is a test to ensure Rejected CVEs do not match against software. The related PR needs to be merged first, otherwise this test will fail: https://github.com/fleetdm/fleet/pull/19972 - [X] Added/updated tests --- server/vulnerabilities/nvd/cve_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/vulnerabilities/nvd/cve_test.go b/server/vulnerabilities/nvd/cve_test.go index c69897179d..fb8ac08070 100644 --- a/server/vulnerabilities/nvd/cve_test.go +++ b/server/vulnerabilities/nvd/cve_test.go @@ -320,6 +320,7 @@ func TestTranslateCPEToCVE(t *testing.T) { }, excludedCVEs: []string{ "CVE-2023-28205", // This vulnerability is for Safari 16.4.0 + "CVE-2024-23252", // Rejected CVE }, continuesToUpdate: true, }, From 83d3c6e6bece8213d14bd3f3250ea713dd0ed5be Mon Sep 17 00:00:00 2001 From: Gabriel Hernandez Date: Fri, 2 Aug 2024 12:49:25 +0100 Subject: [PATCH 46/88] update Other Workflows modal on policy page to be disabled when the form is submitted. (#20933) relates to #20617 Adds disabled overlay to the other workflows modal on the policy page. This required a change to the modal component to render this new overlay and make that accessible to the consumer via a `isContentDisabled` prop ![image](https://github.com/user-attachments/assets/84811ee1-f11f-426f-a2da-9d14c41840ab) Also there are improvements to the my Add policy modal. It seemed to not work with the new modal HTML structure so I fixed and improved how its handling its scrollable content. > NOTE: I did my own manual regression testing to make sure all the modals still looked and worked properly but please tell me if you see one that does not. - [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] Manual QA for all new/changed functionality --- ...0933-disable-overlay-other-workflows-modal | 1 + frontend/components/Modal/Modal.tsx | 50 ++++++++++++------- frontend/components/Modal/_styles.scss | 19 ++++++- .../components/AddPolicyModal/_styles.scss | 16 ++++-- .../OtherWorkflowsModal.tsx | 1 + 5 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 changes/20933-disable-overlay-other-workflows-modal diff --git a/changes/20933-disable-overlay-other-workflows-modal b/changes/20933-disable-overlay-other-workflows-modal new file mode 100644 index 0000000000..e0386552c5 --- /dev/null +++ b/changes/20933-disable-overlay-other-workflows-modal @@ -0,0 +1 @@ +- add a disabled overlay to the Other Workflows modal on the policy page. diff --git a/frontend/components/Modal/Modal.tsx b/frontend/components/Modal/Modal.tsx index 8d96a37818..2cc3dccadd 100644 --- a/frontend/components/Modal/Modal.tsx +++ b/frontend/components/Modal/Modal.tsx @@ -18,6 +18,11 @@ export interface IModalProps { isHidden?: boolean; /** isLoading can be set true to enable targeting elements by loading state */ isLoading?: boolean; + /** isContentDisabled can be set to true to display the modal content as disabled. + * At the moment this will place an overlay over the modal content and make it + * unclickable. + */ + isContentDisabled?: boolean; className?: string; } @@ -29,6 +34,7 @@ const Modal = ({ width = "medium", isHidden = false, isLoading = false, + isContentDisabled = false, className, }: IModalProps): JSX.Element => { useEffect(() => { @@ -61,26 +67,30 @@ const Modal = ({ } }, [onEnter]); - const modalContainerClassName = classnames( - `${baseClass}__modal_container`, + const backgroundClasses = classnames(`${baseClass}__background`, { + [`${baseClass}__hidden`]: isHidden, + }); + + const modalContainerClasses = classnames( className, - { [`${baseClass}__modal_container__medium`]: width === "medium" }, - { [`${baseClass}__modal_container__large`]: width === "large" }, - { [`${baseClass}__modal_container__xlarge`]: width === "xlarge" }, - { [`${baseClass}__modal_container__auto`]: width === "auto" } + `${baseClass}__modal_container`, + `${baseClass}__modal_container__${width}`, + { + [`${className}__loading`]: isLoading, + } ); + const contentWrapperClasses = classnames(`${baseClass}__content-wrapper`, { + [`${baseClass}__content-wrapper-disabled`]: isContentDisabled, + }); + + const contentClasses = classnames(`${baseClass}__content`, { + [`${baseClass}__content-disabled`]: isContentDisabled, + }); + return ( -
    -
    +
    +
    {title}
    @@ -89,7 +99,13 @@ const Modal = ({
    -
    {children}
    + +
    + {isContentDisabled && ( +
    + )} +
    {children}
    +
    ); diff --git a/frontend/components/Modal/_styles.scss b/frontend/components/Modal/_styles.scss index 33fc9939eb..04dc539176 100644 --- a/frontend/components/Modal/_styles.scss +++ b/frontend/components/Modal/_styles.scss @@ -16,7 +16,7 @@ } } - &__content { + &__content-wrapper { margin-top: $pad-large; font-size: $x-small; @@ -100,4 +100,21 @@ width: auto; } } + + // these styles are for the modal content when it is disabled + &__content-wrapper-disabled { + position: relative; + } + + &__content-disabled { + transition: opacity 150ms ease-in-out; + opacity: 0.5; // this adds a disabled effect to the modal content + } + + &__disabled-overlay { + position: absolute; + height: 100%; + width: 100%; + z-index: 1000; + } } diff --git a/frontend/pages/policies/ManagePoliciesPage/components/AddPolicyModal/_styles.scss b/frontend/pages/policies/ManagePoliciesPage/components/AddPolicyModal/_styles.scss index 924a16b0d8..c1cfe99bb9 100644 --- a/frontend/pages/policies/ManagePoliciesPage/components/AddPolicyModal/_styles.scss +++ b/frontend/pages/policies/ManagePoliciesPage/components/AddPolicyModal/_styles.scss @@ -1,17 +1,25 @@ .add-policy-modal { height: 90%; overflow: hidden; - min-height: 460px; - max-height: fit-content; + + // we have to reach into the modal component classes to style the content + // correctly. This is because this modal always has a fixed height and + // the content is scrollable. + .modal__content-wrapper { + height: 95%; + } .modal__content { - height: 90%; - overflow: scroll; + height: 100%; display: flex; flex-direction: column; gap: $pad-large; } + &__policy-selection { + overflow-y: auto; + } + .Select-multi-value-wrapper { display: flex; } diff --git a/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx b/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx index 75c66b5fd7..d34ae56ff6 100644 --- a/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx +++ b/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx @@ -367,6 +367,7 @@ const OtherWorkflowsModal = ({ title="Other workflows" className={baseClass} width="large" + isContentDisabled={isUpdating} >
    Date: Fri, 2 Aug 2024 12:52:52 +0100 Subject: [PATCH 47/88] fix issue with stacking banners after VPP banner was added (#20938) relates to #20939 fix an issue with stacking banners on the host details page after VPP warning banner was added. This also moves up the banner states into the app config to cut down on code duplication on the host details page and the main content component. - [x] Manual QA for all new/changed functionality --- .../components/MainContent/MainContent.tsx | 22 +++++++--------- frontend/context/app.tsx | 25 ++++++++++++++++++ .../HostDetailsBanners/HostDetailsBanners.tsx | 26 ++++++++++--------- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/frontend/components/MainContent/MainContent.tsx b/frontend/components/MainContent/MainContent.tsx index 5c322637d6..ad31ba4711 100644 --- a/frontend/components/MainContent/MainContent.tsx +++ b/frontend/components/MainContent/MainContent.tsx @@ -37,9 +37,12 @@ const MainContent = ({ config, isPremiumTier, noSandboxHosts, - apnsExpiry = "", - abmExpiry = "", - vppExpiry = "", + isApplePnsExpired, + isAppleBmExpired, + isVppExpired, + willAppleBmExpire, + willApplePnsExpire, + willVppExpire, } = useContext(AppContext); const sandboxExpiryTime = @@ -49,29 +52,22 @@ const MainContent = ({ const renderAppWideBanner = () => { const isAppleBmTermsExpired = config?.mdm?.apple_bm_terms_expired; - const isApplePnsExpired = hasLicenseExpired(apnsExpiry); - const willApplePnsExpireIn30Days = willExpireWithinXDays(apnsExpiry, 30); - const isAppleBmExpired = hasLicenseExpired(abmExpiry); // NOTE: See Rachel's related FIXME added to App.tsx in https://github.com/fleetdm/fleet/pull/19571 - const willAppleBmExpireIn30Days = willExpireWithinXDays(abmExpiry, 30); const isFleetLicenseExpired = hasLicenseExpired( config?.license.expiration || "" ); - const isVppExpired = hasLicenseExpired(vppExpiry); - const willVppExpireIn30Days = willExpireWithinXDays(vppExpiry, 30); - let banner: JSX.Element | null = null; if (isPremiumTier) { - if (isApplePnsExpired || willApplePnsExpireIn30Days) { + if (isApplePnsExpired || willApplePnsExpire) { banner = ; - } else if (isAppleBmExpired || willAppleBmExpireIn30Days) { + } else if (isAppleBmExpired || willAppleBmExpire) { banner = ; } else if (isAppleBmTermsExpired) { banner = ; } else if (isFleetLicenseExpired) { banner = ; - } else if (isVppExpired || willVppExpireIn30Days) { + } else if (isVppExpired || willVppExpire) { banner = ; } } diff --git a/frontend/context/app.tsx b/frontend/context/app.tsx index bf84e72aa3..da774708d9 100644 --- a/frontend/context/app.tsx +++ b/frontend/context/app.tsx @@ -11,6 +11,7 @@ import { import { IUser } from "interfaces/user"; import permissions from "utilities/permissions"; import sort from "utilities/sort"; +import { hasLicenseExpired, willExpireWithinXDays } from "utilities/helpers"; enum ACTIONS { SET_AVAILABLE_TEAMS = "SET_AVAILABLE_TEAMS", @@ -144,6 +145,12 @@ type InitialStateType = { isOnlyObserver?: boolean; isObserverPlus?: boolean; isNoAccess?: boolean; + isAppleBmExpired: boolean; + isApplePnsExpired: boolean; + isVppExpired: boolean; + willAppleBmExpire: boolean; + willApplePnsExpire: boolean; + willVppExpire: boolean; abmExpiry?: string; apnsExpiry?: string; vppExpiry?: string; @@ -206,6 +213,12 @@ export const initialState = { filteredSoftwarePath: undefined, filteredQueriesPath: undefined, filteredPoliciesPath: undefined, + isAppleBmExpired: false, + isApplePnsExpired: false, + isVppExpired: false, + willAppleBmExpire: false, + willApplePnsExpire: false, + willVppExpire: false, setAvailableTeams: () => null, setCurrentUser: () => null, setCurrentTeam: () => null, @@ -339,6 +352,8 @@ const reducer = (state: InitialStateType, action: IAction) => { return { ...state, abmExpiry, + isAppleBmExpired: hasLicenseExpired(abmExpiry), + willAppleBmExpire: willExpireWithinXDays(abmExpiry, 30), }; } case ACTIONS.SET_APNS_EXPIRY: { @@ -346,6 +361,8 @@ const reducer = (state: InitialStateType, action: IAction) => { return { ...state, apnsExpiry, + isApplePnsExpired: hasLicenseExpired(apnsExpiry), + willApplePnsExpire: willExpireWithinXDays(apnsExpiry, 30), }; } case ACTIONS.SET_VPP_EXPIRY: { @@ -353,6 +370,8 @@ const reducer = (state: InitialStateType, action: IAction) => { return { ...state, vppExpiry, + isVppExpired: hasLicenseExpired(vppExpiry), + willVppExpire: willExpireWithinXDays(vppExpiry, 30), }; } case ACTIONS.SET_SANDBOX_EXPIRY: { @@ -418,6 +437,12 @@ const AppProvider = ({ children }: Props): JSX.Element => { abmExpiry: state.abmExpiry, apnsExpiry: state.apnsExpiry, vppExpiry: state.vppExpiry, + isAppleBmExpired: state.isAppleBmExpired, + isApplePnsExpired: state.isApplePnsExpired, + isVppExpired: state.isVppExpired, + willAppleBmExpire: state.willAppleBmExpire, + willApplePnsExpire: state.willApplePnsExpire, + willVppExpire: state.willVppExpire, noSandboxHosts: state.noSandboxHosts, filteredHostsPath: state.filteredHostsPath, filteredSoftwarePath: state.filteredSoftwarePath, diff --git a/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx b/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx index 89632164b0..2a35d4a418 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx @@ -23,21 +23,21 @@ const HostDetailsBanners = ({ connectedToFleetMdm, diskEncryptionStatus, }: IHostDetailsBannersProps) => { - const { config, isPremiumTier, apnsExpiry, abmExpiry } = useContext( - AppContext - ); + const { + config, + isPremiumTier, + isAppleBmExpired, + isApplePnsExpired, + isVppExpired, + willAppleBmExpire, + willApplePnsExpire, + willVppExpire, + } = useContext(AppContext); // Checks to see if an app-wide banner is being shown (the ABM terms, ABM expiry, // or APNs expiry banner) in a parent component. App-wide banners found in parent // component take priority over host details page-level banners. const isAppleBmTermsExpired = config?.mdm?.apple_bm_terms_expired; - const isApplePnsExpired = hasLicenseExpired(apnsExpiry || ""); - const willApplePnsExpireIn30Days = willExpireWithinXDays( - apnsExpiry || "", - 30 - ); - const isAppleBmExpired = hasLicenseExpired(abmExpiry || ""); - const willAppleBmExpireIn30Days = willExpireWithinXDays(abmExpiry || "", 30); const isFleetLicenseExpired = hasLicenseExpired( config?.license.expiration || "" ); @@ -46,9 +46,11 @@ const HostDetailsBanners = ({ isPremiumTier && (isAppleBmTermsExpired || isApplePnsExpired || - willApplePnsExpireIn30Days || + willApplePnsExpire || isAppleBmExpired || - willAppleBmExpireIn30Days || + willAppleBmExpire || + isVppExpired || + willVppExpire || isFleetLicenseExpired); const isMdmUnenrolled = From 695801bff6f4456ab0eb16598f575cb0d9d9679e Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:42:49 -0400 Subject: [PATCH 48/88] Fleet UI: Navigate between no teams tabs (#20969) --- frontend/components/top_nav/SiteTopNav/SiteTopNav.tsx | 8 +++----- frontend/components/top_nav/SiteTopNav/navItems.ts | 5 ++--- frontend/components/top_nav/UserMenu/UserMenu.tsx | 4 +--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/frontend/components/top_nav/SiteTopNav/SiteTopNav.tsx b/frontend/components/top_nav/SiteTopNav/SiteTopNav.tsx index 86944020b6..7dbf45785d 100644 --- a/frontend/components/top_nav/SiteTopNav/SiteTopNav.tsx +++ b/frontend/components/top_nav/SiteTopNav/SiteTopNav.tsx @@ -56,6 +56,7 @@ const REGEX_GLOBAL_PAGES = { const REGEX_EXCLUDE_NO_TEAM_PAGES = { MANAGE_POLICIES: /\/policies\/manage/i, + MANAGE_QUERIES: /\/queries\/manage/i, }; const testDetailPage = (path: string, re: RegExp) => { @@ -96,7 +97,6 @@ const SiteTopNav = ({ isGlobalMaintainer, isAnyTeamMaintainer, isNoAccess, - isSandboxMode, } = useContext(AppContext); const isActiveDetailPage = isDetailPage(currentPath); @@ -187,7 +187,7 @@ const SiteTopNav = ({ { @@ -238,7 +237,6 @@ const SiteTopNav = ({ currentUser={currentUser} isAnyTeamAdmin={isAnyTeamAdmin} isGlobalAdmin={isGlobalAdmin} - isSandboxMode={isSandboxMode} />
    ); diff --git a/frontend/components/top_nav/SiteTopNav/navItems.ts b/frontend/components/top_nav/SiteTopNav/navItems.ts index cbf0654723..00e145ae4b 100644 --- a/frontend/components/top_nav/SiteTopNav/navItems.ts +++ b/frontend/components/top_nav/SiteTopNav/navItems.ts @@ -27,8 +27,7 @@ export default ( isAnyTeamAdmin = false, isAnyTeamMaintainer = false, isGlobalMaintainer = false, - isNoAccess = false, - isSandboxMode = false + isNoAccess = false ): INavItem[] => { if (!user) { return []; @@ -67,7 +66,7 @@ export default ( regex: new RegExp(`^${URL_PREFIX}/controls/`), pathname: PATHS.CONTROLS, }, - exclude: isSandboxMode || !isMaintainerOrAdmin, + exclude: !isMaintainerOrAdmin, withParams: { type: "query", names: ["team_id"] }, }, { diff --git a/frontend/components/top_nav/UserMenu/UserMenu.tsx b/frontend/components/top_nav/UserMenu/UserMenu.tsx index 4e08464120..38f7986a43 100644 --- a/frontend/components/top_nav/UserMenu/UserMenu.tsx +++ b/frontend/components/top_nav/UserMenu/UserMenu.tsx @@ -17,7 +17,6 @@ interface IUserMenuProps { isAnyTeamAdmin: boolean | undefined; isGlobalAdmin: boolean | undefined; currentUser: IUser; - isSandboxMode?: boolean; } const UserMenu = ({ @@ -26,7 +25,6 @@ const UserMenu = ({ isAnyTeamAdmin, isGlobalAdmin, currentUser, - isSandboxMode = false, }: IUserMenuProps): JSX.Element => { const accountNavigate = onNavItemClick(PATHS.ACCOUNT); const dropdownItems = [ @@ -44,7 +42,7 @@ const UserMenu = ({ }, ]; - if (isGlobalAdmin && !isSandboxMode) { + if (isGlobalAdmin) { const manageUsersNavigate = onNavItemClick(PATHS.ADMIN_USERS); const manageUserNavItem = { From 0a15647e108f0291598c78636f8e890872cf8310 Mon Sep 17 00:00:00 2001 From: Dante Catalfamo <43040593+dantecatalfamo@users.noreply.github.com> Date: Fri, 2 Aug 2024 10:47:40 -0400 Subject: [PATCH 49/88] Host software deleted at remigration (#20996) # Recreate out of order migration, replace `docker-compose` with `docker compose` in db test runner --- .github/workflows/test-db-changes.yml | 2 +- ...=> 20240802101043_AddSoftwareInstallResultDeletedAt.go} | 7 ++++--- server/datastore/mysql/schema.sql | 2 +- tools/dbutils/schema_generator.go | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) rename server/datastore/mysql/migrations/tables/{20240729120947_AddSoftwareInstallResultDeletedAt.go => 20240802101043_AddSoftwareInstallResultDeletedAt.go} (75%) diff --git a/.github/workflows/test-db-changes.yml b/.github/workflows/test-db-changes.yml index 301645008e..ecfe464072 100644 --- a/.github/workflows/test-db-changes.yml +++ b/.github/workflows/test-db-changes.yml @@ -46,7 +46,7 @@ jobs: - name: Start Infra Dependencies # Use & to background this - run: docker-compose up -d mysql_test & + run: docker compose up -d mysql_test & - name: Verify test schema changes run: | diff --git a/server/datastore/mysql/migrations/tables/20240729120947_AddSoftwareInstallResultDeletedAt.go b/server/datastore/mysql/migrations/tables/20240802101043_AddSoftwareInstallResultDeletedAt.go similarity index 75% rename from server/datastore/mysql/migrations/tables/20240729120947_AddSoftwareInstallResultDeletedAt.go rename to server/datastore/mysql/migrations/tables/20240802101043_AddSoftwareInstallResultDeletedAt.go index bd4219364d..b5f7e79213 100644 --- a/server/datastore/mysql/migrations/tables/20240729120947_AddSoftwareInstallResultDeletedAt.go +++ b/server/datastore/mysql/migrations/tables/20240802101043_AddSoftwareInstallResultDeletedAt.go @@ -6,10 +6,11 @@ import ( ) func init() { - MigrationClient.AddMigration(Up_20240729120947, Down_20240729120947) + MigrationClient.AddMigration(Up_20240802101043, Down_20240802101043) } -func Up_20240729120947(tx *sql.Tx) error { +// This is a new copy of a previous out-of-order migration +func Up_20240802101043(tx *sql.Tx) error { _, err := tx.Exec("ALTER TABLE host_software_installs ADD COLUMN host_deleted_at timestamp NULL DEFAULT NULL") if err != nil { return fmt.Errorf("failed to create host_deleted_at column on host_software_installs table: %w", err) @@ -33,6 +34,6 @@ AND return nil } -func Down_20240729120947(tx *sql.Tx) error { +func Down_20240802101043(tx *sql.Tx) error { return nil } diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index 73e02ac322..22ac9295c1 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -972,7 +972,7 @@ CREATE TABLE `migration_status_tables` ( UNIQUE KEY `id` (`id`) ) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=294 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240729120947,1,'2020-01-01 01:01:01'),(289,20240730171504,1,'2020-01-01 01:01:01'),(290,20240730174056,1,'2020-01-01 01:01:01'),(291,20240730215453,1,'2020-01-01 01:01:01'),(292,20240730374423,1,'2020-01-01 01:01:01'),(293,20240801115359,1,'2020-01-01 01:01:01'); +INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'),(292,20240801115359,1,'2020-01-01 01:01:01'),(293,20240802101043,1,'2020-01-01 01:01:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `mobile_device_management_solutions` ( diff --git a/tools/dbutils/schema_generator.go b/tools/dbutils/schema_generator.go index 2fecce8683..60c01869d3 100644 --- a/tools/dbutils/schema_generator.go +++ b/tools/dbutils/schema_generator.go @@ -67,7 +67,7 @@ func main() { // Dump schema to dumpfile cmd := exec.Command( - "docker-compose", "exec", "-T", "mysql_test", + "docker", "compose", "exec", "-T", "mysql_test", // Command run inside container "mysqldump", "-u"+testUsername, "-p"+testPassword, "schemadb", "--compact", "--skip-comments", ) From 4b2c8a6f02b0f848a9b276e0739c4270c8eba75c Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:12:43 -0700 Subject: [PATCH 50/88] UI: Coordinate sibling refetches via parent state (#20973) ## #20965 https://www.loom.com/share/52ff44615e2e41a99c129acd3d2427bf?sid=f90ead66-9730-4538-95db-a70bf971b5a8 - [x] Manual QA for all new/changed functionality) --------- Co-authored-by: Jacob Shandling --- frontend/pages/SoftwarePage/SoftwarePage.tsx | 5 +++++ .../SoftwareTitles/SoftwareTitles.tsx | 4 ++++ .../components/AddPackage/AddPackage.tsx | 11 +++++++++-- .../AddSoftwareModal/AddSoftwareModal.tsx | 16 ++++++++++++++-- .../components/AppStoreVpp/AppStoreVpp.tsx | 10 +++++++++- frontend/services/entities/software.ts | 4 ++++ 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/frontend/pages/SoftwarePage/SoftwarePage.tsx b/frontend/pages/SoftwarePage/SoftwarePage.tsx index 7def709f9a..5887d0dd11 100644 --- a/frontend/pages/SoftwarePage/SoftwarePage.tsx +++ b/frontend/pages/SoftwarePage/SoftwarePage.tsx @@ -151,6 +151,9 @@ const SoftwarePage = ({ children, router, location }: ISoftwarePageProps) => { const [showPreviewTicketModal, setShowPreviewTicketModal] = useState(false); const [showAddSoftwareModal, setShowAddSoftwareModal] = useState(false); const [resetPageIndex, setResetPageIndex] = useState(false); + const [addedSoftwareToken, setAddedSoftwareToken] = useState( + null + ); const { currentTeamId, @@ -385,6 +388,7 @@ const SoftwarePage = ({ children, router, location }: ISoftwarePageProps) => { showExploitedVulnerabilitiesOnly, softwareFilter, resetPageIndex, + addedSoftwareToken, })}
    ); @@ -424,6 +428,7 @@ const SoftwarePage = ({ children, router, location }: ISoftwarePageProps) => { teamId={currentTeamId ?? 0} router={router} onExit={toggleAddSoftwareModal} + setAddedSoftwareToken={setAddedSoftwareToken} /> )}
    diff --git a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx index 1a90c284f5..6456d616ea 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx @@ -43,6 +43,7 @@ interface ISoftwareTitlesProps { currentPage: number; teamId?: number; resetPageIndex: boolean; + addedSoftwareToken: string | null; } const SoftwareTitles = ({ @@ -56,6 +57,7 @@ const SoftwareTitles = ({ currentPage, teamId, resetPageIndex, + addedSoftwareToken, }: ISoftwareTitlesProps) => { const showVersions = location.pathname === PATHS.SOFTWARE_VERSIONS; @@ -80,6 +82,7 @@ const SoftwareTitles = ({ orderDirection, orderKey, teamId, + addedSoftwareToken, ...getSoftwareFilterForQueryKey(softwareFilter), }, ], @@ -113,6 +116,7 @@ const SoftwareTitles = ({ orderKey, teamId, vulnerable: softwareFilter === "vulnerableSoftware", + addedSoftwareToken, }, ], ({ queryKey: [queryKey] }) => diff --git a/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx b/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx index 78e559b750..2e7e4b17a5 100644 --- a/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx +++ b/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx @@ -21,9 +21,15 @@ interface IAddPackageProps { teamId: number; router: InjectedRouter; onExit: () => void; + setAddedSoftwareToken: (token: string) => void; } -const AddPackage = ({ teamId, router, onExit }: IAddPackageProps) => { +const AddPackage = ({ + teamId, + router, + onExit, + setAddedSoftwareToken, +}: IAddPackageProps) => { const { renderFlash } = useContext(NotificationContext); const [isUploading, setIsUploading] = useState(false); @@ -86,7 +92,8 @@ const AddPackage = ({ teamId, router, onExit }: IAddPackageProps) => { } else { newQueryParams.available_for_install = true; } - + // any unique string - triggers SW refetch + setAddedSoftwareToken(`${Date.now()}`); router.push( `${PATHS.SOFTWARE_TITLES}?${buildQueryStringFromParams(newQueryParams)}` ); diff --git a/frontend/pages/SoftwarePage/components/AddSoftwareModal/AddSoftwareModal.tsx b/frontend/pages/SoftwarePage/components/AddSoftwareModal/AddSoftwareModal.tsx index f6af29e7b4..7f55adbc9a 100644 --- a/frontend/pages/SoftwarePage/components/AddSoftwareModal/AddSoftwareModal.tsx +++ b/frontend/pages/SoftwarePage/components/AddSoftwareModal/AddSoftwareModal.tsx @@ -37,12 +37,14 @@ interface IAddSoftwareModalProps { teamId: number; router: InjectedRouter; onExit: () => void; + setAddedSoftwareToken: (token: string) => void; } const AddSoftwareModal = ({ teamId, router, onExit, + setAddedSoftwareToken, }: IAddSoftwareModalProps) => { return ( App Store (VPP) - + - + diff --git a/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx b/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx index 874d2d8849..4a210b93d5 100644 --- a/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx +++ b/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx @@ -130,9 +130,15 @@ interface IAppStoreVppProps { teamId: number; router: InjectedRouter; onExit: () => void; + setAddedSoftwareToken: (token: string) => void; } -const AppStoreVpp = ({ teamId, router, onExit }: IAppStoreVppProps) => { +const AppStoreVpp = ({ + teamId, + router, + onExit, + setAddedSoftwareToken, +}: IAppStoreVppProps) => { const { renderFlash } = useContext(NotificationContext); const [isSubmitDisabled, setIsSubmitDisabled] = useState(true); const [selectedApp, setSelectedApp] = useState(null); @@ -189,6 +195,8 @@ const AppStoreVpp = ({ teamId, router, onExit }: IAppStoreVppProps) => { team_id: teamId, available_for_install: true, }); + // any unique string - triggers SW refetch + setAddedSoftwareToken(`${Date.now()}`); router.push(`${PATHS.SOFTWARE}?${queryParams}`); } catch (e) { renderFlash("error", getErrorMessage(e)); diff --git a/frontend/services/entities/software.ts b/frontend/services/entities/software.ts index ecb4d98847..d3f85f9d16 100644 --- a/frontend/services/entities/software.ts +++ b/frontend/services/entities/software.ts @@ -56,10 +56,14 @@ export interface ISoftwareVersionResponse { } export interface ISoftwareVersionsQueryKey extends ISoftwareApiParams { + // used to trigger software refetches from sibling pages + addedSoftwareToken: string | null; scope: "software-versions"; } export interface ISoftwareTitlesQueryKey extends ISoftwareApiParams { + // used to trigger software refetches from sibling pages + addedSoftwareToken: string | null; scope: "software-titles"; } From 33fa8f2fe976cb9eaaa3ebfee6d37d7ad00912e5 Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:24:10 -0700 Subject: [PATCH 51/88] =?UTF-8?q?UI=20=E2=80=93=20adjust=20disk=20encrypti?= =?UTF-8?q?on=20table=20style=20(#20981)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## #20395 Screenshot 2024-08-01 at 7 15 00 PM - [x] Changes file added for user-visible changes in `changes/` - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling --- changes/20395-DE-table-style-fix | 1 + .../OSSettings/_styles.scss | 1 + .../DiskEncryptionTable/_styles.scss | 30 +++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 changes/20395-DE-table-style-fix diff --git a/changes/20395-DE-table-style-fix b/changes/20395-DE-table-style-fix new file mode 100644 index 0000000000..8907c36986 --- /dev/null +++ b/changes/20395-DE-table-style-fix @@ -0,0 +1 @@ +* Fix a styling issue in the Controls > OS Settings > disk encryption table \ No newline at end of file diff --git a/frontend/pages/ManageControlsPage/OSSettings/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/_styles.scss index 986234a842..b9c2bf11a5 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/_styles.scss @@ -12,6 +12,7 @@ &__side-nav { .side-nav__nav-list { top: 0; + padding-right: 40px; } } diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss index 74a24f3ac2..45790a5389 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss @@ -9,11 +9,29 @@ border-right: none; } - @media (max-width: 1120px) { - .view-hosts-link { - span { - display: none; - } + .linkToFilteredHosts__header { + width: auto; + max-width: 120px; + } + +} + +@media (max-width: 1120px) { + .view-hosts-link { + span { + display: none; } } -} + .linkToFilteredHosts { + &__header { + width: 0; + .column-header { + width: 0; + } + } + &__cell { + width: min-content; + } + + } +} \ No newline at end of file From d1149a0a7d3d5ff68f6b842191a02c06000a48e4 Mon Sep 17 00:00:00 2001 From: Benjamin Edwards Date: Fri, 2 Aug 2024 11:34:32 -0400 Subject: [PATCH 52/88] Fix decoding enrollment profiles (#20984) --- server/service/apple_mdm.go | 6 +++++- server/service/integration_mdm_lifecycle_test.go | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/server/service/apple_mdm.go b/server/service/apple_mdm.go index 3f1ef747a3..3ff24a0eb0 100644 --- a/server/service/apple_mdm.go +++ b/server/service/apple_mdm.go @@ -3463,9 +3463,13 @@ func RenewSCEPCertificates( } } - migrationEnrollmentProfile := os.Getenv("FLEET_SILENT_MIGRATION_ENROLLMENT_PROFILE") + decodedMigrationEnrollmentProfile, err := base64.StdEncoding.DecodeString(os.Getenv("FLEET_SILENT_MIGRATION_ENROLLMENT_PROFILE")) + if err != nil { + return ctxerr.Wrap(ctx, err, "failed to decode silent migration enrollment profile") + } hasAssocsFromMigration := len(assocsFromMigration) > 0 + migrationEnrollmentProfile := string(decodedMigrationEnrollmentProfile) if migrationEnrollmentProfile == "" && hasAssocsFromMigration { level.Debug(logger).Log("msg", "found devices from migration that need SCEP renewals but FLEET_SILENT_MIGRATION_ENROLLMENT_PROFILE is empty") } diff --git a/server/service/integration_mdm_lifecycle_test.go b/server/service/integration_mdm_lifecycle_test.go index 5dce43108d..bd467afe55 100644 --- a/server/service/integration_mdm_lifecycle_test.go +++ b/server/service/integration_mdm_lifecycle_test.go @@ -3,6 +3,7 @@ package service import ( "context" "crypto/x509" + "encoding/base64" "encoding/json" "encoding/xml" "fmt" @@ -772,7 +773,7 @@ func (s *integrationMDMTestSuite) TestLifecycleSCEPCertExpiration() { require.NoError(t, err) // set the env var, and run the cron - t.Setenv("FLEET_SILENT_MIGRATION_ENROLLMENT_PROFILE", "") + t.Setenv("FLEET_SILENT_MIGRATION_ENROLLMENT_PROFILE", base64.StdEncoding.EncodeToString([]byte(""))) err = RenewSCEPCertificates(ctx, logger, s.ds, &fleetCfg, s.mdmCommander) require.NoError(t, err) checkRenewCertCommand(migratedDevice, "", "") From b846f90e542f19446bc51616fab83c48c2147ab3 Mon Sep 17 00:00:00 2001 From: Dave Herder <27025660+dherder@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:40:29 -0700 Subject: [PATCH 53/88] Add reference to process_etw_events table (#20947) --- articles/osquery-evented-tables-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/articles/osquery-evented-tables-overview.md b/articles/osquery-evented-tables-overview.md index 883f0bc8ab..f1316a85f1 100644 --- a/articles/osquery-evented-tables-overview.md +++ b/articles/osquery-evented-tables-overview.md @@ -121,7 +121,7 @@ On macOS, there are two utilities that enable osquery process auditing: [OpenBSM To use the `es_process_events` tables, use the flag `--disable_endpointsecurity=false`. See the [EndpointSecurity instructions](https://osquery.readthedocs.io/en/latest/deployment/process-auditing/#auditing-processes-with-endpointsecurity) for more information. To use `process_events` and `socket_events` with OpenBSM, see the [OpenBSM instructions](https://osquery.readthedocs.io/en/latest/deployment/process-auditing/#auditing-processes-with-openbsm). #### Windows -Currently, osquery does not support process auditing for Windows. To learn more about process auditing on Windows, visit [Microsoft's security auditing overview](https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/security-auditing-overview). Fleet is tracking work to build process auditing for Windows in osquery. [Stay up to date on GitHub](https://github.com/fleetdm/fleet/issues/7732). +Fleet supports auditing process events on Windows via the `process_etw_events` table. To learn more about process auditing on Windows, visit [Microsoft's security auditing overview](https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/security-auditing-overview). Fleet is tracking work to add file auditing for Windows in osquery. [Stay up to date on GitHub](https://github.com/fleetdm/fleet/issues/20946). ### YARA scanning [YARA](https://virustotal.github.io/yara/) is a malware research and detection tool available on Linux and macOS that allows users to create descriptions of malware families based on patterns of text or binary code. Each potential piece of malware is matched against a YARA rule and triggers if the specified conditions are met. From 209a9b29a5d32fe159113395687760987c0df5fa Mon Sep 17 00:00:00 2001 From: Gabriel Hernandez Date: Fri, 2 Aug 2024 18:56:25 +0100 Subject: [PATCH 54/88] Remove vpp warning banner when it has been successfuly reuploaded (#21003) quick fix to remove the vpp warning banner when the user has successfully uploaded a new one. --- .../IntegrationsPage/cards/Vpp/VppSetupPage/VppSetupPage.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/pages/admin/IntegrationsPage/cards/Vpp/VppSetupPage/VppSetupPage.tsx b/frontend/pages/admin/IntegrationsPage/cards/Vpp/VppSetupPage/VppSetupPage.tsx index a4289664e6..84d75fd073 100644 --- a/frontend/pages/admin/IntegrationsPage/cards/Vpp/VppSetupPage/VppSetupPage.tsx +++ b/frontend/pages/admin/IntegrationsPage/cards/Vpp/VppSetupPage/VppSetupPage.tsx @@ -4,6 +4,7 @@ import { useQuery } from "react-query"; import { AxiosError } from "axios"; import PATHS from "router/paths"; +import { AppContext } from "context/app"; import { NotificationContext } from "context/notification"; import { getErrorReason } from "interfaces/errors"; import mdmAppleAPI, { IGetVppInfoResponse } from "services/entities/mdm_apple"; @@ -121,6 +122,7 @@ interface IVppSetupPageProps { const VppSetupPage = ({ router }: IVppSetupPageProps) => { const [showDisableModal, setShowDisableModal] = useState(false); const [showRenewModal, setShowRenewModal] = useState(false); + const { setVppExpiry } = useContext(AppContext); const { data: vppData, @@ -134,6 +136,9 @@ const VppSetupPage = ({ router }: IVppSetupPageProps) => { { ...DEFAULT_USE_QUERY_OPTIONS, retry: false, + onSuccess: (data) => { + setVppExpiry(data.renew_date); + }, } ); From 2f479b3ba938759055af135504395b9498db08da Mon Sep 17 00:00:00 2001 From: Lucas Manuel Rodriguez Date: Fri, 2 Aug 2024 14:57:50 -0300 Subject: [PATCH 55/88] Release osqueryd 5.13.0 (#20949) --- .github/workflows/generate-osqueryd-targets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-osqueryd-targets.yml b/.github/workflows/generate-osqueryd-targets.yml index 12e08bddac..b5518c995a 100644 --- a/.github/workflows/generate-osqueryd-targets.yml +++ b/.github/workflows/generate-osqueryd-targets.yml @@ -24,7 +24,7 @@ defaults: shell: bash env: - OSQUERY_VERSION: 5.12.2 + OSQUERY_VERSION: 5.13.0 permissions: contents: read From dc5ff724ecd5f7ef427d14765873fa4d39081094 Mon Sep 17 00:00:00 2001 From: Tim Lee Date: Fri, 2 Aug 2024 12:17:47 -0600 Subject: [PATCH 56/88] Bugfix: delete team 0 app (#20987) #20986 - [X] Added/updated tests - [X] Manual QA for all new/changed functionality --- ee/server/service/software_installers.go | 13 +++- server/service/integration_enterprise_test.go | 74 ++++++++++++++++++- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/ee/server/service/software_installers.go b/ee/server/service/software_installers.go index 8754879992..9871f9fd44 100644 --- a/ee/server/service/software_installers.go +++ b/ee/server/service/software_installers.go @@ -20,6 +20,7 @@ import ( "github.com/fleetdm/fleet/v4/server/contexts/viewer" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/mdm/apple/vpp" + "github.com/fleetdm/fleet/v4/server/ptr" "github.com/go-kit/log/level" "github.com/google/uuid" "golang.org/x/sync/errgroup" @@ -121,7 +122,7 @@ func (svc *Service) deleteVPPApp(ctx context.Context, teamID *uint, meta *fleet. } var teamName *string - if teamID != nil { + if teamID != nil && *teamID != 0 { t, err := svc.ds.Team(ctx, *teamID) if err != nil { return ctxerr.Wrap(ctx, err, "getting team name for deleted VPP app") @@ -161,11 +162,19 @@ func (svc *Service) deleteSoftwareInstaller(ctx context.Context, meta *fleet.Sof teamName = &t.Name } + var teamID *uint + switch { + case meta.TeamID == nil: + teamID = ptr.Uint(0) + case meta.TeamID != nil: + teamID = meta.TeamID + } + if err := svc.NewActivity(ctx, vc.User, fleet.ActivityTypeDeletedSoftware{ SoftwareTitle: meta.SoftwareTitle, SoftwarePackage: meta.Name, TeamName: teamName, - TeamID: meta.TeamID, + TeamID: teamID, SelfService: meta.SelfService, }); err != nil { return ctxerr.Wrap(ctx, err, "creating activity for deleted software") diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index 32420f39d6..f87d9b144a 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -9892,7 +9892,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD meta, err := s.ds.GetSoftwareInstallerMetadataByID(context.Background(), id) require.NoError(t, err) - if payload.TeamID != nil { + if payload.TeamID != nil && *payload.TeamID > 0 { require.Equal(t, *payload.TeamID, *meta.TeamID) } else { require.Nil(t, meta.TeamID) @@ -9951,8 +9951,11 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD // download the installer s.Do("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d/package?alt=media", titleID), nil, http.StatusBadRequest) - // delete the installer + // delete the installer from nil team fails s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/software/titles/%d/available_for_install", titleID), nil, http.StatusBadRequest) + + // delete from team 0 succeeds + s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/software/titles/%d/available_for_install", titleID), nil, http.StatusNoContent, "team_id", "0") }) t.Run("create team software installer", func(t *testing.T) { @@ -10027,6 +10030,72 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD // download the installer, not found anymore s.Do("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d/package?alt=media", titleID), nil, http.StatusNotFound, "team_id", fmt.Sprintf("%d", *payload.TeamID)) }) + + t.Run("create team 0 software installer", func(t *testing.T) { + payload := &fleet.UploadSoftwareInstallerPayload{ + TeamID: ptr.Uint(0), + InstallScript: "another install script", + PreInstallQuery: "another pre install query", + PostInstallScript: "another post install script", + Filename: "ruby.deb", + // additional fields below are pre-populated so we can re-use the payload later for the test assertions + Title: "ruby", + Version: "1:2.5.1", + Source: "deb_packages", + StorageID: "df06d9ce9e2090d9cb2e8cd1f4d7754a803dc452bf93e3204e3acd3b95508628", + Platform: "linux", + SelfService: true, + } + s.uploadSoftwareInstaller(payload, http.StatusOK, "") + + // check the software installer + installerID, titleID := checkSoftwareInstaller(t, payload) + + // check activity + s.lastActivityOfTypeMatches(fleet.ActivityTypeAddedSoftware{}.ActivityName(), fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": null, "team_id": 0, "self_service": true}`), 0) + + // upload again fails + s.uploadSoftwareInstaller(payload, http.StatusConflict, "already exists") + + // download the installer + r := s.Do("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d/package?alt=media", titleID), nil, http.StatusOK, "team_id", fmt.Sprintf("%d", 0)) + checkDownloadResponse(t, r, payload.Filename) + + // create an orbit host that is not in the team + hostNotInTeam := createOrbitEnrolledHost(t, "windows", "orbit-host-no-team", s.ds) + // downloading installer still works because we allow it explicitly + s.Do("POST", "/api/fleet/orbit/software_install/package?alt=media", orbitDownloadSoftwareInstallerRequest{ + InstallerID: installerID, + OrbitNodeKey: *hostNotInTeam.OrbitNodeKey, + }, http.StatusOK) + + // create an orbit host, assign to team + hostInTeam := createOrbitEnrolledHost(t, "windows", "orbit-host-team", s.ds) + + // requesting download with alt != media fails + r = s.Do("POST", "/api/fleet/orbit/software_install/package?alt=FOOBAR", orbitDownloadSoftwareInstallerRequest{ + InstallerID: installerID, + OrbitNodeKey: *hostInTeam.OrbitNodeKey, + }, http.StatusBadRequest) + errMsg := extractServerErrorText(r.Body) + require.Contains(t, errMsg, "only alt=media is supported") + + // valid download + r = s.Do("POST", "/api/fleet/orbit/software_install/package?alt=media", orbitDownloadSoftwareInstallerRequest{ + InstallerID: installerID, + OrbitNodeKey: *hostInTeam.OrbitNodeKey, + }, http.StatusOK) + checkDownloadResponse(t, r, payload.Filename) + + // delete the installer + s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/software/titles/%d/available_for_install", titleID), nil, http.StatusNoContent, "team_id", "0") + + // check activity + s.lastActivityOfTypeMatches(fleet.ActivityTypeDeletedSoftware{}.ActivityName(), fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": null, "team_id": 0, "self_service": true}`), 0) + + // download the installer, not found anymore + s.Do("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d/package?alt=media", titleID), nil, http.StatusNotFound, "team_id", fmt.Sprintf("%d", 0)) + }) } func (s *integrationEnterpriseTestSuite) TestApplyTeamsSoftwareConfig() { @@ -12243,7 +12312,6 @@ func (s *integrationEnterpriseTestSuite) TestCalendarEventBodyUpdate() { require.Len(t, calEvents, 1) assert.Contains(t, calEvents[0].Description, fleet.CalendarDefaultDescription) assert.Contains(t, calEvents[0].Description, fleet.CalendarDefaultResolution) - } func (s *integrationEnterpriseTestSuite) TestVPPAppsWithoutMDM() { From 39a9ec1ad6725c68d1140559e9b6f43b6639abf1 Mon Sep 17 00:00:00 2001 From: Noah Talerman <47070608+noahtalerman@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:28:43 -0400 Subject: [PATCH 57/88] Missing space before timestamp (#20811) For the following bug: #20810 --- .../Software/SelfService/SelfServiceItem/SelfServiceItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceItem/SelfServiceItem.tsx b/frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceItem/SelfServiceItem.tsx index 9c4146da4d..76b7cd7f7f 100644 --- a/frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceItem/SelfServiceItem.tsx +++ b/frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceItem/SelfServiceItem.tsx @@ -41,7 +41,7 @@ const STATUS_CONFIG: Record = { tooltip: ({ lastInstalledAt = "" }) => ( <> Software failed to install - {lastInstalledAt ? `(${dateAgo(lastInstalledAt)})` : ""}. Select{" "} + {lastInstalledAt ? ` (${dateAgo(lastInstalledAt)})` : ""}. Select{" "} Retry to install again, or contact your IT department. ), From e7d56e9149c180d32d5207842af2f602b3a210d5 Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Fri, 2 Aug 2024 15:51:43 -0300 Subject: [PATCH 58/88] fix docker compose detection in fleetctl preview (#21006) for https://github.com/fleetdm/fleet/issues/21007 CI that uses this is passing now https://github.com/fleetdm/fleet/actions/runs/10220076886/job/28279696099 # 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] Manual QA for all new/changed functionality --- changes/21006-fleetctl-preview | 1 + cmd/fleetctl/preview.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changes/21006-fleetctl-preview diff --git a/changes/21006-fleetctl-preview b/changes/21006-fleetctl-preview new file mode 100644 index 0000000000..9fe2fd3286 --- /dev/null +++ b/changes/21006-fleetctl-preview @@ -0,0 +1 @@ +* Fixed a bug in `fleetctl preview` that was causing it to fail if Docker was installed without support for the deprecated `docker-compose` CLI diff --git a/cmd/fleetctl/preview.go b/cmd/fleetctl/preview.go index a48734871c..1aa78695f9 100644 --- a/cmd/fleetctl/preview.go +++ b/cmd/fleetctl/preview.go @@ -74,7 +74,7 @@ func (d dockerCompose) Command(arg ...string) *exec.Cmd { func newDockerCompose() (dockerCompose, error) { // first, check if `docker compose` is available - if err := exec.Command("docker compose").Run(); err == nil { + if err := exec.Command("docker", "compose").Run(); err == nil { return dockerCompose{dockerComposeV2}, nil } From 480e123ae53d8de5eb8f1e7c055ae9654d439429 Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Sat, 3 Aug 2024 04:00:33 +0900 Subject: [PATCH 59/88] Create fleet-profile-image.png (#20985) Uploading the Fleet's default profile image for use on brand fronts. --- website/assets/images/fleet-profile-image.png | Bin 0 -> 11380 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 website/assets/images/fleet-profile-image.png diff --git a/website/assets/images/fleet-profile-image.png b/website/assets/images/fleet-profile-image.png new file mode 100644 index 0000000000000000000000000000000000000000..3d28053398fc86c3b0e03473bec0a13b46d8d8ef GIT binary patch literal 11380 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 Date: Fri, 2 Aug 2024 16:06:21 -0300 Subject: [PATCH 60/88] disable FileVault rotation if the server talks to an old fleetd (#21004) for https://github.com/fleetdm/confidential/issues/7522 and part of #13157, support map is defined as: | | fleetd < v1.30 | fleetd >= v1.30 | | -------------- | ---------------------------------------- | ---------------------------------------- | | Server < 4.55 | OK/FileVault rotation uses system prompt | OK/FileVault rotation uses system prompt | | Server >= 4.55 | FileVault rotation disabled | Escrow Buddy | # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [ ] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [ ] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)). --- server/fleet/capabilities.go | 6 +++++ server/service/hosts_test.go | 31 +++++++++++++++++++++- server/service/integration_mdm_test.go | 36 ++++++++++++++++++++++++++ server/service/orbit.go | 12 +++++++++ server/service/orbit_client.go | 2 +- 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/server/fleet/capabilities.go b/server/fleet/capabilities.go index be397bcc32..2e12810be8 100644 --- a/server/fleet/capabilities.go +++ b/server/fleet/capabilities.go @@ -99,5 +99,11 @@ func GetServerDeviceCapabilities() CapabilityMap { return capabilities } +func GetOrbitClientCapabilities() CapabilityMap { + return CapabilityMap{ + CapabilityEscrowBuddy: {}, + } +} + // CapabilitiesHeader is the header name used to communicate the capabilities. const CapabilitiesHeader = "X-Fleet-Capabilities" diff --git a/server/service/hosts_test.go b/server/service/hosts_test.go index b2765516e2..1e9e663ed6 100644 --- a/server/service/hosts_test.go +++ b/server/service/hosts_test.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "errors" "fmt" + "net/http" "strconv" "testing" "time" @@ -13,6 +14,7 @@ import ( "github.com/WatchBeam/clock" "github.com/fleetdm/fleet/v4/server/authz" "github.com/fleetdm/fleet/v4/server/config" + "github.com/fleetdm/fleet/v4/server/contexts/capabilities" "github.com/fleetdm/fleet/v4/server/contexts/license" "github.com/fleetdm/fleet/v4/server/contexts/viewer" "github.com/fleetdm/fleet/v4/server/datastore/mysql" @@ -23,6 +25,7 @@ import ( "github.com/fleetdm/fleet/v4/server/mock" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/test" + kitlog "github.com/go-kit/log" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mozilla.org/pkcs7" @@ -1861,7 +1864,7 @@ func TestBulkOperationFilterValidation(t *testing.T) { func TestSetDiskEncryptionNotifications(t *testing.T) { ds := new(mock.Store) ctx := context.Background() - svc := &Service{ds: ds} + svc := &Service{ds: ds, logger: kitlog.NewNopLogger()} tests := []struct { name string @@ -1873,6 +1876,7 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { getHostDiskEncryptionKey func(context.Context, uint) (*fleet.HostDiskEncryptionKey, error) expectedNotifications *fleet.OrbitConfigNotifications expectedError bool + disableCapability bool }{ { name: "no MDM configured", @@ -1943,6 +1947,24 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { }, expectedError: false, }, + { + name: "darwin needs rotation but client is old", + host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, + appConfig: &fleet.AppConfig{ + MDM: fleet.MDM{EnabledAndConfigured: true}, + }, + diskEncryptionConfigured: true, + isConnectedToFleetMDM: true, + mdmInfo: nil, + getHostDiskEncryptionKey: func(ctx context.Context, id uint) (*fleet.HostDiskEncryptionKey, error) { + return &fleet.HostDiskEncryptionKey{Decryptable: ptr.Bool(false)}, nil + }, + expectedNotifications: &fleet.OrbitConfigNotifications{ + RotateDiskEncryptionKey: true, + }, + expectedError: false, + disableCapability: true, + }, { name: "darwin needs rotation", host: &fleet.Host{ID: 1, Platform: "darwin", OsqueryHostID: ptr.String("foo")}, @@ -2056,6 +2078,13 @@ func TestSetDiskEncryptionNotifications(t *testing.T) { return tt.appConfig, nil } + if !tt.disableCapability { + r := http.Request{ + Header: http.Header{fleet.CapabilitiesHeader: []string{string(fleet.CapabilityEscrowBuddy)}}, + } + ctx = capabilities.NewContext(ctx, &r) + } + notifs := &fleet.OrbitConfigNotifications{} err := svc.setDiskEncryptionNotifications(ctx, notifs, tt.host, tt.appConfig, tt.diskEncryptionConfigured, tt.isConnectedToFleetMDM, tt.mdmInfo) if tt.expectedError { diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index b4180fb2b2..4ccd1cba50 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -1624,6 +1624,42 @@ func (s *integrationMDMTestSuite) TestDiskEncryptionSharedSetting() { checkConfigSetSucceeds() } +func (s *integrationMDMTestSuite) TestEscrowBuddyBackwardsCompat() { + t := s.T() + ctx := context.Background() + + // create a host + host, _ := createHostThenEnrollMDM(s.ds, s.server.URL, t) + orbitKey := setOrbitEnrollment(t, host, s.ds) + host.OrbitNodeKey = &orbitKey + + // install a filevault profile for that host + acResp := appConfigResponse{} + s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{ + "mdm": { "enable_disk_encryption": true } + }`), http.StatusOK, &acResp) + assert.True(t, acResp.MDM.EnableDiskEncryption.Value) + + // set the status as non-decryptable so a notification should be sent + err := s.ds.SetOrUpdateHostDiskEncryptionKey(ctx, host.ID, "", "", ptr.Bool(false)) + require.NoError(t, err) + + // notification is false because the escrow buddy capability is not set + orbitConfigResp := orbitGetConfigResponse{} + s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *host.OrbitNodeKey)), http.StatusOK, &orbitConfigResp) + require.False(t, orbitConfigResp.Notifications.RotateDiskEncryptionKey) + + // send the request again, this time with the right header + orbitConfigResp = orbitGetConfigResponse{} + res := s.DoRawWithHeaders("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *host.OrbitNodeKey)), http.StatusOK, map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", s.token), + fleet.CapabilitiesHeader: string(fleet.CapabilityEscrowBuddy), + }) + err = json.NewDecoder(res.Body).Decode(&orbitConfigResp) + require.NoError(t, err) + require.True(t, orbitConfigResp.Notifications.RotateDiskEncryptionKey) +} + func (s *integrationMDMTestSuite) TestMDMAppleHostDiskEncryption() { t := s.T() ctx := context.Background() diff --git a/server/service/orbit.go b/server/service/orbit.go index 1ee8725a08..e6241a0640 100644 --- a/server/service/orbit.go +++ b/server/service/orbit.go @@ -10,6 +10,7 @@ import ( "net/url" "github.com/fleetdm/fleet/v4/server" + "github.com/fleetdm/fleet/v4/server/contexts/capabilities" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" hostctx "github.com/fleetdm/fleet/v4/server/contexts/host" "github.com/fleetdm/fleet/v4/server/contexts/license" @@ -428,6 +429,17 @@ func (svc *Service) setDiskEncryptionNotifications( switch host.FleetPlatform() { case "darwin": + mp, ok := capabilities.FromContext(ctx) + if !ok { + level.Debug(svc.logger).Log("msg", "no capabilities in context, skipping disk encryption notification") + return nil + } + + if !mp.Has(fleet.CapabilityEscrowBuddy) { + level.Debug(svc.logger).Log("msg", "host doesn't support Escrow Buddy, skipping disk encryption notification", "host_uuid", host.UUID) + return nil + } + notifs.RotateDiskEncryptionKey = encryptionKey != nil && encryptionKey.Decryptable != nil && !*encryptionKey.Decryptable case "windows": isServer := mdmInfo != nil && mdmInfo.IsServer diff --git a/server/service/orbit_client.go b/server/service/orbit_client.go index fb4fe0aa2f..5d4c5ce60c 100644 --- a/server/service/orbit_client.go +++ b/server/service/orbit_client.go @@ -146,7 +146,7 @@ func NewOrbitClient( orbitHostInfo fleet.OrbitHostInfo, onGetConfigErrFns *OnGetConfigErrFuncs, ) (*OrbitClient, error) { - orbitCapabilities := fleet.CapabilityMap{} + orbitCapabilities := fleet.GetOrbitClientCapabilities() bc, err := newBaseClient(addr, insecureSkipVerify, rootCA, "", fleetClientCert, orbitCapabilities) if err != nil { return nil, err From 3230a9aa543d19fc2d74347230659e4ddbd0981a Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:44:38 -0700 Subject: [PATCH 61/88] =?UTF-8?q?UI=20=E2=80=93=20Only=20modify=20nav=20pa?= =?UTF-8?q?dding=20at=20low=20viewport=20width=20(#21005)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Follow-up for #20395 Wider: ![Screenshot 2024-08-02 at 10 54 32 AM](https://github.com/user-attachments/assets/d9f66377-02e6-48be-bf3a-3cac94200379) Narrower: ![Screenshot 2024-08-02 at 10 54 49 AM](https://github.com/user-attachments/assets/9ce7e525-2571-4f15-b29e-6da0f5fdce07) If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/` - covered by previous PR - [x] Manual QA for all new/changed functionality Co-authored-by: Jacob Shandling --- frontend/pages/ManageControlsPage/OSSettings/_styles.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/pages/ManageControlsPage/OSSettings/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/_styles.scss index b9c2bf11a5..37228609c6 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/_styles.scss @@ -12,11 +12,15 @@ &__side-nav { .side-nav__nav-list { top: 0; - padding-right: 40px; } } .side-nav__card-container > .custom-settings { max-width: none; } + @media (max-width: 1120px) { + .side-nav__nav-list { + padding-right: 0; + } + } } From 0f41fc1a8d7d14b08a5332f1cdff281f9ae0dcf3 Mon Sep 17 00:00:00 2001 From: Noah Talerman <47070608+noahtalerman@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:49:20 -0400 Subject: [PATCH 62/88] API design: Hide "Self-service" if there's no self-service software (#20908) --- docs/Contributing/API-for-contributors.md | 1 + docs/REST API/rest-api.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/Contributing/API-for-contributors.md b/docs/Contributing/API-for-contributors.md index 170ff1c8ea..0f1f3a2ffb 100644 --- a/docs/Contributing/API-for-contributors.md +++ b/docs/Contributing/API-for-contributors.md @@ -2481,6 +2481,7 @@ Gets all information required by Fleet Desktop, this includes things like the nu ```json { "failing_policies_count": 3, + "self_service": true, "notifications": { "needs_mdm_migration": true, "renew_enrollment_profile": false, diff --git a/docs/REST API/rest-api.md b/docs/REST API/rest-api.md index e07c86e33f..a447e15a12 100644 --- a/docs/REST API/rest-api.md +++ b/docs/REST API/rest-api.md @@ -3504,6 +3504,7 @@ This is the API route used by the **My device** page in Fleet desktop to display ] } }, + "self_service": true, "org_logo_url": "https://example.com/logo.jpg", "license": { "tier": "free", From 13f68fc387a4b82b0efbd41fe1d3f157009b8f40 Mon Sep 17 00:00:00 2001 From: Noah Talerman <47070608+noahtalerman@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:58:16 -0400 Subject: [PATCH 63/88] =?UTF-8?q?Update=20=F0=9F=8E=81=F0=9F=97=A3=20Featu?= =?UTF-8?q?re=20Fest=20(#20962)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handbook/company/product-groups.md | 40 ++++++++---------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/handbook/company/product-groups.md b/handbook/company/product-groups.md index 17b3acbd15..f084beaf7e 100644 --- a/handbook/company/product-groups.md +++ b/handbook/company/product-groups.md @@ -296,33 +296,21 @@ To make a feature request or advocate for a feature request from a customer or c Requests are weighed from top to bottom while prioritizing attendee requests. This means that if the individual that added a feature request is not in attendance, the feature request will be discussed towards the end of the call if there's time. -To be acceptable for consideration, a request must: -- Have a clear proposed change -- Have a well-articulated underlying user need -- Specify the requestor (either internal stakeholder or customer or community user) - -To help the product team, other pieces of information can be optionally included: -- How would they solve the problem without any changes if pressed? -- How does this change fit into the requester's overall usage of Fleet? -- What other potential changes to the product have you considered? - -To ensure your request appears on the ["Feature Fest" board](https://app.zenhub.com/workspaces/-feature-fest-651b2962605ba29209324c57/board): -- Add the `~feature fest` label to your issue -- Add the relevant customer label (if applicable) - -To maximize your chances of having a feature accepted, requesters can visit the [🗣 Product office hours](#rituals) meeting to get feedback on requests prior to being accepted. - ### How feature requests are evaluated Digestion of these new product ideas (requests) happens at the **🎁🗣 Feature Fest** meeting. -At the **🎁🗣 Feature Fest** meeting, the DRI (Head of Product) weighs all requests on the board. When the team weighs a request, it is immediately prioritized or put to the side. +Before the **🎁🗣 Feature Fest** meeting, the [Customer renewals DRI](https://fleetdm.com/handbook/company/communications#directly-responsible-individuals-dris) goes through the "Inbox" column and removes customer requests that are not a high priority for the business. Stakeholders will be notified by the Customer renewals DRI. -Product Managers prioritize all potential product improvements worked on by Fleeties. Anyone (Fleeties, customers, and community members) are invited to suggest improvements. +All community and contributor requests (non-customer) are left in the inbox. A high priority customer request may be a request that's blocking a customer from getting their job done or a request that's critical for customer renewal. -- A _request is prioritized_ when the DRI decides it is a priority. When this happens, the team sets the request to be estimated within five business days. +Before the meeting, the Feature prioritization DRI adds requests from Fleet's roadmap that are planned for the next design sprint. The quarterly roadmap is in the [OKRs spreadsheet](https://docs.google.com/spreadsheets/d/1Hso0LxqwrRVINCyW_n436bNHmoqhoLhC8bcbvLPOs9A/edit?gid=0#gid=0). + +At the **🎁🗣 Feature Fest** meeting, the Feature prioritization DRI weighs all requests in the inbox. When the team weighs a request, it is immediately prioritized or put to the side (not prioritized). + +- A _request is prioritized_ when the Feature prioritization DRI decides it is a priority. - A _request is put to the side_ when the business perceives competing priorities as more pressing in the immediate moment. -If a feature is not prioritized during a 🎁🗣 Feature Fest meeting, it only means the feature has been rejected _at that time_. Requestors will be notified by the Head of Product, and they can resubmit their request at a future meeting. +If a feature is not prioritized during a 🎁🗣 Feature Fest meeting, it only means the feature has been rejected _at that time_. Requestors will be notified by the Feature prioritization DRI, and they can resubmit their request at a future meeting. Requests are weighed by: - The completeness of the request (see [making a request](#making-a-request)) @@ -331,16 +319,10 @@ Requests are weighed by: - How well the request fits within Fleet's product vision and roadmap - Whether the feature seems like it can be designed, estimated, and developed in 6 weeks, given its individual complexity and when combined with other work already accepted -### Customer feature requests -The product team's goal is to prioritize 16 customer feature requests at Feature Fest, then take them from settled to shipped. The customer success team is responsible for providing the Head of Product a live count during the Feature Fest meeting. Product Operations is responsible for monitoring this KPI and raising alarms throughout the design and engineering sprints. -> Customer stories should be estimated at 1-3 points each to count as 1 request. If a feature request spans across multiple customers, it will be counted as the number of customers involved. - ### After the feature is accepted -After the 🎁🗣 Feature Fest meeting, Product Operations will clear the Feature Fest board as follows: -**Prioritized features:** Remove `feature fest` label, add `:product` label, and assign the group Product Manager. -**Put to the side features:** Remove `feature fest` label and close the issue. - -Group Product Managers will then develop user stories for the prioritized features. +After the 🎁🗣 Feature Fest meeting, the Feature prioritization DRI will clear the Feature Fest board as follows: +**Prioritized features:** Remove `feature fest` label, add `:product` label, and move the issue to the "Ready" column in the drafting board. The request will then be assigned to a [Product Designer](https://fleetdm.com/handbook/company/product-groups#current-product-groups) during the "Design sprint kick-off" ritual. +**Put to the side features:** Remove `feature fest` label and notify the requestor. > The product team's commitment to the requester is that a prioritized feature will be delivered within 6 weeks or the requester will be notified within 1 business day of the decision to de-prioritize the feature. From 611aeb311a7d5d5250f6671822c07336290346b3 Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Sat, 3 Aug 2024 05:33:23 +0900 Subject: [PATCH 64/88] website-vulnerabilty-management-fix (#20989) Fixes for https://github.com/fleetdm/fleet/pull/20988 - Increased width of header to fix widowed text - Reworded caption to fix widowed text and typo --- website/assets/styles/pages/vulnerability-management.less | 2 +- website/views/pages/vulnerability-management.ejs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/assets/styles/pages/vulnerability-management.less b/website/assets/styles/pages/vulnerability-management.less index 17a1504178..87998dd3d2 100644 --- a/website/assets/styles/pages/vulnerability-management.less +++ b/website/assets/styles/pages/vulnerability-management.less @@ -46,7 +46,7 @@ [purpose='page-headline'] { padding-bottom: 80px; - width: 680px; + max-width: 780px; h2 { font-size: 48px; font-style: normal; diff --git a/website/views/pages/vulnerability-management.ejs b/website/views/pages/vulnerability-management.ejs index adca60393d..e1f3982eb7 100644 --- a/website/views/pages/vulnerability-management.ejs +++ b/website/views/pages/vulnerability-management.ejs @@ -12,7 +12,7 @@
    Report what matters -

    Report exactly when CVEs got fixed or mitigated, down to the hour

    +

    Report exactly when CVEs were fixed or mitigated, down to the hour.

    Deep context from the environment

    Fleet gives you data down to the chip level on every endpoint to help you make sense of which vulnerabilities to prioritize.

    Untangle your security stack From ab7df5155dfe4fbdf3e9bf5e02abb198ea52f88c Mon Sep 17 00:00:00 2001 From: Lucas Manuel Rodriguez Date: Fri, 2 Aug 2024 18:12:36 -0300 Subject: [PATCH 65/88] Use docker compose on CI instead of docker-compose (#21017) After this is merged I'll cherry pick to `minor-fleet-4.55.0`. --- .github/workflows/fleet-and-orbit.yml | 2 +- .github/workflows/test-go.yaml | 6 +++--- Makefile | 6 +++--- server/datastore/mysql/migrations_test.go | 2 +- server/datastore/mysql/testing_utils.go | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/fleet-and-orbit.yml b/.github/workflows/fleet-and-orbit.yml index 4cab7da482..571d59d067 100644 --- a/.github/workflows/fleet-and-orbit.yml +++ b/.github/workflows/fleet-and-orbit.yml @@ -111,7 +111,7 @@ jobs: done - name: Start Infra Dependencies - run: FLEET_MYSQL_IMAGE=${{ matrix.mysql }} docker-compose up -d mysql redis & + run: FLEET_MYSQL_IMAGE=${{ matrix.mysql }} docker compose up -d mysql redis & - name: Install JS Dependencies run: make deps-js diff --git a/.github/workflows/test-go.yaml b/.github/workflows/test-go.yaml index 0f128b8025..5256806b5f 100644 --- a/.github/workflows/test-go.yaml +++ b/.github/workflows/test-go.yaml @@ -70,7 +70,7 @@ jobs: # Pre-starting dependencies here means they are ready to go when we need them. - name: Start Infra Dependencies # Use & to background this - run: FLEET_MYSQL_IMAGE=${{ matrix.mysql }} docker-compose -f docker-compose.yml -f docker-compose-redis-cluster.yml up -d mysql_test mysql_replica_test redis redis-cluster-1 redis-cluster-2 redis-cluster-3 redis-cluster-4 redis-cluster-5 redis-cluster-6 redis-cluster-setup minio saml_idp mailhog mailpit smtp4dev_test & + run: FLEET_MYSQL_IMAGE=${{ matrix.mysql }} docker compose -f docker-compose.yml -f docker-compose-redis-cluster.yml up -d mysql_test mysql_replica_test redis redis-cluster-1 redis-cluster-2 redis-cluster-3 redis-cluster-4 redis-cluster-5 redis-cluster-6 redis-cluster-setup minio saml_idp mailhog mailpit smtp4dev_test & - name: Add TLS certificate for SMTP Tests run: | @@ -98,13 +98,13 @@ jobs: - name: Wait for mysql run: | echo "waiting for mysql..." - until docker-compose exec -T mysql_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do + until docker compose exec -T mysql_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do echo "." sleep 1 done echo "mysql is ready" echo "waiting for mysql replica..." - until docker-compose exec -T mysql_replica_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do + until docker compose exec -T mysql_replica_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do echo "." sleep 1 done diff --git a/Makefile b/Makefile index 2e7c317baa..c7eaac214c 100644 --- a/Makefile +++ b/Makefile @@ -281,7 +281,7 @@ binary-arch: .pre-binary-arch .pre-binary-bundle .pre-fleet # Drop, create, and migrate the e2e test database e2e-reset-db: - docker-compose exec -T mysql_test bash -c 'echo "drop database if exists e2e; create database e2e;" | MYSQL_PWD=toor mysql -uroot' + docker compose exec -T mysql_test bash -c 'echo "drop database if exists e2e; create database e2e;" | MYSQL_PWD=toor mysql -uroot' ./build/fleet prepare db --mysql_address=localhost:3307 --mysql_username=root --mysql_password=toor --mysql_database=e2e e2e-setup: @@ -312,7 +312,7 @@ e2e-serve-premium: e2e-reset-db # Usage: # make e2e-set-desktop-token host_id=1 token=foo e2e-set-desktop-token: - docker-compose exec -T mysql_test bash -c 'echo "INSERT INTO e2e.host_device_auth (host_id, token) VALUES ($(host_id), \"$(token)\") ON DUPLICATE KEY UPDATE token=VALUES(token)" | MYSQL_PWD=toor mysql -uroot' + docker compose exec -T mysql_test bash -c 'echo "INSERT INTO e2e.host_device_auth (host_id, token) VALUES ($(host_id), \"$(token)\") ON DUPLICATE KEY UPDATE token=VALUES(token)" | MYSQL_PWD=toor mysql -uroot' changelog: sh -c "find changes -type f | grep -v .keep | xargs -I {} sh -c 'grep \"\S\" {}; echo' > new-CHANGELOG.md" @@ -347,7 +347,7 @@ fleetd-tuf: # Reset the development DB db-reset: - docker-compose exec -T mysql bash -c 'echo "drop database if exists fleet; create database fleet;" | MYSQL_PWD=toor mysql -uroot' + docker compose exec -T mysql bash -c 'echo "drop database if exists fleet; create database fleet;" | MYSQL_PWD=toor mysql -uroot' ./build/fleet prepare db --dev # Back up the development DB to file diff --git a/server/datastore/mysql/migrations_test.go b/server/datastore/mysql/migrations_test.go index a8a010dc8f..e782e0d2b2 100644 --- a/server/datastore/mysql/migrations_test.go +++ b/server/datastore/mysql/migrations_test.go @@ -64,7 +64,7 @@ func TestMigrations(t *testing.T) { // Dump schema to dumpfile cmd := exec.Command( - "docker-compose", "exec", "-T", "mysql_test", + "docker", "compose", "exec", "-T", "mysql_test", // Command run inside container "mysqldump", "-u"+testUsername, "-p"+testPassword, "TestMigrations", "--compact", "--skip-comments", ) diff --git a/server/datastore/mysql/testing_utils.go b/server/datastore/mysql/testing_utils.go index 5fdc6a9082..f36ed5f961 100644 --- a/server/datastore/mysql/testing_utils.go +++ b/server/datastore/mysql/testing_utils.go @@ -237,7 +237,7 @@ func setupRealReplica(t testing.TB, testName string, ds *Datastore, options *dbO func() { // Stop slave if out, err := exec.Command( - "docker-compose", "exec", "-T", "mysql_replica_test", + "docker", "compose", "exec", "-T", "mysql_replica_test", // Command run inside container "mysql", "-u"+testUsername, "-p"+testPassword, @@ -282,7 +282,7 @@ func setupRealReplica(t testing.TB, testName string, ds *Datastore, options *dbO // Configure slave and start replication if out, err := exec.Command( - "docker-compose", "exec", "-T", "mysql_replica_test", + "docker", "compose", "exec", "-T", "mysql_replica_test", // Command run inside container "mysql", "-u"+testUsername, "-p"+testPassword, @@ -348,7 +348,7 @@ func initializeDatabase(t testing.TB, testName string, opts *DatastoreTestOption ) cmd := exec.Command( - "docker-compose", "exec", "-T", "mysql_test", + "docker", "compose", "exec", "-T", "mysql_test", // Command run inside container "mysql", "-u"+testUsername, "-p"+testPassword, @@ -369,7 +369,7 @@ func initializeDatabase(t testing.TB, testName string, opts *DatastoreTestOption ) cmd := exec.Command( - "docker-compose", "exec", "-T", "mysql_replica_test", + "docker", "compose", "exec", "-T", "mysql_replica_test", // Command run inside container "mysql", "-u"+testUsername, "-p"+testPassword, From c83458e26f1bd05c50ca87d78e14093f98aa8b0b Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:15:20 -0400 Subject: [PATCH 66/88] Fleet UI: No team header text and button fix (#21018) --- frontend/hooks/useTeamIdParam.ts | 2 ++ frontend/pages/SoftwarePage/SoftwarePage.tsx | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/hooks/useTeamIdParam.ts b/frontend/hooks/useTeamIdParam.ts index f1683aa204..530ec3bb9f 100644 --- a/frontend/hooks/useTeamIdParam.ts +++ b/frontend/hooks/useTeamIdParam.ts @@ -395,6 +395,8 @@ export const useTeamIdParam = ({ currentTeamName: currentTeam?.name, currentTeamSummary: currentTeam, isAnyTeamSelected: isAnyTeamSelected(currentTeam?.id), + isAllTeamsSelected: + !isAnyTeamSelected(currentTeam?.id) && currentTeam?.id !== 0, isRouteOk, isTeamAdmin: !!currentTeam?.id && permissions.isTeamAdmin(currentUser, currentTeam.id), diff --git a/frontend/pages/SoftwarePage/SoftwarePage.tsx b/frontend/pages/SoftwarePage/SoftwarePage.tsx index 5887d0dd11..1cf063cc2d 100644 --- a/frontend/pages/SoftwarePage/SoftwarePage.tsx +++ b/frontend/pages/SoftwarePage/SoftwarePage.tsx @@ -157,7 +157,7 @@ const SoftwarePage = ({ children, router, location }: ISoftwarePageProps) => { const { currentTeamId, - isAnyTeamSelected, + isAllTeamsSelected, isRouteOk, teamIdForApi, userTeams, @@ -318,7 +318,7 @@ const SoftwarePage = ({ children, router, location }: ISoftwarePageProps) => { const renderPageActions = () => { const canManageAutomations = - isGlobalAdmin && (!isPremiumTier || !isAnyTeamSelected); + isGlobalAdmin && (!isPremiumTier || isAllTeamsSelected); const canAddSoftware = isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer; @@ -349,7 +349,7 @@ const SoftwarePage = ({ children, router, location }: ISoftwarePageProps) => { return (

    Manage software and search for installed software, OS and - vulnerabilities {isAnyTeamSelected ? "on this team" : "for all hosts"}. + vulnerabilities {isAllTeamsSelected ? "for all hosts" : "on this team"}.

    ); }; From 1d3c6f3a960c2cf9fc760680490eed01fbec5a58 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 2 Aug 2024 16:51:49 -0500 Subject: [PATCH 67/88] Fix typo in pricing-features-table.yml key (#20825) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: Fixed a typo in the pricing features table yaml (description » description) --- handbook/company/pricing-features-table.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handbook/company/pricing-features-table.yml b/handbook/company/pricing-features-table.yml index f29ddac991..4514c3c95e 100644 --- a/handbook/company/pricing-features-table.yml +++ b/handbook/company/pricing-features-table.yml @@ -1102,7 +1102,7 @@ # ╚╗╔╝╠═╣╠╦╝║╠═╣╠╩╗║ ║╣ ╠═╣║ ╦║╣ ║║║ ║ ╚╗╔╝║╣ ╠╦╝╚═╗║║ ║║║║╚═╗ # ╚╝ ╩ ╩╩╚═╩╩ ╩╚═╝╩═╝╚═╝ ╩ ╩╚═╝╚═╝╝╚╝ ╩ ╚╝ ╚═╝╩╚═╚═╝╩╚═╝╝╚╝╚═╝ - industryName: Variable agent versions - descrption: Manage agents remotely by setting different versions per-baseline. + description: Manage agents remotely by setting different versions per-baseline. documentationUrl: https://fleetdm.com/docs/configuration/agent-configuration#configure-fleetd-update-channels tier: Premium jamfProHasFeature: no From e790e56a06f690d270f4b3f686401393040e247a Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 2 Aug 2024 17:05:12 -0500 Subject: [PATCH 68/88] Website: Validate keys in pricing table configuration (#20826) Closes: #20776 Changes: - updated the build-static-content script to throw an error if a feature in the pricing-features-table.yml contains an unrecognized key. Note: The "Test Fleet website" GH action will fail until https://github.com/fleetdm/fleet/pull/20825 is merged and this PR is updated. --- website/scripts/build-static-content.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/website/scripts/build-static-content.js b/website/scripts/build-static-content.js index 03050e00f0..042a43cfe1 100644 --- a/website/scripts/build-static-content.js +++ b/website/scripts/build-static-content.js @@ -804,7 +804,14 @@ module.exports = { let pricingTableFeatures = YAML.parse(yaml, {prettyErrors: true}); let VALID_PRODUCT_CATEGORIES = ['Endpoint operations', 'Device management', 'Vulnerability management']; let VALID_PRICING_TABLE_CATEGORIES = ['Support', 'Deployment', 'Integrations', 'Endpoint operations', 'Device management', 'Vulnerability management']; + let VALID_PRICING_TABLE_KEYS = ['industryName', 'description', 'documentationUrl', 'tier', 'jamfProHasFeature', 'jamfProtectHasFeature', 'usualDepartment', 'productCategories', 'pricingTableCategories', 'waysToUse', 'buzzwords', 'demos', 'dri', 'friendlyName', 'moreInfoUrl', 'comingSoonOn', 'screenshotSrc', 'isExperimental']; for(let feature of pricingTableFeatures){ + // Throw an error if a feature contains an unrecognized key. + for(let key of _.keys(feature)){ + if(!VALID_PRICING_TABLE_KEYS.includes(key)){ + throw new Error(`Unrecognized key. Could not build pricing table config from pricing-features-table.yml. The "${feature.industryName}" feature contains an unrecognized key (${key}). To resolve, fix any typos or remove this key and try running this script again.`); + } + } if(feature.name) {// Compatibility check throw new Error(`Could not build pricing table config from pricing-features-table.yml. A feature has a "name" (${feature.name}) which is no longer supported. To resolve, add a "industryName" to this feature: ${feature}`); } From c0cc609127d5b9d8934f6a6728832993cea184cf Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 2 Aug 2024 17:10:56 -0500 Subject: [PATCH 69/88] Website: Use GitHub API to get `lastmodifiedAt` timestamps (#20859) Closes: #20823 Changes: - Updated the build-static-content script to use the GitHub API to get timestamps of when files were last changed. - Updated the get-extended-osquery schema helper to use a GitHub token to authenticate GitHub requests (if it is provided) --- .../helpers/get-extended-osquery-schema.js | 20 ++++-- website/scripts/build-static-content.js | 67 +++++++++++++++---- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/website/api/helpers/get-extended-osquery-schema.js b/website/api/helpers/get-extended-osquery-schema.js index d19b090b7b..1a697a5847 100644 --- a/website/api/helpers/get-extended-osquery-schema.js +++ b/website/api/helpers/get-extended-osquery-schema.js @@ -11,6 +11,10 @@ module.exports = { type: 'boolean', defaultsTo: false, description: 'Whether or not to include a lastModifiedAt value for each table.', + }, + githubAccessToken: { + type: 'string', + description: 'A github token used to authenticate requests to the GitHub API' } }, @@ -25,11 +29,10 @@ module.exports = { }, - fn: async function ({includeLastModifiedAtValue}) { + fn: async function ({includeLastModifiedAtValue, githubAccessToken}) { let path = require('path'); let YAML = require('yaml'); let util = require('util'); - let topLvlRepoPath = path.resolve(sails.config.appPath, '../'); require('assert')(sails.config.custom.versionOfOsquerySchemaToUseWhenGeneratingDocumentation, 'Please set sails.config.custom.sails.config.custom.versionOfOsquerySchemaToUseWhenGeneratingDocumentation to the version of osquery to use, for example \'5.8.1\'.'); let VERSION_OF_OSQUERY_SCHEMA_TO_USE = sails.config.custom.versionOfOsquerySchemaToUseWhenGeneratingDocumentation; @@ -40,6 +43,14 @@ module.exports = { let rawOsqueryTablesLastModifiedAt; if(includeLastModifiedAtValue) { // If we're including a lastModifiedAt value for schema tables, we'll send a request to the GitHub API to get a timestamp of when the last commit + let baseHeadersForGithubRequests = { + 'User-Agent': 'fleet-schema-builder', + 'Accept': 'application/vnd.github.v3+json', + }; + // If a GitHub access token was provided, add it to the headers. + if(githubAccessToken){ + baseHeadersForGithubRequests['Authorization'] = `token ${githubAccessToken}`; + } let responseData = await sails.helpers.http.get.with({// [?]: https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#list-commits url: 'https://api.github.com/repos/osquery/osquery-site/commits', data: { @@ -47,10 +58,7 @@ module.exports = { page: 1, per_page: 1,//eslint-disable-line camelcase }, - headers: { - 'User-Agent': 'fleet-schema-builder', - 'Accept': 'application/vnd.github.v3+json', - }, + headers: baseHeadersForGithubRequests }).intercept((err)=>{ return new Error(`When trying to send a request to GitHub get a timestamp of the last commit to the osqeury schema JSON, an error occurred. Full error: ${util.inspect(err)}`); }); diff --git a/website/scripts/build-static-content.js b/website/scripts/build-static-content.js index 042a43cfe1..a34e2b5640 100644 --- a/website/scripts/build-static-content.js +++ b/website/scripts/build-static-content.js @@ -16,7 +16,7 @@ module.exports = { fn: async function ({ dry, githubAccessToken }) { let path = require('path'); let YAML = require('yaml'); - + let util = require('util'); // FUTURE: If we ever need to gather source files from other places or branches, etc, see git history of this file circa 2021-05-19 for an example of a different strategy we might use to do that. let topLvlRepoPath = path.resolve(sails.config.appPath, '../'); @@ -390,11 +390,29 @@ module.exports = { }//fi // Get last modified timestamp using git, and represent it as a JS timestamp. - // > Inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L265-L273 - let lastModifiedAt = (new Date((await sails.helpers.process.executeCommand.with({ - command: `git log -1 --format="%ai" '${path.relative(topLvlRepoPath, pageSourcePath)}'`, - dir: topLvlRepoPath, - })).stdout)).getTime(); + let lastModifiedAt; + if(!githubAccessToken) { + lastModifiedAt = Date.now(); + } else { + let responseData = await sails.helpers.http.get.with({// [?]: https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#list-commits + url: 'https://api.github.com/repos/fleetdm/fleet/commits', + data: { + path: path.join(sectionRepoPath, pageRelSourcePath), + page: 1, + per_page: 1,//eslint-disable-line camelcase + }, + headers: baseHeadersForGithubRequests, + }).intercept((err)=>{ + return new Error(`When getting the commit history for ${path.join(sectionRepoPath, pageRelSourcePath)} to get a lastModifiedAt timestamp, an error occured.`, err); + }); + // The value we'll use for the lastModifiedAt timestamp will be date value of the `commiter` property of the `commit` we got in the API response from github. + let mostRecentCommitToOsquerySchema = responseData[0]; + if(!mostRecentCommitToOsquerySchema.commit || !mostRecentCommitToOsquerySchema.commit.committer) { + // Throw an error if the the response from GitHub is missing a commit or commiter. + throw new Error(`When getting the commit history for ${path.join(sectionRepoPath, pageRelSourcePath)} to get a lastModifiedAt timestamp, the response from the GitHub API did not include information about the most recent commit. Response from GitHub: ${util.inspect(responseData, {depth:null})}`); + } + lastModifiedAt = (new Date(mostRecentCommitToOsquerySchema.commit.committer.date)).getTime(); // Convert the UTC timestamp from GitHub to a JS timestamp. + } // Determine display title (human-readable title) to use for this page. let pageTitle; @@ -560,11 +578,30 @@ module.exports = { let RELATIVE_PATH_TO_OPEN_POSITIONS_YML_IN_FLEET_REPO = 'handbook/company/open-positions.yml'; // Get last modified timestamp using git, and represent it as a JS timestamp. - // > Inspired by https://github.com/uncletammy/doc-templater/blob/2969726b598b39aa78648c5379e4d9503b65685e/lib/compile-markdown-tree-from-remote-git-repo.js#L265-L273 - let lastModifiedAt = (new Date((await sails.helpers.process.executeCommand.with({ - command: `git log -1 --format="%ai" '${path.join(topLvlRepoPath, RELATIVE_PATH_TO_OPEN_POSITIONS_YML_IN_FLEET_REPO)}'`, - dir: topLvlRepoPath, - })).stdout)).getTime(); + let lastModifiedAt; + if(!githubAccessToken) { + lastModifiedAt = Date.now(); + } else { + // If we're including a lastModifiedAt value for schema tables, we'll send a request to the GitHub API to get a timestamp of when the last commit + let responseData = await sails.helpers.http.get.with({// [?]: https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#list-commits + url: 'https://api.github.com/repos/fleetdm/fleet/commits', + data: { + path: RELATIVE_PATH_TO_OPEN_POSITIONS_YML_IN_FLEET_REPO, + page: 1, + per_page: 1,//eslint-disable-line camelcase + }, + headers: baseHeadersForGithubRequests, + }).intercept((err)=>{ + return new Error(`When getting the commit history for the open positions YAML to get a lastModifiedAt timestamp, an error occured.`, err); + }); + // The value we'll use for the lastModifiedAt timestamp will be date value of the `commiter` property of the `commit` we got in the API response from github. + let mostRecentCommitToOsquerySchema = responseData[0]; + if(!mostRecentCommitToOsquerySchema.commit || !mostRecentCommitToOsquerySchema.commit.committer) { + // Throw an error if the the response from GitHub is missing a commit or commiter. + throw new Error(`When trying to get a lastModifiedAt timestamp for the open positions YAML, the response from the GitHub API did not include information about the most recent commit. Response from GitHub: ${util.inspect(responseData, {depth:null})}`); + } + lastModifiedAt = (new Date(mostRecentCommitToOsquerySchema.commit.committer.date)).getTime(); // Convert the UTC timestamp from GitHub to a JS timestamp. + } let openPositionsYaml = await sails.helpers.fs.read(path.join(topLvlRepoPath, RELATIVE_PATH_TO_OPEN_POSITIONS_YML_IN_FLEET_REPO)).intercept('doesNotExist', (err)=>new Error(`Could not find open positions YAML file at "${RELATIVE_PATH_TO_OPEN_POSITIONS_YML_IN_FLEET_REPO}". Was it accidentally moved? Raw error: `+err.message)); let openPositionsToCreatePartialsFor = YAML.parse(openPositionsYaml, {prettyErrors: true}); @@ -673,7 +710,12 @@ module.exports = { } // After we build the Markdown pages, we'll merge the osquery schema with the Fleet schema overrides, then create EJS partials for each table in the merged schema. - let expandedTables = await sails.helpers.getExtendedOsquerySchema.with({includeLastModifiedAtValue: true}); + let expandedTables; + if(githubAccessToken){ + expandedTables = await sails.helpers.getExtendedOsquerySchema.with({includeLastModifiedAtValue: true, githubAccessToken,}); + } else { + expandedTables = await sails.helpers.getExtendedOsquerySchema(); + } // Once we have our merged schema, we'll create ejs partials for each table. for(let table of expandedTables) { @@ -1098,7 +1140,6 @@ module.exports = { } }); } - } From 5f7a644e3cb2b6f737d77b177daceafdb2f6ac6a Mon Sep 17 00:00:00 2001 From: Jahziel Villasana-Espinoza Date: Fri, 2 Aug 2024 18:50:03 -0400 Subject: [PATCH 70/88] fix software array migration (#21010) > Related issue: #20978 # 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] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated tests - [x] If database migrations are included, checked table schema to confirm autoupdate - For database migrations: - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Manual QA for all new/changed functionality --- changes/fix-software-array-migration | 2 + ...240802113716_UpdateSoftwareGitopsConfig.go | 59 ++++++ ...2113716_UpdateSoftwareGitopsConfig_test.go | 194 ++++++++++++++++++ server/datastore/mysql/schema.sql | 4 +- 4 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 changes/fix-software-array-migration create mode 100644 server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go create mode 100644 server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go diff --git a/changes/fix-software-array-migration b/changes/fix-software-array-migration new file mode 100644 index 0000000000..27536ccc1e --- /dev/null +++ b/changes/fix-software-array-migration @@ -0,0 +1,2 @@ +- Adds a migration to migrate older team configurations to the new version that includes both + installers and App Store apps. \ No newline at end of file diff --git a/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go new file mode 100644 index 0000000000..96c9912287 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go @@ -0,0 +1,59 @@ +package tables + +import ( + "database/sql" + "encoding/json" + "fmt" + "reflect" + + "github.com/jmoiron/sqlx" + "github.com/jmoiron/sqlx/reflectx" +) + +func init() { + MigrationClient.AddMigration(Up_20240802113716, Down_20240802113716) +} + +func Up_20240802113716(tx *sql.Tx) error { + txx := sqlx.Tx{Tx: tx, Mapper: reflectx.NewMapperFunc("db", sqlx.NameMapper)} + + type row struct { + Config json.RawMessage `db:"config"` + ID uint `db:"id"` + } + + var rows []row + if err := txx.Select(&rows, "SELECT config, id FROM teams"); err != nil { + return fmt.Errorf("selecting team configs: %w", err) + } + + for _, r := range rows { + + config := make(map[string]any) + if err := json.Unmarshal(r.Config, &config); err != nil { + return fmt.Errorf("unmarshal team config: %w", err) + } + softwareData := config["software"] + rt := reflect.TypeOf(config["software"]) + if rt.Kind() == reflect.Slice { + // then we have an older config without the new fields + // Note: we are setting the new key to be whatever the old key was (if it was null, then + // it's set to null, if it was empty array, then it's set to empty array) + config["software"] = map[string]any{"packages": softwareData} + b, err := json.Marshal(config) + if err != nil { + return fmt.Errorf("marshal updated team config: %w", err) + } + if _, err := tx.Exec(`UPDATE teams SET config = ? WHERE id = ?`, b, r.ID); err != nil { + return fmt.Errorf("updating config for team %d: %w", r.ID, err) + } + } + + } + + return nil +} + +func Down_20240802113716(tx *sql.Tx) error { + return nil +} diff --git a/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go new file mode 100644 index 0000000000..020c071075 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go @@ -0,0 +1,194 @@ +package tables + +import ( + "testing" + + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/stretchr/testify/require" +) + +func TestUp_20240802113716(t *testing.T) { + db := applyUpToPrev(t) + + badCfg := ` +{ + "mdm": { + "ios_updates": { + "deadline": "", + "minimum_version": "" + }, + "macos_setup": { + "bootstrap_package": "", + "macos_setup_assistant": "", + "enable_end_user_authentication": false, + "enable_release_device_manually": false + }, + "macos_updates": { + "deadline": "", + "minimum_version": "" + }, + "ipados_updates": { + "deadline": "", + "minimum_version": "" + }, + "macos_settings": { + "custom_settings": [] + }, + "windows_updates": { + "deadline_days": null, + "grace_period_days": null + }, + "windows_settings": { + "custom_settings": [] + }, + "enable_disk_encryption": false + }, + "scripts": [], + "features": { + "enable_host_users": true, + "enable_software_inventory": true + }, + "software": [ + { + "url": "http://localhost:8100/1Password.pkg", + "self_service": true, + "install_script": { + "path": "" + }, + "pre_install_query": { + "path": "" + }, + "post_install_script": { + "path": "" + } + } + ], + "integrations": { + "jira": null, + "zendesk": null, + "google_calendar": { + "webhook_url": "", + "enable_calendar_events": false + } + }, + "webhook_settings": { + "host_status_webhook": { + "days_count": 0, + "destination_url": "", + "host_percentage": 0, + "enable_host_status_webhook": false + }, + "failing_policies_webhook": { + "policy_ids": null, + "destination_url": "", + "host_batch_size": 0, + "enable_failing_policies_webhook": false + } + }, + "host_expiry_settings": { + "host_expiry_window": 30, + "host_expiry_enabled": true + } +} + +` + + badCfgEmptyArr := ` +{ + "mdm": { + "ios_updates": { + "deadline": "", + "minimum_version": "" + }, + "macos_setup": { + "bootstrap_package": "", + "macos_setup_assistant": "", + "enable_end_user_authentication": false, + "enable_release_device_manually": false + }, + "macos_updates": { + "deadline": "", + "minimum_version": "" + }, + "ipados_updates": { + "deadline": "", + "minimum_version": "" + }, + "macos_settings": { + "custom_settings": [] + }, + "windows_updates": { + "deadline_days": null, + "grace_period_days": null + }, + "windows_settings": { + "custom_settings": [] + }, + "enable_disk_encryption": false + }, + "scripts": [], + "features": { + "enable_host_users": true, + "enable_software_inventory": true + }, + "software": [], + "integrations": { + "jira": null, + "zendesk": null, + "google_calendar": { + "webhook_url": "", + "enable_calendar_events": false + } + }, + "webhook_settings": { + "host_status_webhook": { + "days_count": 0, + "destination_url": "", + "host_percentage": 0, + "enable_host_status_webhook": false + }, + "failing_policies_webhook": { + "policy_ids": null, + "destination_url": "", + "host_batch_size": 0, + "enable_failing_policies_webhook": false + } + }, + "host_expiry_settings": { + "host_expiry_window": 30, + "host_expiry_enabled": true + } +} + +` + tid1 := execNoErrLastID(t, db, `INSERT INTO teams (name, config) VALUES (?,?)`, "team 1", badCfg) + tid2 := execNoErrLastID(t, db, `INSERT INTO teams (name, config) VALUES (?,?)`, "team 2", badCfgEmptyArr) + + // Apply current migration. + applyNext(t, db) + + var team fleet.Team + require.NoError(t, db.Get(&team, "SELECT id, config FROM teams WHERE id = ?", tid1)) + + // Team with a package should see it in the new field + require.NotNil(t, team.Config.Software) + require.True(t, team.Config.Software.Packages.Set) + require.True(t, team.Config.Software.Packages.Valid) + require.Len(t, team.Config.Software.Packages.Value, 1) + + require.False(t, team.Config.Software.AppStoreApps.Set) + require.False(t, team.Config.Software.AppStoreApps.Valid) + require.Len(t, team.Config.Software.AppStoreApps.Value, 0) + + require.NoError(t, db.Get(&team, "SELECT id, config FROM teams WHERE id = ?", tid2)) + + // Team with an empty array originally should have JSON null set for packages + require.NotNil(t, team.Config.Software) + require.True(t, team.Config.Software.Packages.Set) + require.True(t, team.Config.Software.Packages.Valid) + require.Len(t, team.Config.Software.Packages.Value, 0) + + require.False(t, team.Config.Software.AppStoreApps.Set) + require.False(t, team.Config.Software.AppStoreApps.Valid) + require.Len(t, team.Config.Software.AppStoreApps.Value, 0) +} diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index 22ac9295c1..9efa895008 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -970,9 +970,9 @@ CREATE TABLE `migration_status_tables` ( `tstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`) -) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=294 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=295 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'),(292,20240801115359,1,'2020-01-01 01:01:01'),(293,20240802101043,1,'2020-01-01 01:01:01'); +INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'),(292,20240801115359,1,'2020-01-01 01:01:01'),(293,20240802101043,1,'2020-01-01 01:01:01'),(294,20240802113716,1,'2020-01-01 01:01:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `mobile_device_management_solutions` ( From 1517b285ec0e917bbbc433f90e079382a03891d2 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 2 Aug 2024 18:35:23 -0500 Subject: [PATCH 71/88] Docs: Add fleetdm.com/guides link to tutorials-and-guides docs page. (#21026) Related to: https://github.com/fleetdm/confidential/issues/7343 Changes: - Added a fleetdm.com/guides link to the tutorials and guides docs page. --- docs/Get started/tutorials-and-guides.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Get started/tutorials-and-guides.md b/docs/Get started/tutorials-and-guides.md index 0b1584f6a3..612f7c1b23 100644 --- a/docs/Get started/tutorials-and-guides.md +++ b/docs/Get started/tutorials-and-guides.md @@ -67,5 +67,7 @@ A collection of guides to help you get up and running with Fleet. - [Generate process trees with osquery](https://fleetdm.com/guides/generate-process-trees-with-osquery) +See all guides + From 20e9ebf04182e701df2412e2bfc449cb0537114c Mon Sep 17 00:00:00 2001 From: Drew Baker <89049099+Drew-P-drawers@users.noreply.github.com> Date: Fri, 2 Aug 2024 19:51:36 -0400 Subject: [PATCH 72/88] Update README.md (#21000) Updating readme for alignment. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 7e8651a618..3c23f067c3 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,6 @@ Fleet has no ambition to replace all of your other tools. (Though it might repl Fleet plays well with Munki, Chef, Puppet, and Ansible, as well as with security tools like Crowdstrike and SentinelOne. For example, you can use the free version of Fleet to quickly report on what hosts are _actually_ running your EDR agent. -While most folks prefer to use one or the other, Fleet can also coexist peacefully with Rapid7 and other agent-based vulnerability scanners. This can be useful during migrations. - #### Free as in free The free version of Fleet will [always be free](https://fleetdm.com/pricing). Fleet is [independently backed](https://linkedin.com/company/fleetdm) and actively maintained with the help of many amazing [contributors](https://github.com/fleetdm/fleet/graphs/contributors). From 18977f324bcfab7ea1a8a9bcd282183f5d8f41ab Mon Sep 17 00:00:00 2001 From: Jahziel Villasana-Espinoza Date: Mon, 5 Aug 2024 09:23:15 -0400 Subject: [PATCH 73/88] fix: panic during migration (#21031) > Related issue: #21030 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com> --- ...240802113716_UpdateSoftwareGitopsConfig.go | 10 ++- ...2113716_UpdateSoftwareGitopsConfig_test.go | 76 ++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go index 96c9912287..c91e99099e 100644 --- a/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go +++ b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig.go @@ -33,8 +33,16 @@ func Up_20240802113716(tx *sql.Tx) error { if err := json.Unmarshal(r.Config, &config); err != nil { return fmt.Errorf("unmarshal team config: %w", err) } - softwareData := config["software"] + softwareData, ok := config["software"] + if !ok { + continue + } + rt := reflect.TypeOf(config["software"]) + if rt == nil { + continue + } + if rt.Kind() == reflect.Slice { // then we have an older config without the new fields // Note: we are setting the new key to be whatever the old key was (if it was null, then diff --git a/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go index 020c071075..0bd2edcab4 100644 --- a/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go +++ b/server/datastore/mysql/migrations/tables/20240802113716_UpdateSoftwareGitopsConfig_test.go @@ -159,10 +159,78 @@ func TestUp_20240802113716(t *testing.T) { "host_expiry_enabled": true } } - ` + + badCfgNoSoftwareField := ` +{ + "mdm": { + "ios_updates": { + "deadline": "", + "minimum_version": "" + }, + "macos_setup": { + "bootstrap_package": "", + "macos_setup_assistant": "", + "enable_end_user_authentication": false, + "enable_release_device_manually": false + }, + "macos_updates": { + "deadline": "", + "minimum_version": "" + }, + "ipados_updates": { + "deadline": "", + "minimum_version": "" + }, + "macos_settings": { + "custom_settings": [] + }, + "windows_updates": { + "deadline_days": null, + "grace_period_days": null + }, + "windows_settings": { + "custom_settings": [] + }, + "enable_disk_encryption": false + }, + "scripts": [], + "features": { + "enable_host_users": true, + "enable_software_inventory": true + }, + "integrations": { + "jira": null, + "zendesk": null, + "google_calendar": { + "webhook_url": "", + "enable_calendar_events": false + } + }, + "webhook_settings": { + "host_status_webhook": { + "days_count": 0, + "destination_url": "", + "host_percentage": 0, + "enable_host_status_webhook": false + }, + "failing_policies_webhook": { + "policy_ids": null, + "destination_url": "", + "host_batch_size": 0, + "enable_failing_policies_webhook": false + } + }, + "host_expiry_settings": { + "host_expiry_window": 30, + "host_expiry_enabled": true + } +} +` + tid1 := execNoErrLastID(t, db, `INSERT INTO teams (name, config) VALUES (?,?)`, "team 1", badCfg) tid2 := execNoErrLastID(t, db, `INSERT INTO teams (name, config) VALUES (?,?)`, "team 2", badCfgEmptyArr) + tid3 := execNoErrLastID(t, db, `INSERT INTO teams (name, config) VALUES (?,?)`, "team 3", badCfgNoSoftwareField) // Apply current migration. applyNext(t, db) @@ -180,6 +248,7 @@ func TestUp_20240802113716(t *testing.T) { require.False(t, team.Config.Software.AppStoreApps.Valid) require.Len(t, team.Config.Software.AppStoreApps.Value, 0) + team = fleet.Team{} require.NoError(t, db.Get(&team, "SELECT id, config FROM teams WHERE id = ?", tid2)) // Team with an empty array originally should have JSON null set for packages @@ -191,4 +260,9 @@ func TestUp_20240802113716(t *testing.T) { require.False(t, team.Config.Software.AppStoreApps.Set) require.False(t, team.Config.Software.AppStoreApps.Valid) require.Len(t, team.Config.Software.AppStoreApps.Value, 0) + + team = fleet.Team{} + require.NoError(t, db.Get(&team, "SELECT id, config FROM teams WHERE id = ?", tid3)) + + require.Nil(t, team.Config.Software) } From f836722fb4164f9d9047c6f1d99f26b93750c6d8 Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Mon, 5 Aug 2024 11:53:15 -0400 Subject: [PATCH 74/88] Initial implementation of decrypt tool (#21044) --- tools/mdm/decrypt-disk-encryption-key/main.go | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tools/mdm/decrypt-disk-encryption-key/main.go diff --git a/tools/mdm/decrypt-disk-encryption-key/main.go b/tools/mdm/decrypt-disk-encryption-key/main.go new file mode 100644 index 0000000000..22bf6ef714 --- /dev/null +++ b/tools/mdm/decrypt-disk-encryption-key/main.go @@ -0,0 +1,56 @@ +// Command decrypt-disk-encryption-key decrypts a base64-encoded encrypted key +// using the provided X509 certificate and private key. This is typically used +// to manually decrypt a disk encryption key, e.g. BitLocker on Windows or +// FileVault on macOS. The certificate and private key used are the SCEP files +// for a macOS host and the WSTEP files for a Windows host. +// +// Example usage (running from the root of this repository): +// +// go run ./tools/mdm/decrypt-disk-encryption-key/main.go -cert path/to/file.crt \ +// -key path/to/file.key -value-to-decrypt base64-encoded-value +package main + +import ( + "errors" + "flag" + "fmt" + + "github.com/apex/log" + "github.com/fleetdm/fleet/v4/server/config" + "github.com/fleetdm/fleet/v4/server/mdm" +) + +func main() { + var ( + certFile = flag.String("cert", "", "The path to the X509 certificate file (required).") + keyFile = flag.String("key", "", "The path to the X509 private key file (required).") + valueToDecrypt = flag.String("value-to-decrypt", "", "The base64-encoded value to decrypt (required).") + ) + flag.Parse() + + if *certFile == "" || *keyFile == "" || *valueToDecrypt == "" { + flag.Usage() + return + } + + cfg := config.MDMConfig{ + WindowsWSTEPIdentityCert: *certFile, + WindowsWSTEPIdentityKey: *keyFile, + } + cert, _, _, err := cfg.MicrosoftWSTEP() + if err != nil { + // unwrap the error once to remove "Microsoft WSTEP" from the error + // message, as we don't know in this tool if the cert is for WSTEP or SCEP + // (it doesn't matter) + if uerr := errors.Unwrap(err); uerr != nil { + err = uerr + } + log.Fatalf("Error loading certificate: %v", err) + } + + decrypted, err := mdm.DecryptBase64CMS(*valueToDecrypt, cert.Leaf, cert.PrivateKey) + if err != nil { + log.Fatalf("Error decrypting value: %v", err) + } + fmt.Printf("Decrypted value: %s\n", string(decrypted)) +} From 8362c328a1b010c7fcd8f1f4ff10ec7e0b703ddb Mon Sep 17 00:00:00 2001 From: Ian Littman Date: Mon, 5 Aug 2024 11:23:26 -0500 Subject: [PATCH 75/88] Fix grammar on load balancer documentation in deploy docs (#21032) Checklist deleted as items are irrlevant for docs updates. --- docs/Deploy/Reference-Architectures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Deploy/Reference-Architectures.md b/docs/Deploy/Reference-Architectures.md index 06a7d8dd5a..630b8561b5 100644 --- a/docs/Deploy/Reference-Architectures.md +++ b/docs/Deploy/Reference-Architectures.md @@ -150,7 +150,7 @@ In some cases adding a read replica can increase database performance for specif #### Traffic load balancing Load balancing enables distributing request traffic over many instances of the backend application. Using AWS Application -Load Balancer can also [offload SSL termination](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html), freeing Fleet to spend the majority of it's allocated compute dedicated +Load Balancer can also [offload SSL termination](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html), freeing Fleet to spend the majority of its allocated compute dedicated to its core functionality. More details about ALB can be found [here](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html). _**Note if using [terraform reference architecture](https://github.com/fleetdm/fleet/tree/main/infrastructure/dogfood/terraform/aws#terraform) all configurations can dynamically scale based on load(cpu/memory) and all configurations From 40b0349d132ef72ba0acb2fc45dc873efeff7967 Mon Sep 17 00:00:00 2001 From: Victor Lyuboslavsky Date: Mon, 5 Aug 2024 18:44:30 +0200 Subject: [PATCH 76/88] Fixed issue where callback was clearing event body tag. (#20997) #20994 unreleased bug -- callback was clearing event body tag # Checklist for submitter - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --- ee/server/calendar/google_calendar.go | 27 ++++++++------- ee/server/service/calendar.go | 4 ++- server/cron/calendar_cron.go | 9 ++--- server/fleet/calendar.go | 4 +-- server/fleet/calendar_events.go | 12 +++++-- server/fleet/calendar_events_test.go | 8 ++--- server/service/integration_enterprise_test.go | 34 +++++++++++++++++++ 7 files changed, 72 insertions(+), 26 deletions(-) diff --git a/ee/server/calendar/google_calendar.go b/ee/server/calendar/google_calendar.go index 73c47d5cde..39c31d4807 100644 --- a/ee/server/calendar/google_calendar.go +++ b/ee/server/calendar/google_calendar.go @@ -298,30 +298,30 @@ func (c *GoogleCalendar) Configure(userEmail string) error { } func (c *GoogleCalendar) UpdateEventBody(event *fleet.CalendarEvent, - genBodyFn fleet.CalendarGenBodyFn) error { + genBodyFn fleet.CalendarGenBodyFn) (string, error) { details, err := c.unmarshalDetails(event) if err != nil { - return err + return "", err } gEvent, err := c.config.API.GetEvent(details.ID, "") if err != nil { - return ctxerr.Wrap(c.config.Context, err, "retrieving Google calendar event") + return "", ctxerr.Wrap(c.config.Context, err, "retrieving Google calendar event") } // Check if the current description contains the conflict text conflict := strings.Contains(gEvent.Description, fleet.CalendarEventConflictText) var ok bool gEvent.Description, ok, err = genBodyFn(conflict) if err != nil { - return ctxerr.Wrap(c.config.Context, err, "generating calendar event body") + return "", ctxerr.Wrap(c.config.Context, err, "generating calendar event body") } if !ok { - return nil + return "", nil } - _, err = c.config.API.UpdateEvent(gEvent) + updatedEvent, err := c.config.API.UpdateEvent(gEvent) if err != nil { - return ctxerr.Wrap(c.config.Context, err, "updating Google calendar event") + return "", ctxerr.Wrap(c.config.Context, err, "updating Google calendar event") } - return nil + return updatedEvent.Etag, nil } func (c *GoogleCalendar) GetAndUpdateEvent(event *fleet.CalendarEvent, genBodyFn fleet.CalendarGenBodyFn, @@ -441,7 +441,8 @@ func (c *GoogleCalendar) GetAndUpdateEvent(event *fleet.CalendarEvent, genBodyFn if err != nil { return nil, false, err } - fleetEvent, err := c.googleEventToFleetEvent(*startTime, *endTime, gEvent, event.UUID, details.ChannelID, details.ResourceID) + fleetEvent, err := c.googleEventToFleetEvent(*startTime, *endTime, gEvent, event.UUID, details.ChannelID, details.ResourceID, + details.BodyTag) if err != nil { return nil, false, err } @@ -674,8 +675,8 @@ func (c *GoogleCalendar) createEvent( resourceID = opts.ResourceID } - // Convert Google event to Fleet event - fleetEvent, err := c.googleEventToFleetEvent(eventStart, eventEnd, event, eventUUID, channelID, resourceID) + // Convert Google event to Fleet event. Body tag will be updated by the calling function. + fleetEvent, err := c.googleEventToFleetEvent(eventStart, eventEnd, event, eventUUID, channelID, resourceID, "body_tag") if err != nil { return nil, err } @@ -726,8 +727,7 @@ func getLocation(tz string, config *GoogleCalendarConfig) *time.Location { } func (c *GoogleCalendar) googleEventToFleetEvent(startTime time.Time, endTime time.Time, event *calendar.Event, eventUUID string, - channelID string, - resourceID string) ( + channelID string, resourceID string, bodyTag string) ( *fleet.CalendarEvent, error, ) { tzName := c.location.String() @@ -742,6 +742,7 @@ func (c *GoogleCalendar) googleEventToFleetEvent(startTime time.Time, endTime ti ETag: event.Etag, ChannelID: channelID, ResourceID: resourceID, + BodyTag: bodyTag, } detailsJson, err := json.Marshal(details) if err != nil { diff --git a/ee/server/service/calendar.go b/ee/server/service/calendar.go index 4f5f971b56..75886f1053 100644 --- a/ee/server/service/calendar.go +++ b/ee/server/service/calendar.go @@ -235,7 +235,9 @@ func (svc *Service) processCalendarEvent(ctx context.Context, eventDetails *flee return ctxerr.Wrap(ctx, err, "set recent update flag") } // Event was updated, so we need to save it - err = event.SaveBodyTag(generatedTag) + if generatedTag != "" { + err = event.SaveDataItems("body_tag", generatedTag) + } if err != nil { return ctxerr.Wrap(ctx, err, "save calendar event body tag") } diff --git a/server/cron/calendar_cron.go b/server/cron/calendar_cron.go index 4e717a84b6..ed943caa52 100644 --- a/server/cron/calendar_cron.go +++ b/server/cron/calendar_cron.go @@ -396,6 +396,7 @@ func processFailingHostExistingCalendarEvent( // Function to generate calendar event body. var generatedTag string + var newETag string var genBodyFn fleet.CalendarGenBodyFn = func(conflict bool) (string, bool, error) { var body string body, generatedTag = calendar.GenerateCalendarEventBody(ctx, ds, orgName, host, policyIDtoPolicy, conflict, logger) @@ -409,7 +410,7 @@ func processFailingHostExistingCalendarEvent( updatedBodyTag := getBodyTag(ctx, ds, host, policyIDtoPolicy, logger) if currentBodyTag != updatedBodyTag && updatedBodyTag != "" { - err = userCalendar.UpdateEventBody(calendarEvent, genBodyFn) + newETag, err = userCalendar.UpdateEventBody(calendarEvent, genBodyFn) if err != nil { return fmt.Errorf("update event body: %w", err) } @@ -440,8 +441,8 @@ func processFailingHostExistingCalendarEvent( } if updated { - if generatedTag != "" { - err = updatedEvent.SaveBodyTag(generatedTag) + if generatedTag != "" && newETag != "" { + err = updatedEvent.SaveDataItems("body_tag", generatedTag, "etag", newETag) if err != nil { return fmt.Errorf("save calendar event body tag: %w", err) } @@ -623,7 +624,7 @@ func attemptCreatingEventOnUserCalendar( var dee fleet.DayEndedError switch { case err == nil: - err = calendarEvent.SaveBodyTag(generatedTag) + err = calendarEvent.SaveDataItems("body_tag", generatedTag) if err != nil { return nil, err } diff --git a/server/fleet/calendar.go b/server/fleet/calendar.go index 72c3e9e0ba..fa9de8f07a 100644 --- a/server/fleet/calendar.go +++ b/server/fleet/calendar.go @@ -42,8 +42,8 @@ type UserCalendar interface { GetAndUpdateEvent(event *CalendarEvent, genBodyFn CalendarGenBodyFn, opts CalendarGetAndUpdateEventOpts) (updatedEvent *CalendarEvent, updated bool, err error) - // UpdateEventBody updates the body of the calendar event. - UpdateEventBody(event *CalendarEvent, genBodyFn CalendarGenBodyFn) error + // UpdateEventBody updates the body of the calendar event and returns new ETag + UpdateEventBody(event *CalendarEvent, genBodyFn CalendarGenBodyFn) (string, error) // DeleteEvent deletes the event with the given ID. DeleteEvent(event *CalendarEvent) error // StopEventChannel stops the event's callback channel. diff --git a/server/fleet/calendar_events.go b/server/fleet/calendar_events.go index 44d11306fc..5e730e283b 100644 --- a/server/fleet/calendar_events.go +++ b/server/fleet/calendar_events.go @@ -2,6 +2,7 @@ package fleet import ( "encoding/json" + "errors" "fmt" "time" ) @@ -30,7 +31,10 @@ func (ce *CalendarEvent) GetBodyTag() string { return d.BodyTag } -func (ce *CalendarEvent) SaveBodyTag(bodyTag string) error { +func (ce *CalendarEvent) SaveDataItems(keysAndValues ...string) error { + if len(keysAndValues)%2 != 0 { + return errors.New("SaveDataItem requires an even number of arguments") + } var result map[string]any if len(ce.Data) > 0 { err := json.Unmarshal(ce.Data, &result) @@ -40,7 +44,11 @@ func (ce *CalendarEvent) SaveBodyTag(bodyTag string) error { } else { result = make(map[string]any, 1) } - result["body_tag"] = bodyTag + for i := 0; i < len(keysAndValues); i += 2 { + key := keysAndValues[i] + value := keysAndValues[i+1] + result[key] = value + } data, err := json.Marshal(result) if err != nil { return fmt.Errorf("could not marshal event data: %w", err) diff --git a/server/fleet/calendar_events_test.go b/server/fleet/calendar_events_test.go index 3e79bd6bb4..931cd3889f 100644 --- a/server/fleet/calendar_events_test.go +++ b/server/fleet/calendar_events_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestBodyTag(t *testing.T) { +func TestSaveDataItems(t *testing.T) { t.Parallel() var event CalendarEvent @@ -16,7 +16,7 @@ func TestBodyTag(t *testing.T) { assert.Equal(t, "", event.GetBodyTag()) bodyTag := "bodyTag" - require.NoError(t, event.SaveBodyTag(bodyTag)) + require.NoError(t, event.SaveDataItems("body_tag", bodyTag)) assert.Equal(t, bodyTag, event.GetBodyTag()) testMap := make(map[string]any, 5) @@ -29,11 +29,11 @@ func TestBodyTag(t *testing.T) { event.Data = data assert.Equal(t, oldBodyTag, event.GetBodyTag()) - require.NoError(t, event.SaveBodyTag(bodyTag)) + require.NoError(t, event.SaveDataItems("body_tag", bodyTag)) assert.Equal(t, bodyTag, event.GetBodyTag()) // Make sure data was not modified - require.NoError(t, event.SaveBodyTag(oldBodyTag)) + require.NoError(t, event.SaveDataItems("body_tag", oldBodyTag)) var result map[string]any require.NoError(t, json.Unmarshal(event.Data, &result)) assert.Equal(t, testMap, result) diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index f87d9b144a..438138dc67 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -11728,11 +11728,15 @@ func (s *integrationEnterpriseTestSuite) TestCalendarCallback() { require.NotZero(t, event.StartTime) require.NotZero(t, event.EndTime) require.NotEmpty(t, event.UUID) + bodyTag := event.GetBodyTag() + assert.NotEmpty(t, bodyTag) assert.Equal(t, 1, calendar.MockChannelsCount()) // Get channel ID type eventDetails struct { ChannelID string `json:"channel_id"` + BodyTag string `json:"body_tag"` + ETag string `json:"etag"` } var details eventDetails err = json.Unmarshal(event.Data, &details) @@ -11855,6 +11859,8 @@ func (s *integrationEnterpriseTestSuite) TestCalendarCallback() { err = json.Unmarshal(eventRecreated.Data, &details) require.NoError(t, err) + assert.NotEmpty(t, details.BodyTag) + bodyTag = details.BodyTag // New event callback should work _ = s.DoRawWithHeaders("POST", "/api/v1/fleet/calendar/webhook/"+eventRecreated.UUID, []byte(""), http.StatusOK, @@ -11891,6 +11897,30 @@ func (s *integrationEnterpriseTestSuite) TestCalendarCallback() { assert.Greater(t, eventUpdated.StartTime, eventRecreated.StartTime) assert.Equal(t, eventRecreated.EndTime, eventUpdated.EndTime) assert.Equal(t, 1, calendar.MockChannelsCount()) + assert.Equal(t, bodyTag, eventRecreated.GetBodyTag()) + + // Change the body contents of event. + events = calendar.ListGoogleMockEvents() + require.Len(t, events, 1) + eTag := "description change etag" + for _, e := range events { + e.Etag = eTag + e.Description = "new description" + } + // New event callback should cause Etag to update but Body tag to remain the same + _ = s.DoRawWithHeaders("POST", "/api/v1/fleet/calendar/webhook/"+eventRecreated.UUID, []byte(""), http.StatusOK, + map[string]string{ + "X-Goog-Channel-Id": details.ChannelID, + "X-Goog-Resource-State": "exists", + }) + team1CalendarEvents, err = s.ds.ListCalendarEvents(ctx, &team1.ID) + require.NoError(t, err) + require.Len(t, team1CalendarEvents, 1) + eventDescUpdated := team1CalendarEvents[0] + err = json.Unmarshal(eventDescUpdated.Data, &details) + require.NoError(t, err) + assert.Equal(t, bodyTag, details.BodyTag) + assert.Equal(t, eTag, details.ETag) // Update the time of the event again events = calendar.ListGoogleMockEvents() @@ -11900,6 +11930,7 @@ func (s *integrationEnterpriseTestSuite) TestCalendarCallback() { require.NoError(t, err) newStartTime := st.Add(5 * time.Minute).Format(time.RFC3339) e.Start.DateTime = newStartTime + e.Etag = e.Etag + "1" } // Grab the lock @@ -11950,6 +11981,9 @@ func (s *integrationEnterpriseTestSuite) TestCalendarCallback() { require.NoError(t, err) if len(team1CalendarEvents) == 1 && team1CalendarEvents[0].UUID == event.UUID && team1CalendarEvents[0].StartTime.After(event.StartTime) { + err = json.Unmarshal(team1CalendarEvents[0].Data, &details) + require.NoError(t, err) + assert.NotEqual(t, eTag, details.ETag, "ETag should have updated") done <- struct{}{} return } From 7f95ae46a35e99228ee4457f1735584406f97a53 Mon Sep 17 00:00:00 2001 From: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:30:57 -0500 Subject: [PATCH 77/88] Update content of "Turn on MDM" banner in UI (#21046) --- changes/20882-ui-update-turn-on-mdm-banner | 1 + .../components/DeviceUserBanners/DeviceUserBanners.tsx | 5 +++-- .../components/HostDetailsBanners/HostDetailsBanners.tsx | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 changes/20882-ui-update-turn-on-mdm-banner diff --git a/changes/20882-ui-update-turn-on-mdm-banner b/changes/20882-ui-update-turn-on-mdm-banner new file mode 100644 index 0000000000..eca36625ce --- /dev/null +++ b/changes/20882-ui-update-turn-on-mdm-banner @@ -0,0 +1 @@ +- Updated text for "Turn on MDM" banners in UI. \ No newline at end of file diff --git a/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx b/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx index 028165648f..286101a026 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/components/DeviceUserBanners/DeviceUserBanners.tsx @@ -51,8 +51,9 @@ const DeviceUserBanners = ({ return ( Mobile device management (MDM) is off. MDM allows your organization to - change settings and install software. This lets your organization keep - your device up to date so you don't have to. + enforce settings, OS updates, disk encryption, and more. This lets + your organization keep your device up to date so you don't have + to. ); } diff --git a/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx b/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx index 2a35d4a418..fbd7e94c24 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/components/HostDetailsBanners/HostDetailsBanners.tsx @@ -73,9 +73,9 @@ const HostDetailsBanners = ({
    {showTurnOnMdmInfoBanner && ( - To change settings and install software, ask the end user to follow - the Turn on MDM instructions on their{" "} - My device page. + To enforce settings, OS updates, disk encryption, and more, ask the + end user to follow the Turn on MDM instructions on + their My device page. )} {showDiskEncryptionUserActionRequired && ( From a6a9a2e1c26cbea6ecdb40e9501045b5a8d58d05 Mon Sep 17 00:00:00 2001 From: Tim Lee Date: Mon, 5 Aug 2024 11:39:10 -0600 Subject: [PATCH 78/88] no team software gitops (#20847) #20464 Adding gitops support for a top level `software` key to be used to manage installable software into "no team". - [ ] 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 --------- Co-authored-by: Victor Lyuboslavsky --- cmd/fleetctl/apply.go | 2 +- cmd/fleetctl/gitops.go | 2 +- .../gitops_enterprise_integration_test.go | 2 +- cmd/fleetctl/gitops_test.go | 47 +++- cmd/fleetctl/preview.go | 2 +- .../gitops/global_config_no_paths.yml | 1 + ...macos_custom_settings_valid_deprecated.yml | 1 + ...al_macos_windows_custom_settings_valid.yml | 1 + ...dows_custom_settings_invalid_label_mix.yml | 1 + ..._windows_custom_settings_unknown_label.yml | 1 + ...m_software_installer_install_not_found.yml | 19 ++ ...e_installer_invalid_self_service_value.yml | 18 ++ .../no_team_software_installer_no_url.yml | 22 ++ .../no_team_software_installer_not_found.yml | 17 ++ ...tware_installer_post_install_not_found.yml | 21 ++ ...staller_pre_condition_multiple_queries.yml | 23 ++ ...ware_installer_pre_condition_not_found.yml | 21 ++ .../no_team_software_installer_too_large.yml | 17 ++ ...no_team_software_installer_unsupported.yml | 17 ++ .../no_team_software_installer_valid.yml | 25 ++ docs/Contributing/API-for-contributors.md | 4 +- ee/server/service/software_installers.go | 27 +-- ee/server/service/teams.go | 2 +- pkg/spec/gitops.go | 24 +- pkg/spec/gitops_test.go | 16 +- pkg/spec/spec.go | 1 + server/fleet/software_installer.go | 14 ++ server/fleet/teams.go | 17 +- server/service/client.go | 224 +++++++++++------- server/service/client_software.go | 11 + server/service/integration_enterprise_test.go | 41 +++- server/service/software_installers.go | 2 +- 32 files changed, 492 insertions(+), 151 deletions(-) create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_install_not_found.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_invalid_self_service_value.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_no_url.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_not_found.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_post_install_not_found.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_multiple_queries.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_not_found.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_too_large.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_unsupported.yml create mode 100644 cmd/fleetctl/testdata/gitops/no_team_software_installer_valid.yml diff --git a/cmd/fleetctl/apply.go b/cmd/fleetctl/apply.go index 751c74709f..a84ade90f0 100644 --- a/cmd/fleetctl/apply.go +++ b/cmd/fleetctl/apply.go @@ -90,7 +90,7 @@ func applyCommand() *cli.Command { opts.TeamForPolicies = policiesTeamName } baseDir := filepath.Dir(flFilename) - _, err = fleetClient.ApplyGroup(c.Context, specs, baseDir, logf, opts) + _, err = fleetClient.ApplyGroup(c.Context, specs, baseDir, logf, nil, opts) if err != nil { return err } diff --git a/cmd/fleetctl/gitops.go b/cmd/fleetctl/gitops.go index c56016eca3..6f13fd29e9 100644 --- a/cmd/fleetctl/gitops.go +++ b/cmd/fleetctl/gitops.go @@ -90,7 +90,7 @@ func gitopsCommand() *cli.Command { secrets := make(map[string]struct{}) for _, flFilename := range flFilenames.Value() { baseDir := filepath.Dir(flFilename) - config, err := spec.GitOpsFromFile(flFilename, baseDir) + config, err := spec.GitOpsFromFile(flFilename, baseDir, appConfig) if err != nil { return err } diff --git a/cmd/fleetctl/gitops_enterprise_integration_test.go b/cmd/fleetctl/gitops_enterprise_integration_test.go index ab3f8bf835..7089ef6893 100644 --- a/cmd/fleetctl/gitops_enterprise_integration_test.go +++ b/cmd/fleetctl/gitops_enterprise_integration_test.go @@ -176,6 +176,7 @@ contexts: fmt.Sprintf( ` controls: +software: queries: policies: agent_options: @@ -230,5 +231,4 @@ team_settings: for _, fileName := range teamFileNames { _ = runAppForTest(t, []string{"gitops", "--config", fleetctlConfig.Name(), "-f", fileName}) } - } diff --git a/cmd/fleetctl/gitops_test.go b/cmd/fleetctl/gitops_test.go index 826dd43374..22bd28845a 100644 --- a/cmd/fleetctl/gitops_test.go +++ b/cmd/fleetctl/gitops_test.go @@ -36,7 +36,7 @@ const ( orgName = "GitOps Test" ) -func TestFilenameValidation(t *testing.T) { +func TestFilenameGitOpsValidation(t *testing.T) { filename := strings.Repeat("a", filenameMaxLength+1) _, err := runAppNoChecks([]string{"gitops", "-f", filename}) assert.ErrorContains(t, err, "file name must be less than") @@ -207,6 +207,9 @@ func TestBasicGlobalPremiumGitOps(t *testing.T) { ds.NewJobFunc = func(ctx context.Context, job *fleet.Job) (*fleet.Job, error) { return &fleet.Job{}, nil } + ds.BatchSetSoftwareInstallersFunc = func(ctx context.Context, teamID *uint, installers []*fleet.UploadSoftwareInstallerPayload) error { + return nil + } tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml") require.NoError(t, err) @@ -238,6 +241,7 @@ org_settings: org_logo_url_light_background: "" org_name: ${ORG_NAME} secrets: +software: `, ) require.NoError(t, err) @@ -381,6 +385,7 @@ agent_options: name: ${TEST_TEAM_NAME} team_settings: secrets: ${TEST_SECRET} +software: `, ) require.NoError(t, err) @@ -538,6 +543,7 @@ func TestFullGlobalGitOps(t *testing.T) { t.Setenv("FLEET_SERVER_URL", fleetServerURL) t.Setenv("ORG_NAME", orgName) t.Setenv("APPLE_BM_DEFAULT_TEAM", teamName) + t.Setenv("SOFTWARE_INSTALLER_URL", fleetServerURL) file := "./testdata/gitops/global_config_no_paths.yml" // Dry run should fail because Apple BM Default Team does not exist and premium license is not set @@ -834,6 +840,7 @@ agent_options: name: ${TEST_TEAM_NAME} team_settings: secrets: [{"secret":"${TEST_SECRET}"}] +software: `, ) require.NoError(t, err) @@ -1011,6 +1018,7 @@ org_settings: org_logo_url_light_background: "" org_name: ${ORG_NAME} secrets: [{"secret":"globalSecret"}] +software: `, ) require.NoError(t, err) @@ -1030,6 +1038,7 @@ agent_options: name: ${TEST_TEAM_NAME} team_settings: secrets: [{"secret":"${TEST_SECRET}"}] +software: `, ) require.NoError(t, err) @@ -1045,6 +1054,7 @@ agent_options: name: ${TEST_TEAM_NAME} team_settings: secrets: [{"secret":"${TEST_SECRET}"},{"secret":"globalSecret"}] +software: `, ) require.NoError(t, err) @@ -1222,7 +1232,7 @@ func TestTeamSofwareInstallersGitOps(t *testing.T) { {"testdata/gitops/team_software_installer_install_not_found.yml", "no such file or directory"}, {"testdata/gitops/team_software_installer_post_install_not_found.yml", "no such file or directory"}, {"testdata/gitops/team_software_installer_no_url.yml", "software URL is required"}, - {"testdata/gitops/team_software_installer_invalid_self_service_value.yml", "cannot unmarshal string into Go struct field TeamSpecSoftware.packages of type bool"}, + {"testdata/gitops/team_software_installer_invalid_self_service_value.yml", "cannot unmarshal string into Go struct field SoftwareSpec.packages of type bool"}, } for _, c := range cases { t.Run(filepath.Base(c.file), func(t *testing.T) { @@ -1255,6 +1265,39 @@ func TestTeamSoftwareInstallersGitopsQueryEnv(t *testing.T) { require.NoError(t, err) } +func TestNoTeamSoftwareInstallersGitOps(t *testing.T) { + startSoftwareInstallerServer(t) + + cases := []struct { + file string + wantErr string + }{ + {"testdata/gitops/no_team_software_installer_not_found.yml", "Please make sure that URLs are publicy accessible to the internet."}, + {"testdata/gitops/no_team_software_installer_unsupported.yml", "The file should be .pkg, .msi, .exe or .deb."}, + {"testdata/gitops/no_team_software_installer_too_large.yml", "The maximum file size is 500 MB"}, + {"testdata/gitops/no_team_software_installer_valid.yml", ""}, + {"testdata/gitops/no_team_software_installer_pre_condition_multiple_queries.yml", "should have only one query."}, + {"testdata/gitops/no_team_software_installer_pre_condition_not_found.yml", "no such file or directory"}, + {"testdata/gitops/no_team_software_installer_install_not_found.yml", "no such file or directory"}, + {"testdata/gitops/no_team_software_installer_post_install_not_found.yml", "no such file or directory"}, + {"testdata/gitops/no_team_software_installer_no_url.yml", "software URL is required"}, + {"testdata/gitops/no_team_software_installer_invalid_self_service_value.yml", "cannot unmarshal string into Go struct field SoftwareSpec.packages of type bool"}, + } + for _, c := range cases { + t.Run(filepath.Base(c.file), func(t *testing.T) { + setupFullGitOpsPremiumServer(t) + + t.Setenv("APPLE_BM_DEFAULT_TEAM", "") + _, err := runAppNoChecks([]string{"gitops", "-f", c.file}) + if c.wantErr == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, c.wantErr) + } + }) + } +} + func TestTeamVPPAppsGitOps(t *testing.T) { config := &appleVPPConfigSrvConf{ Assets: []vpp.Asset{ diff --git a/cmd/fleetctl/preview.go b/cmd/fleetctl/preview.go index 1aa78695f9..e11dc8bf9e 100644 --- a/cmd/fleetctl/preview.go +++ b/cmd/fleetctl/preview.go @@ -387,7 +387,7 @@ Use the stop and reset subcommands to manage the server and dependencies once st } // this only applies standard queries, the base directory is not used, // so pass in the current working directory. - _, err = client.ApplyGroup(c.Context, specs, ".", logf, fleet.ApplyClientSpecOptions{}) + _, err = client.ApplyGroup(c.Context, specs, ".", logf, nil, fleet.ApplyClientSpecOptions{}) if err != nil { return err } diff --git a/cmd/fleetctl/testdata/gitops/global_config_no_paths.yml b/cmd/fleetctl/testdata/gitops/global_config_no_paths.yml index 76936e3ad5..7d3dfe40f2 100644 --- a/cmd/fleetctl/testdata/gitops/global_config_no_paths.yml +++ b/cmd/fleetctl/testdata/gitops/global_config_no_paths.yml @@ -187,3 +187,4 @@ org_settings: secrets: # These secrets are used to enroll hosts to the "All teams" team - secret: SampleSecret123 - secret: ABC +software: diff --git a/cmd/fleetctl/testdata/gitops/global_macos_custom_settings_valid_deprecated.yml b/cmd/fleetctl/testdata/gitops/global_macos_custom_settings_valid_deprecated.yml index 177c1c80cf..b098442585 100644 --- a/cmd/fleetctl/testdata/gitops/global_macos_custom_settings_valid_deprecated.yml +++ b/cmd/fleetctl/testdata/gitops/global_macos_custom_settings_valid_deprecated.yml @@ -91,3 +91,4 @@ org_settings: databases_path: "" secrets: - secret: ABC +software: \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/global_macos_windows_custom_settings_valid.yml b/cmd/fleetctl/testdata/gitops/global_macos_windows_custom_settings_valid.yml index da75847cd5..e6231bf030 100644 --- a/cmd/fleetctl/testdata/gitops/global_macos_windows_custom_settings_valid.yml +++ b/cmd/fleetctl/testdata/gitops/global_macos_windows_custom_settings_valid.yml @@ -97,3 +97,4 @@ org_settings: databases_path: "" secrets: - secret: ABC +software: diff --git a/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_invalid_label_mix.yml b/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_invalid_label_mix.yml index 9d2ac6e69f..1a100de6f3 100644 --- a/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_invalid_label_mix.yml +++ b/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_invalid_label_mix.yml @@ -93,3 +93,4 @@ org_settings: databases_path: "" secrets: - secret: ABC +software: \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_unknown_label.yml b/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_unknown_label.yml index ba1d06f784..5208ba7248 100644 --- a/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_unknown_label.yml +++ b/cmd/fleetctl/testdata/gitops/global_windows_custom_settings_unknown_label.yml @@ -91,3 +91,4 @@ org_settings: databases_path: "" secrets: - secret: ABC +software: \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_install_not_found.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_install_not_found.yml new file mode 100644 index 0000000000..d3bcada54e --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_install_not_found.yml @@ -0,0 +1,19 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/notfound.sh \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_invalid_self_service_value.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_invalid_self_service_value.yml new file mode 100644 index 0000000000..acee06d683 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_invalid_self_service_value.yml @@ -0,0 +1,18 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/invalidtype.txt + self_service: "not a boolean" \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_no_url.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_no_url.yml new file mode 100644 index 0000000000..6d83a9daed --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_no_url.yml @@ -0,0 +1,22 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - install_script: + path: lib/install_ruby.sh + pre_install_query: + path: lib/query_ruby.yml + post_install_script: + path: lib/post_install_ruby.sh \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_not_found.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_not_found.yml new file mode 100644 index 0000000000..cd7332f91e --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_not_found.yml @@ -0,0 +1,17 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/notfound.deb \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_post_install_not_found.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_post_install_not_found.yml new file mode 100644 index 0000000000..ac0a436360 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_post_install_not_found.yml @@ -0,0 +1,21 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/install_ruby.sh + post_install_script: + path: lib/notfound.sh \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_multiple_queries.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_multiple_queries.yml new file mode 100644 index 0000000000..a2b5419c05 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_multiple_queries.yml @@ -0,0 +1,23 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/install_ruby.sh + pre_install_query: + path: lib/query_multiple.yml + post_install_script: + path: lib/post_install_ruby.sh \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_not_found.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_not_found.yml new file mode 100644 index 0000000000..bafde42691 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_pre_condition_not_found.yml @@ -0,0 +1,21 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/install_ruby.sh + pre_install_query: + path: lib/notfound.yml \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_too_large.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_too_large.yml new file mode 100644 index 0000000000..db4ffd3211 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_too_large.yml @@ -0,0 +1,17 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/toolarge.deb \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_unsupported.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_unsupported.yml new file mode 100644 index 0000000000..2bc609b931 --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_unsupported.yml @@ -0,0 +1,17 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/invalidtype.txt \ No newline at end of file diff --git a/cmd/fleetctl/testdata/gitops/no_team_software_installer_valid.yml b/cmd/fleetctl/testdata/gitops/no_team_software_installer_valid.yml new file mode 100644 index 0000000000..e0fcaa490e --- /dev/null +++ b/cmd/fleetctl/testdata/gitops/no_team_software_installer_valid.yml @@ -0,0 +1,25 @@ +# Test config +controls: +queries: +policies: +agent_options: +org_settings: + server_settings: + server_url: $FLEET_SERVER_URL + org_info: + contact_url: https://example.com/contact + org_logo_url: "" + org_logo_url_light_background: "" + org_name: ${ORG_NAME} + secrets: [{"secret":"globalSecret"}] +software: + packages: + - url: ${SOFTWARE_INSTALLER_URL}/ruby.deb + install_script: + path: lib/install_ruby.sh + pre_install_query: + path: lib/query_ruby.yml + post_install_script: + path: lib/post_install_ruby.sh + - url: ${SOFTWARE_INSTALLER_URL}/other.deb + self_service: true \ No newline at end of file diff --git a/docs/Contributing/API-for-contributors.md b/docs/Contributing/API-for-contributors.md index 0f1f3a2ffb..4699b76d3d 100644 --- a/docs/Contributing/API-for-contributors.md +++ b/docs/Contributing/API-for-contributors.md @@ -2957,8 +2957,8 @@ _Available in Fleet Premium._ | Name | Type | In | Description | | --------- | ------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| team_id | number | query | The ID of the team to add the software package to. Only one team identifier (`team_id` or `team_name`) can be included in the request, omit this parameter if using `team_name`. | -| team_name | string | query | The name of the team to add the software package to. Only one team identifier (`team_id` or `team_name`) can be included in the request, omit this parameter if using `team_id`. | +| team_id | number | query | The ID of the team to add the software package to. Only one team identifier (`team_id` or `team_name`) can be included in the request, omit this parameter if using `team_name`. Ommitting these parameters will add software to 'No Team'. | +| team_name | string | query | The name of the team to add the software package to. Only one team identifier (`team_id` or `team_name`) can be included in the request, omit this parameter if using `team_id`. Ommitting these parameters will add software to 'No Team'. | | dry_run | bool | query | If `true`, will validate the provided software packages and return any validation errors, but will not apply the changes. | | software | list | body | An array of software objects. Each object consists of:`url`- URL to the software package (PKG, MSI, EXE or DEB),`install_script` - command that Fleet runs to install software, `pre_install_query` - condition query that determines if the install will proceed, and `post_install_script` - script that runs after software install. | diff --git a/ee/server/service/software_installers.go b/ee/server/service/software_installers.go index 9871f9fd44..ad0dbe0a81 100644 --- a/ee/server/service/software_installers.go +++ b/ee/server/service/software_installers.go @@ -580,25 +580,24 @@ func (svc *Service) addMetadataToSoftwarePayload(ctx context.Context, payload *f const maxInstallerSizeBytes int64 = 1024 * 1024 * 500 func (svc *Service) BatchSetSoftwareInstallers(ctx context.Context, tmName string, payloads []fleet.SoftwareInstallerPayload, dryRun bool) error { - if tmName == "" { - svc.authz.SkipAuthorization(ctx) // so that the error message is not replaced by "forbidden" - return ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("team_name", "must not be empty")) - } - if err := svc.authz.Authorize(ctx, &fleet.Team{}, fleet.ActionRead); err != nil { return err } - tm, err := svc.ds.TeamByName(ctx, tmName) - if err != nil { - // If this is a dry run, the team may not have been created yet - if dryRun && fleet.IsNotFound(err) { - return nil + var teamID *uint + if tmName != "" { + tm, err := svc.ds.TeamByName(ctx, tmName) + if err != nil { + // If this is a dry run, the team may not have been created yet + if dryRun && fleet.IsNotFound(err) { + return nil + } + return err } - return err + teamID = &tm.ID } - if err := svc.authz.Authorize(ctx, &fleet.SoftwareInstaller{TeamID: &tm.ID}, fleet.ActionWrite); err != nil { + if err := svc.authz.Authorize(ctx, &fleet.SoftwareInstaller{TeamID: teamID}, fleet.ActionWrite); err != nil { return ctxerr.Wrap(ctx, err, "validating authorization") } @@ -672,7 +671,7 @@ func (svc *Service) BatchSetSoftwareInstallers(ctx context.Context, tmName strin } installer := &fleet.UploadSoftwareInstallerPayload{ - TeamID: &tm.ID, + TeamID: teamID, InstallScript: p.InstallScript, PreInstallQuery: p.PreInstallQuery, PostInstallScript: p.PostInstallScript, @@ -732,7 +731,7 @@ func (svc *Service) BatchSetSoftwareInstallers(ctx context.Context, tmName strin } } - if err := svc.ds.BatchSetSoftwareInstallers(ctx, &tm.ID, installers); err != nil { + if err := svc.ds.BatchSetSoftwareInstallers(ctx, teamID, installers); err != nil { return ctxerr.Wrap(ctx, err, "batch set software installers") } diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go index 4b8df03123..3d25abafe9 100644 --- a/ee/server/service/teams.go +++ b/ee/server/service/teams.go @@ -1246,7 +1246,7 @@ func (svc *Service) editTeamFromSpec( if spec.Software != nil { if team.Config.Software == nil { - team.Config.Software = &fleet.TeamSpecSoftware{} + team.Config.Software = &fleet.SoftwareSpec{} } if spec.Software.Packages.Set { diff --git a/pkg/spec/gitops.go b/pkg/spec/gitops.go index b6eea43708..e29e9138dc 100644 --- a/pkg/spec/gitops.go +++ b/pkg/spec/gitops.go @@ -61,12 +61,12 @@ type GitOps struct { } type GitOpsSoftware struct { - Packages []*fleet.TeamSpecSoftwarePackage + Packages []*fleet.SoftwarePackageSpec AppStoreApps []*fleet.TeamSpecAppStoreApp } // GitOpsFromFile parses a GitOps yaml file. -func GitOpsFromFile(filePath, baseDir string) (*GitOps, error) { +func GitOpsFromFile(filePath, baseDir string, appConfig *fleet.EnrichedAppConfig) (*GitOps, error) { b, err := os.ReadFile(filePath) if err != nil { return nil, fmt.Errorf("failed to read file: %s: %w", filePath, err) @@ -96,18 +96,16 @@ func GitOpsFromFile(filePath, baseDir string) (*GitOps, error) { // Figure out if this is an org or team settings file teamRaw, teamOk := top["name"] teamSettingsRaw, teamSettingsOk := top["team_settings"] - teamSoftware, teamSoftwareOk := top["software"] orgSettingsRaw, orgOk := top["org_settings"] if orgOk { - if teamOk || teamSettingsOk || teamSoftwareOk { - multiError = multierror.Append(multiError, errors.New("'org_settings' cannot be used with 'name', 'team_settings' or 'software'")) + if teamOk || teamSettingsOk { + multiError = multierror.Append(multiError, errors.New("'org_settings' cannot be used with 'name', 'team_settings'")) } else { multiError = parseOrgSettings(orgSettingsRaw, result, baseDir, multiError) } } else if teamOk && teamSettingsOk { multiError = parseName(teamRaw, result, multiError) multiError = parseTeamSettings(teamSettingsRaw, result, baseDir, multiError) - multiError = parseSoftware(teamSoftware, result, baseDir, multiError) } else { multiError = multierror.Append(multiError, errors.New("either 'org_settings' or 'name' and 'team_settings' is required")) } @@ -118,6 +116,10 @@ func GitOpsFromFile(filePath, baseDir string) (*GitOps, error) { multiError = parsePolicies(top, result, baseDir, multiError) multiError = parseQueries(top, result, baseDir, multiError) + if appConfig != nil && appConfig.License.IsPremium() { + multiError = parseSoftware(top, result, baseDir, multiError) + } + return result, multiError.ErrorOrNil() } @@ -523,11 +525,15 @@ func parseQueries(top map[string]json.RawMessage, result *GitOps, baseDir string return multiError } -func parseSoftware(softwareRaw json.RawMessage, result *GitOps, baseDir string, multiError *multierror.Error) *multierror.Error { - var software fleet.TeamSpecSoftware +func parseSoftware(top map[string]json.RawMessage, result *GitOps, baseDir string, multiError *multierror.Error) *multierror.Error { + softwareRaw, ok := top["software"] + if !ok { + return multierror.Append(multiError, errors.New("'software' is required")) + } + var software fleet.SoftwareSpec if len(softwareRaw) > 0 { if err := json.Unmarshal(softwareRaw, &software); err != nil { - return multierror.Append(multiError, fmt.Errorf("failed to unmarshall software: %v", err)) + return multierror.Append(multiError, fmt.Errorf("failed to unmarshall softwarespec: %v", err)) } } if software.AppStoreApps.Set { diff --git a/pkg/spec/gitops_test.go b/pkg/spec/gitops_test.go index 644c3e453e..58e12553b9 100644 --- a/pkg/spec/gitops_test.go +++ b/pkg/spec/gitops_test.go @@ -53,7 +53,7 @@ func createTempFile(t *testing.T, pattern, contents string) (filePath string, ba func gitOpsFromString(t *testing.T, s string) (*GitOps, error) { path, basePath := createTempFile(t, "", s) - return GitOpsFromFile(path, basePath) + return GitOpsFromFile(path, basePath, nil) } func TestValidGitOpsYaml(t *testing.T) { @@ -108,7 +108,7 @@ func TestValidGitOpsYaml(t *testing.T) { t.Parallel() } - gitops, err := GitOpsFromFile(test.filePath, "./testdata") + gitops, err := GitOpsFromFile(test.filePath, "./testdata", nil) require.NoError(t, err) if test.isTeam { @@ -336,20 +336,20 @@ func TestMixingGlobalAndTeamConfig(t *testing.T) { config := getGlobalConfig(nil) config += "name: TeamName\n" _, err := gitOpsFromString(t, config) - assert.ErrorContains(t, err, "'org_settings' cannot be used with 'name', 'team_settings' or 'software'") + assert.ErrorContains(t, err, "'org_settings' cannot be used with 'name', 'team_settings'") // Mixing org_settings and team_settings config = getGlobalConfig(nil) config += "team_settings:\n secrets: []\n" _, err = gitOpsFromString(t, config) - assert.ErrorContains(t, err, "'org_settings' cannot be used with 'name', 'team_settings' or 'software'") + assert.ErrorContains(t, err, "'org_settings' cannot be used with 'name', 'team_settings'") // Mixing org_settings and team name and team_settings config = getGlobalConfig(nil) config += "name: TeamName\n" config += "team_settings:\n secrets: []\n" _, err = gitOpsFromString(t, config) - assert.ErrorContains(t, err, "'org_settings' cannot be used with 'name', 'team_settings' or 'software'") + assert.ErrorContains(t, err, "'org_settings' cannot be used with 'name', 'team_settings'") } func TestInvalidGitOpsYaml(t *testing.T) { @@ -696,7 +696,7 @@ func TestGitOpsPaths(t *testing.T) { err = os.WriteFile(mainTmpFile.Name(), []byte(config), 0o644) require.NoError(t, err) - _, err = GitOpsFromFile(mainTmpFile.Name(), dir) + _, err = GitOpsFromFile(mainTmpFile.Name(), dir, nil) assert.NoError(t, err) // Test a bad path @@ -709,7 +709,7 @@ func TestGitOpsPaths(t *testing.T) { err = os.WriteFile(mainTmpFile.Name(), []byte(config), 0o644) require.NoError(t, err) - _, err = GitOpsFromFile(mainTmpFile.Name(), dir) + _, err = GitOpsFromFile(mainTmpFile.Name(), dir, nil) assert.ErrorContains(t, err, "no such file or directory") // Test a bad file -- cannot be unmarshalled @@ -744,7 +744,7 @@ func TestGitOpsPaths(t *testing.T) { } err = os.WriteFile(mainTmpFile.Name(), []byte(config), 0o644) require.NoError(t, err) - _, err = GitOpsFromFile(mainTmpFile.Name(), dir) + _, err = GitOpsFromFile(mainTmpFile.Name(), dir, nil) assert.ErrorContains(t, err, "nested paths are not supported") }, ) diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index d760f8b1d3..10bafd76da 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -26,6 +26,7 @@ type Group struct { Packs []*fleet.PackSpec Labels []*fleet.LabelSpec Policies []*fleet.PolicySpec + Software []*fleet.SoftwarePackageSpec // This needs to be interface{} to allow for the patch logic. Otherwise we send a request that looks to the // server like the user explicitly set the zero values. AppConfig interface{} diff --git a/server/fleet/software_installer.go b/server/fleet/software_installer.go index d542840989..70a8f2ca36 100644 --- a/server/fleet/software_installer.go +++ b/server/fleet/software_installer.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/fleetdm/fleet/v4/pkg/optjson" "github.com/fleetdm/fleet/v4/server/ptr" ) @@ -334,6 +335,19 @@ type SoftwarePackageOrApp struct { LastInstall *HostSoftwareInstall `json:"last_install"` } +type SoftwarePackageSpec struct { + URL string `json:"url"` + SelfService bool `json:"self_service"` + PreInstallQuery TeamSpecSoftwareAsset `json:"pre_install_query"` + InstallScript TeamSpecSoftwareAsset `json:"install_script"` + PostInstallScript TeamSpecSoftwareAsset `json:"post_install_script"` +} + +type SoftwareSpec struct { + Packages optjson.Slice[SoftwarePackageSpec] `json:"packages,omitempty"` + AppStoreApps optjson.Slice[TeamSpecAppStoreApp] `json:"app_store_apps,omitempty"` +} + // HostSoftwareInstall represents installation of software on a host from a // Fleet software installer. type HostSoftwareInstall struct { diff --git a/server/fleet/teams.go b/server/fleet/teams.go index d5eaa71f8b..fa9734f6c1 100644 --- a/server/fleet/teams.go +++ b/server/fleet/teams.go @@ -155,7 +155,7 @@ type TeamConfig struct { Features Features `json:"features"` MDM TeamMDM `json:"mdm"` Scripts optjson.Slice[string] `json:"scripts,omitempty"` - Software *TeamSpecSoftware `json:"software,omitempty"` + Software *SoftwareSpec `json:"software,omitempty"` } type TeamWebhookSettings struct { @@ -168,23 +168,10 @@ type TeamSpecSoftwareAsset struct { Path string `json:"path"` } -type TeamSpecSoftware struct { - Packages optjson.Slice[TeamSpecSoftwarePackage] `json:"packages,omitempty"` - AppStoreApps optjson.Slice[TeamSpecAppStoreApp] `json:"app_store_apps,omitempty"` -} - type TeamSpecAppStoreApp struct { AppStoreID string `json:"app_store_id"` } -type TeamSpecSoftwarePackage struct { - URL string `json:"url"` - SelfService bool `json:"self_service"` - PreInstallQuery TeamSpecSoftwareAsset `json:"pre_install_query"` - InstallScript TeamSpecSoftwareAsset `json:"install_script"` - PostInstallScript TeamSpecSoftwareAsset `json:"post_install_script"` -} - type TeamMDM struct { EnableDiskEncryption bool `json:"enable_disk_encryption"` MacOSUpdates AppleOSUpdateSettings `json:"macos_updates"` @@ -450,7 +437,7 @@ type TeamSpec struct { Scripts optjson.Slice[string] `json:"scripts"` WebhookSettings TeamSpecWebhookSettings `json:"webhook_settings"` Integrations TeamSpecIntegrations `json:"integrations"` - Software *TeamSpecSoftware `json:"software,omitempty"` + Software *SoftwareSpec `json:"software,omitempty"` } type TeamSpecWebhookSettings struct { diff --git a/server/service/client.go b/server/service/client.go index 09ab08e031..740ac19578 100644 --- a/server/service/client.go +++ b/server/service/client.go @@ -394,6 +394,7 @@ func (c *Client) ApplyGroup( specs *spec.Group, baseDir string, logf func(format string, args ...interface{}), + appconfig *fleet.EnrichedAppConfig, opts fleet.ApplyClientSpecOptions, ) (map[string]uint, error) { logfn := func(format string, args ...interface{}) { @@ -610,90 +611,10 @@ func (c *Client) ApplyGroup( tmSoftwarePackages := extractTmSpecsSoftwarePackages(specs.Teams) tmSoftwarePackagesPayloads := make(map[string][]fleet.SoftwareInstallerPayload, len(tmScripts)) for tmName, software := range tmSoftwarePackages { - softwarePayloads := make([]fleet.SoftwareInstallerPayload, len(software)) - for i, si := range software { - var qc string - var err error - if si.PreInstallQuery.Path != "" { - queryFile := resolveApplyRelativePath(baseDir, si.PreInstallQuery.Path) - rawSpec, err := os.ReadFile(queryFile) - if err != nil { - return nil, fmt.Errorf("reading pre-install query: %w", err) - } - - rawSpecExpanded, err := spec.ExpandEnvBytes(rawSpec) - if err != nil { - return nil, fmt.Errorf("Couldn't exit software (%s). Unable to expand environment variable in YAML file %s: %w", si.URL, queryFile, err) - } - - var top any - - if err := yaml.Unmarshal(rawSpecExpanded, &top); err != nil { - return nil, fmt.Errorf("Couldn't exit software (%s). Unable to expand environment variable in YAML file %s: %w", si.URL, queryFile, err) - } - - if _, ok := top.(map[any]any); ok { - // Old apply format - group, err := spec.GroupFromBytes(rawSpecExpanded) - if err != nil { - return nil, fmt.Errorf("Couldn't edit software (%s). Unable to parse pre-install apply format query YAML file %s: %w", si.URL, queryFile, err) - } - - if len(group.Queries) > 1 { - return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s should have only one query.", si.URL, queryFile) - } - - if len(group.Queries) == 0 { - return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s doesn't have a query defined.", si.URL, queryFile) - } - - qc = group.Queries[0].Query - } else { - // Gitops format - var querySpecs []fleet.QuerySpec - if err := yaml.Unmarshal(rawSpecExpanded, &querySpecs); err != nil { - return nil, fmt.Errorf("Couldn't edit software (%s). Unable to parse pre-install query YAML file %s: %w", si.URL, queryFile, err) - } - - if len(querySpecs) > 1 { - return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s should have only one query.", si.URL, queryFile) - } - - if len(querySpecs) == 0 { - return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s doesn't have a query defined.", si.URL, queryFile) - } - - qc = querySpecs[0].Query - } - } - - var ic []byte - if si.InstallScript.Path != "" { - installScriptFile := resolveApplyRelativePath(baseDir, si.InstallScript.Path) - ic, err = os.ReadFile(installScriptFile) - if err != nil { - return nil, fmt.Errorf("Couldn't edit software (%s). Unable to read install script file %s: %w", si.URL, si.InstallScript.Path, err) - } - } - - var pc []byte - if si.PostInstallScript.Path != "" { - postInstallScriptFile := resolveApplyRelativePath(baseDir, si.PostInstallScript.Path) - pc, err = os.ReadFile(postInstallScriptFile) - if err != nil { - return nil, fmt.Errorf("Couldn't edit software (%s). Unable to read post-install script file %s: %w", si.URL, si.PostInstallScript.Path, err) - } - } - - softwarePayloads[i] = fleet.SoftwareInstallerPayload{ - URL: si.URL, - SelfService: si.SelfService, - PreInstallQuery: qc, - InstallScript: string(ic), - PostInstallScript: string(pc), - } + softwarePayloads, err := buildSoftwarePackagesPayload(baseDir, software) + if err != nil { + return nil, fmt.Errorf("applying software installers for team %q: %w", tmName, err) } - tmSoftwarePackagesPayloads[tmName] = softwarePayloads } @@ -810,6 +731,95 @@ func (c *Client) ApplyGroup( return teamIDsByName, nil } +func buildSoftwarePackagesPayload(baseDir string, specs []fleet.SoftwarePackageSpec) ([]fleet.SoftwareInstallerPayload, error) { + softwarePayloads := make([]fleet.SoftwareInstallerPayload, len(specs)) + for i, si := range specs { + var qc string + var err error + if si.PreInstallQuery.Path != "" { + queryFile := resolveApplyRelativePath(baseDir, si.PreInstallQuery.Path) + rawSpec, err := os.ReadFile(queryFile) + if err != nil { + return nil, fmt.Errorf("reading pre-install query: %w", err) + } + + rawSpecExpanded, err := spec.ExpandEnvBytes(rawSpec) + if err != nil { + return nil, fmt.Errorf("Couldn't exit software (%s). Unable to expand environment variable in YAML file %s: %w", si.URL, queryFile, err) + } + + var top any + + if err := yaml.Unmarshal(rawSpecExpanded, &top); err != nil { + return nil, fmt.Errorf("Couldn't exit software (%s). Unable to expand environment variable in YAML file %s: %w", si.URL, queryFile, err) + } + + if _, ok := top.(map[any]any); ok { + // Old apply format + group, err := spec.GroupFromBytes(rawSpecExpanded) + if err != nil { + return nil, fmt.Errorf("Couldn't edit software (%s). Unable to parse pre-install apply format query YAML file %s: %w", si.URL, queryFile, err) + } + + if len(group.Queries) > 1 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s should have only one query.", si.URL, queryFile) + } + + if len(group.Queries) == 0 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s doesn't have a query defined.", si.URL, queryFile) + } + + qc = group.Queries[0].Query + } else { + // Gitops format + var querySpecs []fleet.QuerySpec + if err := yaml.Unmarshal(rawSpecExpanded, &querySpecs); err != nil { + return nil, fmt.Errorf("Couldn't edit software (%s). Unable to parse pre-install query YAML file %s: %w", si.URL, queryFile, err) + } + + if len(querySpecs) > 1 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s should have only one query.", si.URL, queryFile) + } + + if len(querySpecs) == 0 { + return nil, fmt.Errorf("Couldn't edit software (%s). Pre-install query YAML file %s doesn't have a query defined.", si.URL, queryFile) + } + + qc = querySpecs[0].Query + } + } + + var ic []byte + if si.InstallScript.Path != "" { + installScriptFile := resolveApplyRelativePath(baseDir, si.InstallScript.Path) + ic, err = os.ReadFile(installScriptFile) + if err != nil { + return nil, fmt.Errorf("Couldn't edit software (%s). Unable to read install script file %s: %w", si.URL, si.InstallScript.Path, err) + } + } + + var pc []byte + if si.PostInstallScript.Path != "" { + postInstallScriptFile := resolveApplyRelativePath(baseDir, si.PostInstallScript.Path) + pc, err = os.ReadFile(postInstallScriptFile) + if err != nil { + return nil, fmt.Errorf("Couldn't edit software (%s). Unable to read post-install script file %s: %w", si.URL, si.PostInstallScript.Path, err) + } + } + + softwarePayloads[i] = fleet.SoftwareInstallerPayload{ + URL: si.URL, + SelfService: si.SelfService, + PreInstallQuery: qc, + InstallScript: string(ic), + PostInstallScript: string(pc), + } + + } + + return softwarePayloads, nil +} + func extractAppCfgMacOSSetup(appCfg any) *fleet.MacOSSetup { asMap, ok := appCfg.(map[string]interface{}) if !ok { @@ -1045,8 +1055,8 @@ func extractTmSpecsMDMCustomSettings(tmSpecs []json.RawMessage) map[string]profi return m } -func extractTmSpecsSoftwarePackages(tmSpecs []json.RawMessage) map[string][]fleet.TeamSpecSoftwarePackage { - var m map[string][]fleet.TeamSpecSoftwarePackage +func extractTmSpecsSoftwarePackages(tmSpecs []json.RawMessage) map[string][]fleet.SoftwarePackageSpec { + var m map[string][]fleet.SoftwarePackageSpec for _, tm := range tmSpecs { var spec struct { Name string `json:"name"` @@ -1059,10 +1069,10 @@ func extractTmSpecsSoftwarePackages(tmSpecs []json.RawMessage) map[string][]flee spec.Name = norm.NFC.String(spec.Name) if spec.Name != "" && len(spec.Software) > 0 { if m == nil { - m = make(map[string][]fleet.TeamSpecSoftwarePackage) + m = make(map[string][]fleet.SoftwarePackageSpec) } - var software fleet.TeamSpecSoftware - var packages []fleet.TeamSpecSoftwarePackage + var software fleet.SoftwareSpec + var packages []fleet.SoftwarePackageSpec if err := json.Unmarshal(spec.Software, &software); err != nil { // ignore, will fail in apply team specs call continue @@ -1070,7 +1080,7 @@ func extractTmSpecsSoftwarePackages(tmSpecs []json.RawMessage) map[string][]flee if !software.Packages.Valid { // to be consistent with the AppConfig custom settings, set it to an // empty slice if the provided custom settings are present but empty. - packages = []fleet.TeamSpecSoftwarePackage{} + packages = []fleet.SoftwarePackageSpec{} } else { packages = software.Packages.Value } @@ -1096,7 +1106,7 @@ func extractTmSpecsSoftwareApps(tmSpecs []json.RawMessage) map[string][]fleet.Te if m == nil { m = make(map[string][]fleet.TeamSpecAppStoreApp) } - var software fleet.TeamSpecSoftware + var software fleet.SoftwareSpec var apps []fleet.TeamSpecAppStoreApp if err := json.Unmarshal(spec.Software, &software); err != nil { // ignore, will fail in apply team specs call @@ -1255,6 +1265,8 @@ func (c *Client) DoGitOps( } } group.AppConfig.(map[string]interface{})["scripts"] = scripts + + group.Software = config.Software.Packages } else { team = make(map[string]interface{}) team["name"] = *config.TeamName @@ -1413,7 +1425,7 @@ func (c *Client) DoGitOps( } // Apply org settings, scripts, enroll secrets, and controls - teamIDsByName, err := c.ApplyGroup(ctx, &group, baseDir, logf, fleet.ApplyClientSpecOptions{ + teamIDsByName, err := c.ApplyGroup(ctx, &group, baseDir, logf, appConfig, fleet.ApplyClientSpecOptions{ ApplySpecOptions: fleet.ApplySpecOptions{ DryRun: dryRun, }, @@ -1449,9 +1461,39 @@ func (c *Client) DoGitOps( return nil, err } + err = c.doGitOpsNoTeamSoftware(group, baseDir, appConfig, logFn, dryRun) + if err != nil { + return nil, err + } + return teamAssumptions, nil } +func (c *Client) doGitOpsNoTeamSoftware(specs spec.Group, baseDir string, appconfig *fleet.EnrichedAppConfig, logFn func(format string, args ...interface{}), dryRun bool) error { + if len(specs.Teams) == 0 && appconfig != nil && appconfig.License.IsPremium() { + packages := make([]fleet.SoftwarePackageSpec, 0, len(specs.Software)) + for _, software := range specs.Software { + if software != nil { + packages = append(packages, *software) + } + } + payload, err := buildSoftwarePackagesPayload(baseDir, packages) + if err != nil { + return fmt.Errorf("applying software installers: %w", err) + } + if err := c.ApplyNoTeamSoftwareInstallers(payload, fleet.ApplySpecOptions{DryRun: dryRun}); err != nil { + return fmt.Errorf("applying software installers: %w", err) + } + + if dryRun { + logFn("[+] would've applied 'No Team' software installers\n") + } else { + logFn("[+] applied 'No Team' software installers\n") + } + } + return nil +} + func (c *Client) doGitOpsPolicies(config *spec.GitOps, logFn func(format string, args ...interface{}), dryRun bool) error { // Get the ids and names of current policies to figure out which ones to delete policies, err := c.GetPolicies(config.TeamID) diff --git a/server/service/client_software.go b/server/service/client_software.go index 22c602e96c..d08faee404 100644 --- a/server/service/client_software.go +++ b/server/service/client_software.go @@ -1,6 +1,8 @@ package service import ( + "net/url" + "github.com/fleetdm/fleet/v4/server/fleet" ) @@ -25,3 +27,12 @@ func (c *Client) ListSoftwareTitles(query string) ([]fleet.SoftwareTitleListResu } return responseBody.SoftwareTitles, nil } + +func (c *Client) ApplyNoTeamSoftwareInstallers(softwareInstallers []fleet.SoftwareInstallerPayload, opts fleet.ApplySpecOptions) error { + verb, path := "POST", "/api/latest/fleet/software/batch" + query, err := url.ParseQuery(opts.RawQuery()) + if err != nil { + return err + } + return c.authenticatedRequestWithQuery(map[string]interface{}{"software": softwareInstallers}, verb, path, nil, query.Encode()) +} diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index 438138dc67..79e61b96d1 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -10161,7 +10161,7 @@ func (s *integrationEnterpriseTestSuite) TestApplyTeamsSoftwareConfig() { } s.Do("POST", "/api/latest/fleet/spec/teams", teamSpecs, http.StatusOK) - wantSoftwarePackages := []fleet.TeamSpecSoftwarePackage{ + wantSoftwarePackages := []fleet.SoftwarePackageSpec{ { URL: "http://foo.com", SelfService: true, @@ -10320,9 +10320,6 @@ func (s *integrationEnterpriseTestSuite) TestApplyTeamsSoftwareConfig() { func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() { t := s.T() - // a team name is required (we don't allow installers for "no team") - s.Do("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{}, http.StatusBadRequest) - // non-existent team s.Do("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{}, http.StatusNotFound, "team_name", "foo") @@ -10397,6 +10394,42 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() { s.DoJSON("GET", "/api/v1/fleet/software/titles", nil, http.StatusOK, &titlesResp, "available_for_install", "true", "team_id", strconv.Itoa(int(tm.ID))) require.Equal(t, 0, titlesResp.Count) require.Len(t, titlesResp.SoftwareTitles, 0) + + ////////////////////////// + // Do a request with a valid URL with no team + ////////////////////////// + softwareToInstall = []fleet.SoftwareInstallerPayload{ + {URL: srv.URL}, + } + s.Do("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusNoContent) + + // check the application status on team 0 + titlesResp = listSoftwareTitlesResponse{} + s.DoJSON("GET", "/api/v1/fleet/software/titles", nil, http.StatusOK, &titlesResp, "available_for_install", "true", "team_id", strconv.Itoa(int(0))) + require.Equal(t, 1, titlesResp.Count) + require.Len(t, titlesResp.SoftwareTitles, 1) + + // same payload doesn't modify anything + s.Do("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusNoContent) + newTitlesResp = listSoftwareTitlesResponse{} + s.DoJSON("GET", "/api/v1/fleet/software/titles", nil, http.StatusOK, &newTitlesResp, "available_for_install", "true", "team_id", strconv.Itoa(int(0))) + require.Equal(t, titlesResp, newTitlesResp) + + // setting self-service to true updates the software title metadata + softwareToInstall[0].SelfService = true + s.Do("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusNoContent) + newTitlesResp = listSoftwareTitlesResponse{} + s.DoJSON("GET", "/api/v1/fleet/software/titles", nil, http.StatusOK, &newTitlesResp, "available_for_install", "true", "team_id", strconv.Itoa(int(0))) + titlesResp.SoftwareTitles[0].SoftwarePackage.SelfService = ptr.Bool(true) + require.Equal(t, titlesResp, newTitlesResp) + + // empty payload cleans the software items + softwareToInstall = []fleet.SoftwareInstallerPayload{} + s.Do("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusNoContent) + titlesResp = listSoftwareTitlesResponse{} + s.DoJSON("GET", "/api/v1/fleet/software/titles", nil, http.StatusOK, &titlesResp, "available_for_install", "true", "team_id", strconv.Itoa(int(0))) + require.Equal(t, 0, titlesResp.Count) + require.Len(t, titlesResp.SoftwareTitles, 0) } func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerNewInstallRequestPlatformValidation() { diff --git a/server/service/software_installers.go b/server/service/software_installers.go index 5de426c2d6..0cdff35c2a 100644 --- a/server/service/software_installers.go +++ b/server/service/software_installers.go @@ -318,7 +318,7 @@ func (svc *Service) GetSoftwareInstallResults(ctx context.Context, resultUUID st //////////////////////////////////////////////////////////////////////////////// type batchSetSoftwareInstallersRequest struct { - TeamName string `json:"-" query:"team_name"` + TeamName string `json:"-" query:"team_name,optional"` DryRun bool `json:"-" query:"dry_run,optional"` // if true, apply validation but do not save changes Software []fleet.SoftwareInstallerPayload `json:"software"` } From 5730c1c3c855ff8837b7475cd5b5c02bd8b122a8 Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:57:53 -0700 Subject: [PATCH 79/88] =?UTF-8?q?UI=20=E2=80=93=20Render=20"vulns=20not=20?= =?UTF-8?q?supported"=20empty=20state=20for=20iphone/ipad=20host=20softwar?= =?UTF-8?q?e=20filtered=20by=20vuln=20(#21029)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## #21027 Screenshot 2024-08-02 at 4 12 52 PM - [x] Manual QA for all new/changed functionality Co-authored-by: Jacob Shandling --- .../HostDetailsPage/HostDetailsPage.tsx | 3 ++ .../details/cards/Software/HostSoftware.tsx | 31 ++++++++++++++++--- .../HostSoftwareTable/HostSoftwareTable.tsx | 24 ++++++++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 5f4a57a356..cf63e55962 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -53,6 +53,8 @@ import { HOST_OSQUERY_DATA, } from "utilities/constants"; +import { Platform } from "interfaces/platform"; + import Spinner from "components/Spinner"; import TabsWrapper from "components/TabsWrapper"; import MainContent from "components/MainContent"; @@ -921,6 +923,7 @@ const HostDetailsPage = ({ { interface IHostSoftwareProps { /** This is the host id or the device token */ id: number | string; + /** The host's platform. Only used for the host details page, so can be omited on the Device User Page. */ + platform?: Platform; softwareUpdatedAt?: string; hostCanInstallSoftware: boolean; router: InjectedRouter; @@ -82,6 +85,7 @@ export const parseHostSoftwareQueryParams = (queryParams: { const HostSoftware = ({ id, + platform, softwareUpdatedAt, hostCanInstallSoftware, router, @@ -93,6 +97,8 @@ const HostSoftware = ({ isMyDevicePage = false, }: IHostSoftwareProps) => { const { renderFlash } = useContext(NotificationContext); + const vulnFilterAndNotSupported = + ["ios", "ipados"].includes(platform ?? "") && queryParams.vulnerable; const { isGlobalAdmin, isGlobalMaintainer, @@ -129,7 +135,8 @@ const HostSoftware = ({ }, { ...DEFAULT_USE_QUERY_OPTIONS, - enabled: isSoftwareEnabled && !isMyDevicePage, // if disabled, we'll always show a generic "No software detected" message + enabled: + isSoftwareEnabled && !isMyDevicePage && !vulnFilterAndNotSupported, keepPreviousData: true, staleTime: 7000, } @@ -158,7 +165,7 @@ const HostSoftware = ({ ({ queryKey }) => deviceAPI.getDeviceSoftware(queryKey[0]), { ...DEFAULT_USE_QUERY_OPTIONS, - enabled: isSoftwareEnabled && isMyDevicePage, // if disabled, we'll always show a generic "No software detected" message + enabled: isSoftwareEnabled && isMyDevicePage, // if disabled, we'll always show a generic "No software detected" message. No DUP for iPad/iPhone keepPreviousData: true, staleTime: 7000, } @@ -251,7 +258,10 @@ const HostSoftware = ({ if (isLoading) { return ; } - + // will never be the case - to handle `platform` typing discrepancy with DeviceUserPage + if (!platform) { + return null; + } return ( <> {isError && } @@ -260,7 +270,20 @@ const HostSoftware = ({ isLoading={ isMyDevicePage ? deviceSoftwareFetching : hostSoftwareFetching } - data={data} + // this could be cleaner, however, we are going to revert this commit anyway once vulns are + // supported for iPad/iPhone, by the end of next sprint + data={ + vulnFilterAndNotSupported + ? ({ + count: 0, + meta: { + has_next_results: false, + has_previous_results: false, + }, + } as IGetHostSoftwareResponse) + : data + } // eshould be mpty for iPad/iPhone since API call is disabled, but to be sure to trigger empty state + platform={platform} router={router} tableConfig={tableConfig} sortHeader={queryParams.order_key} diff --git a/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx b/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx index 6ac5f7a4a9..cf37cd0065 100644 --- a/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx +++ b/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx @@ -8,6 +8,12 @@ import { QueryParams } from "utilities/url"; import { ISoftwareDropdownFilterVal } from "pages/SoftwarePage/SoftwareTitles/SoftwareTable/helpers"; +import { + ApplePlatform, + APPLE_PLATFORM_DISPLAY_NAMES, + Platform, +} from "interfaces/platform"; + import TableContainer from "components/TableContainer"; import { ITableQueryData } from "components/TableContainer/TableContainer"; // @ts-ignore @@ -15,6 +21,7 @@ import Dropdown from "components/forms/fields/Dropdown"; import EmptySoftwareTable from "pages/SoftwarePage/components/EmptySoftwareTable"; import TableCount from "components/TableContainer/TableCount"; +import { VulnsNotSupported } from "pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable"; const DEFAULT_PAGE_SIZE = 20; @@ -45,6 +52,7 @@ export const DROPDOWN_OPTIONS = [ interface IHostSoftwareTableProps { tableConfig: any; // TODO: type data?: IGetHostSoftwareResponse | IGetDeviceSoftwareResponse; + platform: Platform; isLoading: boolean; router: InjectedRouter; sortHeader: string; @@ -60,6 +68,7 @@ interface IHostSoftwareTableProps { const HostSoftwareTable = ({ tableConfig, data, + platform, isLoading, router, sortHeader, @@ -167,7 +176,7 @@ const HostSoftwareTable = ({ [determineQueryParamChange, pagePath, generateNewQueryParams, router] ); - const count = data?.count || data?.software.length || 0; + const count = data?.count || data?.software?.length || 0; const isSoftwareNotDetected = count === 0 && searchQuery === ""; const memoizedSoftwareCount = useCallback(() => { @@ -179,8 +188,17 @@ const HostSoftwareTable = ({ }, [count, isSoftwareNotDetected]); const memoizedEmptyComponent = useCallback(() => { - return ; - }, [searchQuery]); + const vulnFilterAndNotSupported = + ["ios", "ipados"].includes(platform) && + hostSoftwareFilter === "vulnerableSoftware"; + return vulnFilterAndNotSupported ? ( + + ) : ( + + ); + }, [hostSoftwareFilter, platform, searchQuery]); return (
    From afc292666c1703f4e0c6a5c4be7a44b98aeb17d1 Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:54:16 -0400 Subject: [PATCH 80/88] Fleet UI: Update host details > software > status "Installed" tooltip (#21052) --- frontend/pages/SoftwarePage/SoftwarePage.tsx | 2 +- .../cards/Software/InstallStatusCell/InstallStatusCell.tsx | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/pages/SoftwarePage/SoftwarePage.tsx b/frontend/pages/SoftwarePage/SoftwarePage.tsx index 1cf063cc2d..34aeb03cc5 100644 --- a/frontend/pages/SoftwarePage/SoftwarePage.tsx +++ b/frontend/pages/SoftwarePage/SoftwarePage.tsx @@ -348,7 +348,7 @@ const SoftwarePage = ({ children, router, location }: ISoftwarePageProps) => { const renderHeaderDescription = () => { return (

    - Manage software and search for installed software, OS and + Manage software and search for installed software, OS, and vulnerabilities {isAllTeamsSelected ? "for all hosts" : "on this team"}.

    ); diff --git a/frontend/pages/hosts/details/cards/Software/InstallStatusCell/InstallStatusCell.tsx b/frontend/pages/hosts/details/cards/Software/InstallStatusCell/InstallStatusCell.tsx index 38a3a42df3..7e8ea90bc1 100644 --- a/frontend/pages/hosts/details/cards/Software/InstallStatusCell/InstallStatusCell.tsx +++ b/frontend/pages/hosts/details/cards/Software/InstallStatusCell/InstallStatusCell.tsx @@ -38,8 +38,9 @@ export const INSTALL_STATUS_DISPLAY_OPTIONS: Record< displayText: "Installed", tooltip: ({ lastInstalledAt: lastInstall }) => ( <> - Fleet installed software on these hosts. ( - {dateAgo(lastInstall as string)}) + Fleet installed software on this host + {dateAgo(lastInstall as string)}). Currently, if the software is + deleted, the “Installed” status won’t be updated. ), }, From 379aa9e6f742daca8d58c3bc1661cdfd170fe2fb Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Mon, 5 Aug 2024 18:14:12 -0300 Subject: [PATCH 81/88] add Escrow Buddy to TUF.md after the push to `stable` (#21066) --- orbit/TUF.md | 2 ++ tools/tuf/status/tuf-status.go | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/orbit/TUF.md b/orbit/TUF.md index 53be1e46e8..634ee62b5d 100644 --- a/orbit/TUF.md +++ b/orbit/TUF.md @@ -12,6 +12,7 @@ Following are the currently deployed versions of fleetd components on the `stabl | osqueryd | 5.12.1 | 5.12.1 | 5.12.1 | 5.12.1 | | nudge | 1.1.10.81462 | - | - | - | | swiftDialog | 2.1.0 | - | - | - | +| escrowBuddy | 1.0.0 | - | - | - | ## `edge` @@ -22,3 +23,4 @@ Following are the currently deployed versions of fleetd components on the `stabl | osqueryd | 5.13.0 | 5.13.0 | 5.13.0 | 5.13.0 | | nudge | - | - | - | - | | swiftDialog | - | - | - | - | +| escrowBuddy | - | - | - | - | diff --git a/tools/tuf/status/tuf-status.go b/tools/tuf/status/tuf-status.go index 6f8aa6fd36..e62dc14f12 100644 --- a/tools/tuf/status/tuf-status.go +++ b/tools/tuf/status/tuf-status.go @@ -186,6 +186,9 @@ func channelVersionCommand() *cli.Command { "swiftDialog": { "macos": "swiftDialog.app.tar.gz", }, + "escrowBuddy": { + "macos": "escrowBuddy.pkg", + }, } var ( channel string @@ -208,7 +211,7 @@ func channelVersionCommand() *cli.Command { &cli.StringSliceFlag{ Name: "components", EnvVars: []string{"TUF_STATUS_COMPONENTS"}, - Value: cli.NewStringSlice("orbit", "desktop", "osqueryd", "nudge", "swiftDialog"), + Value: cli.NewStringSlice("orbit", "desktop", "osqueryd", "nudge", "swiftDialog", "escrowBuddy"), Destination: &components, Usage: "List of components", }, @@ -324,7 +327,7 @@ func channelVersionCommand() *cli.Command { Right: true, }) var rows [][]string - componentsInOrder := []string{"orbit", "desktop", "osqueryd", "nudge", "swiftDialog"} + componentsInOrder := []string{"orbit", "desktop", "osqueryd", "nudge", "swiftDialog", "escrowBuddy"} setIfEmpty := func(m map[string]string, k string) string { v := m[k] if v == "" { From b49841acc13de31b16ff47929c4997f2b6c6eb38 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 5 Aug 2024 16:23:08 -0500 Subject: [PATCH 82/88] Website: Add unsubscribe link to marketing emails (#21055) Closes: https://github.com/fleetdm/confidential/issues/7528 Changes: - Added a new action: unsubscribe-from-marketing-emails, which updates a user record that uses a specified email address to exclude it from the deliver-nurture-emails script. - Updated the email template to include a link that users can click to unsubscribe. - Added a modal to the homepage that is shown to users who unsubscribe from marketing emails - Updated the email template data in deliver-nurture-emails and view-email-template-preview --- .../admin/view-email-template-preview.js | 9 ++- .../unsubscribe-from-marketing-emails.js | 79 +++++++++++++++++++ website/api/models/User.js | 7 +- website/assets/js/pages/homepage.page.js | 4 + website/config/routes.js | 3 +- website/scripts/deliver-nurture-emails.js | 9 ++- .../views/layouts/layout-nurture-email.ejs | 1 + website/views/pages/homepage.ejs | 3 + 8 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 website/api/controllers/unsubscribe-from-marketing-emails.js diff --git a/website/api/controllers/admin/view-email-template-preview.js b/website/api/controllers/admin/view-email-template-preview.js index 5692353463..6898cb3370 100644 --- a/website/api/controllers/admin/view-email-template-preview.js +++ b/website/api/controllers/admin/view-email-template-preview.js @@ -117,19 +117,22 @@ module.exports = { case 'email-nurture-stage-three': layout = 'layout-nurture-email'; fakeData = { - firstName: 'Sage' + firstName: 'Sage', + emailAddress: 'sage@example.com', }; break; case 'email-nurture-stage-four': layout = 'layout-nurture-email'; fakeData = { - firstName: 'Sage' + firstName: 'Sage', + emailAddress: 'sage@example.com', }; break; case 'email-nurture-stage-five': layout = 'layout-nurture-email'; fakeData = { - firstName: 'Sage' + firstName: 'Sage', + emailAddress: 'sage@example.com', }; break; case 'email-deal-registration': diff --git a/website/api/controllers/unsubscribe-from-marketing-emails.js b/website/api/controllers/unsubscribe-from-marketing-emails.js new file mode 100644 index 0000000000..26a9b53ee8 --- /dev/null +++ b/website/api/controllers/unsubscribe-from-marketing-emails.js @@ -0,0 +1,79 @@ +module.exports = { + + + friendlyName: 'Unsubscribe from marketing emails', + + + description: 'Unsubscribes a specified email address from the nurture email automation.', + + + inputs: { + emailAddress: { + type: 'string', + description: 'The email address of the user who wants to unsubscribe from marketing emails.', + required: true, + } + }, + + + exits: { + userNotFound: { + description: 'The provided email address could not be matched to a Fleet user account', + responseType: 'badRequest', + }, + success: { + description: 'The user has opted out of markering emails', + } + }, + + + fn: async function ({emailAddress}) { + + let userRecord = await User.findOne({emailAddress: emailAddress}); + + if(!userRecord){ + throw 'userNotFound'; + } + // Update the user record for this email address to set their nurture email timestamps to 1 + // so they are excluded them from future runs of the deliver-nurture-emails script. + // FUTURE: update the user model to have a subscribedToNurtureEmails attribute. + await User.updateOne({emailAddress: emailAddress}).set({ + stageThreeNurtureEmailSentAt: 1, + stageFourNurtureEmailSentAt: 1, + stageFiveNurtureEmailSentAt: 1, + }); + + // Update the contact record in salesforce for this email address to indicate that they have opted out of marketing emails. + if(sails.config.environment === 'production'){ + require('assert')(sails.config.custom.salesforceIntegrationUsername); + require('assert')(sails.config.custom.salesforceIntegrationPasskey); + + // Log in to Salesforce. + let jsforce = require('jsforce'); + let salesforceConnection = new jsforce.Connection({ + loginUrl : 'https://fleetdm.my.salesforce.com' + }); + await salesforceConnection.login(sails.config.custom.salesforceIntegrationUsername, sails.config.custom.salesforceIntegrationPasskey); + + let existingContactRecord = await salesforceConnection.sobject('Contact') + .findOne({ + Email: emailAddress, + }); + + if(existingContactRecord) { + //If we found an existing contact record in salesforce, update its status to be "Do not contact" + let salesforceContactId = existingContactRecord.Id; + await salesforceConnection.sobject('Contact') + .update({ + Id: salesforceContactId, + Unsubscribed_from_email_contact__c: true,// eslint-disable-line camelcase + }); + } + } + // Redirect the user to the homepage with a #unsubscribe hash link. + return this.res.redirect('/#unsubscribed'); + + } + + +}; diff --git a/website/api/models/User.js b/website/api/models/User.js index 72b603338d..53be23f9c6 100644 --- a/website/api/models/User.js +++ b/website/api/models/User.js @@ -248,20 +248,19 @@ without necessarily having a billing card.` stageThreeNurtureEmailSentAt: { type: 'number', - description: 'A JS timestamp of when the stage 3 nurture email was sent to the user.' + description: 'A JS timestamp of when the stage 3 nurture email was sent to the user, or 1 if the user is unsubscribed from automated emails.', }, stageFourNurtureEmailSentAt: { type: 'number', - description: 'A JS timestamp of when the stage 4 nurture email was sent to the user.' + description: 'A JS timestamp of when the stage 4 nurture email was sent to the user, or 1 if the user is unsubscribed from automated emails.', }, stageFiveNurtureEmailSentAt: { type: 'number', - description: 'A JS timestamp of when the stage 5 nurture email was sent to the user.' + description: 'A JS timestamp of when the stage 5 nurture email was sent to the user, or 1 if the user is unsubscribed from automated emails.', }, - // ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗ // ║╣ ║║║╠╩╗║╣ ║║╚═╗ // ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝ diff --git a/website/assets/js/pages/homepage.page.js b/website/assets/js/pages/homepage.page.js index 5a5100cebc..b9bfc560b4 100644 --- a/website/assets/js/pages/homepage.page.js +++ b/website/assets/js/pages/homepage.page.js @@ -12,6 +12,10 @@ parasails.registerPage('homepage', { // ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝ beforeMount: function() { //… + if(window.location.hash === '#unsubscribed'){ + this.modal = 'unsubscribed'; + window.location.hash = ''; + } }, mounted: async function() { //… diff --git a/website/config/routes.js b/website/config/routes.js index 59b068e650..1a87ea2567 100644 --- a/website/config/routes.js +++ b/website/config/routes.js @@ -480,7 +480,7 @@ module.exports.routes = { 'GET /get-started': '/try-fleet', 'GET /g': (req,res)=> { let originalQueryStringWithAmp = req.url.match(/\?(.+)$/) ? '&'+req.url.match(/\?(.+)$/)[1] : ''; return res.redirect(301, sails.config.custom.baseUrl+'/?meet-fleet'+originalQueryStringWithAmp); }, 'GET /test-fleet-sandbox': '/register', - 'GET /unsubscribe': (req,res)=> { let originalQueryString = req.url.match(/\?(.+)$/) ? req.url.match(/\?(.+)$/)[1] : ''; return res.redirect(301, sails.config.custom.baseUrl+'/api/v1/unsubscribe-from-all-newsletters?'+originalQueryString);}, + 'GET /unsubscribe': (req,res)=> { let originalQueryString = req.url.match(/\?(.+)$/) ? req.url.match(/\?(.+)$/)[1] : ''; return res.redirect(301, sails.config.custom.baseUrl+'/api/v1/unsubscribe-from-marketing-emails?'+originalQueryString);}, 'GET /tables': '/tables/account_policy_data', 'GET /imagine/launch-party': 'https://www.eventbrite.com/e/601763519887', 'GET /blackhat2023': 'https://github.com/fleetdm/fleet/tree/main/tools/blackhat-mdm', // Assets from @marcosd4h & @zwass Black Hat 2023 talk @@ -605,4 +605,5 @@ module.exports.routes = { 'POST /api/v1/save-questionnaire-progress': { action: 'save-questionnaire-progress' }, 'POST /api/v1/account/update-start-cta-visibility': { action: 'account/update-start-cta-visibility' }, 'POST /api/v1/deliver-deal-registration-submission': { action: 'deliver-deal-registration-submission' }, + '/api/v1/unsubscribe-from-marketing-emails': { action: 'unsubscribe-from-marketing-emails' }, }; diff --git a/website/scripts/deliver-nurture-emails.js b/website/scripts/deliver-nurture-emails.js index 552c75b0a5..e3f90e254f 100644 --- a/website/scripts/deliver-nurture-emails.js +++ b/website/scripts/deliver-nurture-emails.js @@ -52,7 +52,8 @@ module.exports = { template: 'email-nurture-stage-three', layout: 'layout-nurture-email', templateData: { - firstName: user.firstName + firstName: user.firstName, + emailAddress: user.emailAddress }, to: user.emailAddress, toName: `${user.firstName} ${user.lastName}`, @@ -80,7 +81,8 @@ module.exports = { template: 'email-nurture-stage-four', layout: 'layout-nurture-email', templateData: { - firstName: user.firstName + firstName: user.firstName, + emailAddress: user.emailAddress }, to: user.emailAddress, toName: `${user.firstName} ${user.lastName}`, @@ -109,7 +111,8 @@ module.exports = { template: 'email-nurture-stage-five', layout: 'layout-nurture-email', templateData: { - firstName: user.firstName + firstName: user.firstName, + emailAddress: user.emailAddress }, to: user.emailAddress, toName: `${user.firstName} ${user.lastName}`, diff --git a/website/views/layouts/layout-nurture-email.ejs b/website/views/layouts/layout-nurture-email.ejs index 007880839b..5c4df42a0e 100644 --- a/website/views/layouts/layout-nurture-email.ejs +++ b/website/views/layouts/layout-nurture-email.ejs @@ -18,5 +18,6 @@

    © <%= (new Date()).getFullYear() %> Fleet Inc.
    All trademarks are the property of their respective owners.

    + Unsubscribe
    diff --git a/website/views/pages/homepage.ejs b/website/views/pages/homepage.ejs index 365b33a3ab..ef71b85ee8 100644 --- a/website/views/pages/homepage.ejs +++ b/website/views/pages/homepage.ejs @@ -384,6 +384,9 @@
    <%/* Cloud city banner */%> + +

    Your email preferences have been updated.

    +
    From 0995cbf745859c708cb1a2d0eb0b3db352846e9a Mon Sep 17 00:00:00 2001 From: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:04:19 +0900 Subject: [PATCH 83/88] Add brand fronts ritual (#20930) Added brand fronts ritual and instructions. Closes https://github.com/fleetdm/fleet/issues/20911 --------- Co-authored-by: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com> --- handbook/digital-experience/README.md | 6 ++++++ handbook/digital-experience/digital-experience.rituals.yml | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/handbook/digital-experience/README.md b/handbook/digital-experience/README.md index b4bc7db24a..7c5a7d339c 100644 --- a/handbook/digital-experience/README.md +++ b/handbook/digital-experience/README.md @@ -517,6 +517,12 @@ It's not enough to just "delete" a recording of a meeting in Gong. Instead, use - Search for the title of the meeting Google Drive and delete the auto-generated Google Doc containing the transcript. - Always check back to ensure the recording **and** transcript were both deleted. +### Update a company brand front + +Fleet has several brand fronts that need to be updated from time to time. Check each [brand front](https://docs.google.com/spreadsheets/d/1c15vwMZytpCLHUdGvXxi0d6WGgPcQU1UBMniC1F9oKk/edit?gid=0#gid=0) for consistency and update as needed with the following: +- The current pitch, found in the blurbs section of the [🎐 Why Fleet?](https://docs.google.com/document/d/1E0VU4AcB6UTVRd4JKD45Saxh9Gz-mkO3LnGSTBDLEZo/edit#heading=h.uovxedjegxdc) doc. +- The current [brand imagery](https://www.figma.com/design/1J2yxqH8Q7u8V7YTtA1iej/Social-media-(logos%2C-covers%2C-banners)?node-id=3962-65895). Check this [Loom video](https://www.loom.com/share/4432646cc9614046aaa4a74da1c0adb5?sid=2f84779f-f0bd-4055-be69-282c5a16f5c5) for more info. + ## Rituals diff --git a/handbook/digital-experience/digital-experience.rituals.yml b/handbook/digital-experience/digital-experience.rituals.yml index bc2b4db7ca..5b9f8d155e 100644 --- a/handbook/digital-experience/digital-experience.rituals.yml +++ b/handbook/digital-experience/digital-experience.rituals.yml @@ -18,6 +18,13 @@ description: "Run through the entire website in `?utm_content=clear` mode and build a fresh outline of the headings to make sure they all still make sense." moreInfoUrl: "" dri: "mike-j-thomas" +- + task: "Check brand fronts are up to date" + startedOn: "2024-08-01" + frequency: "Quarterly" + description: "Check all brand fronts for consistancy and update as needed with the current product pitch and graphics." + moreInfoUrl: "https://fleetdm.com/handbook/digital-experience#update-a-company-brand-front" + dri: "mike-j-thomas" - task: "Check production dependencies of fleetdm.com" startedOn: "2023-11-10" From c553b4772cbfb06a7781b9f2b66515a19ffa6d1e Mon Sep 17 00:00:00 2001 From: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com> Date: Tue, 6 Aug 2024 00:06:29 -0500 Subject: [PATCH 84/88] Remove sprint filters from handbook (#20899) --- handbook/digital-experience/README.md | 2 +- handbook/product-design/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/handbook/digital-experience/README.md b/handbook/digital-experience/README.md index 7c5a7d339c..d0015e568a 100644 --- a/handbook/digital-experience/README.md +++ b/handbook/digital-experience/README.md @@ -17,7 +17,7 @@ This page details processes specific to working [with](#contact-us) and [within] ## Contact us - To **make a request** of this department, [create an issue](https://github.com/fleetdm/fleet/issues/new?assignees=&labels=%23g-digital-experience&projects=&template=digital-experience-request.md&title=TODO%3A+) and a team member will get back to you within one business day (If urgent, mention a [team member](#team) in the [#g-digital-experience](https://fleetdm.slack.com/archives/C058S8PFSK0) Slack channel. - - Any Fleet team member can [view the kanban board](https://app.zenhub.com/workspaces/g-digital-experience-6451748b4eb15200131d4bab/board) for this department, including pending tasks and the status of new requests. + - Any Fleet team member can [view the kanban board](https://app.zenhub.com/workspaces/g-digital-experience-6451748b4eb15200131d4bab/board?sprints=none) for this department, including pending tasks and the status of new requests. - Please **use issue comments and GitHub mentions** to communicate follow-ups or answer questions related to your request. diff --git a/handbook/product-design/README.md b/handbook/product-design/README.md index af31d259ee..4774fe642c 100644 --- a/handbook/product-design/README.md +++ b/handbook/product-design/README.md @@ -10,7 +10,7 @@ This handbook page details processes specific to working [with](#contact-us) and ## Contact us - To **make a request** of this department, [create an issue](https://github.com/fleetdm/confidential/issues/new?labels=%3Aproduct&title=Product%20design%20request%C2%BB______________________&template=custom-request.md) and a team member will get back to you within one business day (If urgent, mention a [team member](#team) in `#help-design`. - Please **use issue comments and GitHub mentions** to communicate follow-ups or answer questions related to your request. - - Any Fleet team member can [view the kanban board](https://app.zenhub.com/workspaces/-g-digital-experience-6451748b4eb15200131d4bab/board?sprints=none) for this department, including pending tasks and the status of new requests. + - Any Fleet team member can [view the kanban board](https://app.zenhub.com/workspaces/-g-digital-experience-6451748b4eb15200131d4bab/board) for this department, including pending tasks and the status of new requests. ## Responsibilities The Product Design department is responsible for reviewing and collecting feedback from users, would-be users, and future users, prioritizing changes, designing the changes, and delivering these changes to the engineering team. Product Design prioritizes and shapes all changes involving functionality or usage, including the UI, REST API, command line, and webhooks. From 9325bca9c1015f2c8d58d5d9473f9fb8b963191b Mon Sep 17 00:00:00 2001 From: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com> Date: Tue, 6 Aug 2024 00:16:33 -0500 Subject: [PATCH 85/88] Fix sentence case (#21077) --- infrastructure/render/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/infrastructure/render/README.md b/infrastructure/render/README.md index 23bd1618d0..2a464c75ae 100644 --- a/infrastructure/render/README.md +++ b/infrastructure/render/README.md @@ -1,43 +1,43 @@ [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/fleetdm/fleet) -# Fleet Deployment Guide +# Fleet deployment guide This guide outlines the services configured in the Render blueprint for deploying the Fleet system, which includes a web service, a MySQL database, and a Redis server. -## Services Overview +## Services overview -### 1. Fleet Web Service +### 1. Fleet web service - **Type:** Web - **Runtime:** Image - **Image:** `fleetdm/fleet:latest` - **Description:** Main web service running the Fleet application, which is deployed using the latest Fleet Docker image. Configured to prepare the database before deployment. -- **Health Check Path:** `/healthz` -- **Environment Variables:** Connects to MySQL and Redis using service-bound environment variables. +- **Health check path:** `/healthz` +- **Environment variables:** Connects to MySQL and Redis using service-bound environment variables. -### 2. Fleet MySQL Database -- **Type:** Private Service (pserv) +### 2. Fleet MySQL database +- **Type:** Private service (pserv) - **Runtime:** Docker - **Repository:** [MySQL Example on Render](https://github.com/render-examples/mysql) - **Disk:** 10 GB mounted at `/var/lib/mysql` - **Description:** MySQL database used by the Fleet web service. Environment variables for database credentials are managed within the service and some are automatically generated. -### 3. Fleet Redis Service -- **Type:** Private Service (pserv) +### 3. Fleet Redis service +- **Type:** Private service (pserv) - **Runtime:** Image - **Repository:** [Redis Docker image](https://hub.docker.com/_/redis) - **Description:** Redis service for caching and other in-memory data storage needs of the Fleet web service. -## Deployment Guide +## Deployment guide ### Prerequisites - You need an account on [Render](https://render.com). - Familiarity with Render's dashboard and deployment concepts. -### Steps to Deploy +### Steps to deploy Click the deploy on render button or import the blueprint from the Render service deployment dashboard. -### Post-Deployment +### Post-deployment Navigate to the generated URL and run through the initial setup. If you have a license key you can add it post-deploy as an environment variable `FLEET_LICENSE_KEY=value` in the Fleet service configuration. From 9200f1822943eb441dd1868b27620aeb888bd541 Mon Sep 17 00:00:00 2001 From: Gabriel Hernandez Date: Tue, 6 Aug 2024 10:52:23 +0100 Subject: [PATCH 86/88] display the custom labels by in case-insensitive alphabetical ascending order (#21041) relates to #20194 The UI displayed the custom labels by creation date, but we now display custom labels in the UI by name in case-insensitive alphabetical ascending order. ![image](https://github.com/user-attachments/assets/43ce642b-8335-4542-ac38-4b5a4ab569e4) - [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] Manual QA for all new/changed functionality --- changes/20194-sort-label-names-in-ui | 1 + .../AddProfileModal/AddProfileModal.tsx | 7 ++---- .../components/LabelFilterSelect/helpers.ts | 4 +++- frontend/services/entities/labels.ts | 22 +++++++++++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 changes/20194-sort-label-names-in-ui diff --git a/changes/20194-sort-label-names-in-ui b/changes/20194-sort-label-names-in-ui new file mode 100644 index 0000000000..2f27f77f0b --- /dev/null +++ b/changes/20194-sort-label-names-in-ui @@ -0,0 +1 @@ +- display the label names case-insensitive alphabetical order in the fleet UI diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/AddProfileModal.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/AddProfileModal.tsx index 88b7e96ed9..12191a9641 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/AddProfileModal.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/AddProfileModal.tsx @@ -7,7 +7,7 @@ import { NotificationContext } from "context/notification"; import { IApiError } from "interfaces/errors"; import { ILabelSummary } from "interfaces/label"; -import labelsAPI from "services/entities/labels"; +import labelsAPI, { getCustomLabels } from "services/entities/labels"; import mdmAPI from "services/entities/mdm"; // @ts-ignore @@ -250,10 +250,7 @@ const AddProfileModal = ({ isError: isErrorLabels, } = useQuery( ["custom_labels"], - () => - labelsAPI - .summary() - .then((res) => res.labels.filter((l) => l.label_type !== "builtin")), + () => labelsAPI.summary().then((res) => getCustomLabels(res.labels)), { enabled: isPremiumTier, diff --git a/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/helpers.ts b/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/helpers.ts index b6aad87e53..746a2b6ddb 100644 --- a/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/helpers.ts +++ b/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/helpers.ts @@ -1,4 +1,6 @@ import { ILabel } from "interfaces/label"; +import { getCustomLabels } from "services/entities/labels"; + import { EMPTY_OPTION, FILTERED_LINUX, NO_LABELS_OPTION } from "./constants"; export interface IEmptyOption { @@ -27,7 +29,7 @@ const createOptionGroup = ( /** Will create the custom label group options and handles when no labels have been created yet or * will filter by the desired search query */ const createCustomLabelOptions = (labels: ILabel[], query: string) => { - const customLabels = labels.filter((label) => label.label_type === "regular"); + const customLabels = getCustomLabels(labels); let customLabelGroupOptions: ILabel[] | IEmptyOption[]; if (customLabels.length === 0) { diff --git a/frontend/services/entities/labels.ts b/frontend/services/entities/labels.ts index 7a58cb9a04..5ce8d04938 100644 --- a/frontend/services/entities/labels.ts +++ b/frontend/services/entities/labels.ts @@ -49,6 +49,28 @@ const generateCreateLabelBody = ( const generateUpdateLabelBody = generateCreateLabelBody; +/** gets the custom label and returns them in case-insensitive alphabetical + * ascending order by label name. (e.g. [A, B, C, a, b, c] => [A, a, B, b, C, c]) + */ +export const getCustomLabels = ( + labels: T[] +) => { + if (labels.length === 0) { + return []; + } + + return labels + .filter((label) => label.label_type === "regular") + .sort((a, b) => { + // Found this technique here + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare + // This is a case insensitive sort + return a.name.localeCompare(b.name, undefined, { + sensitivity: "base", + }); + }); +}; + export default { create: ( formData: IDynamicLabelFormData | IManualLabelFormData From fef8bdd4a9132f74c218744970ab9a849a570b7f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 07:02:17 -0300 Subject: [PATCH 87/88] Update versions of fleetd components in Fleet's TUF [automated] (#21076) Automated change from [GitHub action](https://github.com/fleetdm/fleet/actions/workflows/fleetd-tuf.yml). Co-authored-by: lucasmrod --- orbit/TUF.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/orbit/TUF.md b/orbit/TUF.md index 634ee62b5d..229455dfc0 100644 --- a/orbit/TUF.md +++ b/orbit/TUF.md @@ -18,8 +18,8 @@ Following are the currently deployed versions of fleetd components on the `stabl | Component\OS | macOS | Linux | Windows | Linux (arm64) | |--------------|--------|--------|---------|---------------| -| orbit | 1.29.0 | 1.29.0 | 1.29.0 | 1.29.0 | -| desktop | 1.29.0 | 1.29.0 | 1.29.0 | 1.29.0 | +| orbit | 1.30.0 | 1.30.0 | 1.30.0 | 1.30.0 | +| desktop | 1.30.0 | 1.30.0 | 1.30.0 | 1.30.0 | | osqueryd | 5.13.0 | 5.13.0 | 5.13.0 | 5.13.0 | | nudge | - | - | - | - | | swiftDialog | - | - | - | - | From 4853ecbf4eaf841a48c176b77d6ec3baa96601bc Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Tue, 6 Aug 2024 07:32:24 -0300 Subject: [PATCH 88/88] Release fleetd 1.30.0 (#21071) --- .github/workflows/generate-desktop-targets.yml | 2 +- orbit/CHANGELOG.md | 4 ++++ orbit/changes/13157-fv-escrow | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 orbit/changes/13157-fv-escrow diff --git a/.github/workflows/generate-desktop-targets.yml b/.github/workflows/generate-desktop-targets.yml index d8269e9948..e3835a9ac2 100644 --- a/.github/workflows/generate-desktop-targets.yml +++ b/.github/workflows/generate-desktop-targets.yml @@ -24,7 +24,7 @@ defaults: shell: bash env: - FLEET_DESKTOP_VERSION: 1.29.0 + FLEET_DESKTOP_VERSION: 1.30.0 permissions: contents: read diff --git a/orbit/CHANGELOG.md b/orbit/CHANGELOG.md index 6596e4286f..b6f9278baa 100644 --- a/orbit/CHANGELOG.md +++ b/orbit/CHANGELOG.md @@ -1,3 +1,7 @@ +## Orbit 1.30.0 (Aug 05, 2024) + +* Use Escrow Buddy to rotate FileVault keys on macOS + ## Orbit 1.29.0 (Jul 24, 2024) * Fixed a startup bug by performing an early restart of orbit if an agent options setting has changed. diff --git a/orbit/changes/13157-fv-escrow b/orbit/changes/13157-fv-escrow deleted file mode 100644 index b4ff408b05..0000000000 --- a/orbit/changes/13157-fv-escrow +++ /dev/null @@ -1 +0,0 @@ -* Use Escrow Buddy to rotate FileVault keys on macOS