From 51709eadb6c5470772776b3de233c1b3c64731d7 Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Tue, 3 Sep 2024 15:50:43 -0400 Subject: [PATCH 1/8] Bugfix: cron startup scheduling is delayed too long if no prior run exists (#21784) --- changes/21757-fix-scheduling-cron-jobs-at-startup | 1 + server/service/schedule/schedule.go | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changes/21757-fix-scheduling-cron-jobs-at-startup diff --git a/changes/21757-fix-scheduling-cron-jobs-at-startup b/changes/21757-fix-scheduling-cron-jobs-at-startup new file mode 100644 index 000000000000..b54ae2c84f53 --- /dev/null +++ b/changes/21757-fix-scheduling-cron-jobs-at-startup @@ -0,0 +1 @@ +* Fixed an issue with the scheduling of cron jobs at startup if the job has never run, which caused it to be delayed. diff --git a/server/service/schedule/schedule.go b/server/service/schedule/schedule.go index 8965416a642e..7ca865416ab6 100644 --- a/server/service/schedule/schedule.go +++ b/server/service/schedule/schedule.go @@ -167,7 +167,13 @@ func (s *Schedule) Start() { level.Error(s.logger).Log("err", "start schedule", "details", err) ctxerr.Handle(s.ctx, err) } - s.setIntervalStartedAt(prevScheduledRun.CreatedAt) + + // if there is no previous run, set the start time to the current time. + startedAt := prevScheduledRun.CreatedAt + if startedAt.IsZero() { + startedAt = time.Now() + } + s.setIntervalStartedAt(startedAt) initialWait := 10 * time.Second if schedInterval := s.getSchedInterval(); schedInterval < initialWait { From 0091a45905593b3049301818a3c2b7e49245a350 Mon Sep 17 00:00:00 2001 From: Robert Fairburn <8029478+rfairburn@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:58:15 -0500 Subject: [PATCH 2/8] ensure that "/repo" can ever be accessed (#21788) The `/repo` path would never get hit in the order that this was previously. This corrects the behavior. --- tools/mdm/migration/mdmproxy/mdmproxy.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/mdm/migration/mdmproxy/mdmproxy.go b/tools/mdm/migration/mdmproxy/mdmproxy.go index 723db4f19f71..c59bf4b425b5 100644 --- a/tools/mdm/migration/mdmproxy/mdmproxy.go +++ b/tools/mdm/migration/mdmproxy/mdmproxy.go @@ -84,14 +84,6 @@ func (m *mdmProxy) handleProxy(w http.ResponseWriter, r *http.Request) { return } - if !strings.HasPrefix(r.URL.Path, "/mdm") { - if m.logSkipped { - log.Printf("Forbidden non-mdm request: %s %s", r.Method, r.URL.String()) - } - http.Error(w, "Forbidden", http.StatusForbidden) - return - } - // Send all micromdm repo requests to the existing server if strings.HasPrefix(r.URL.Path, "/repo") { log.Printf("%s %s -> Existing (Repo)", r.Method, r.URL.String()) @@ -100,6 +92,14 @@ func (m *mdmProxy) handleProxy(w http.ResponseWriter, r *http.Request) { } + if !strings.HasPrefix(r.URL.Path, "/mdm") { + if m.logSkipped { + log.Printf("Forbidden non-mdm request: %s %s", r.Method, r.URL.String()) + } + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + // Read the body of the request body, err := io.ReadAll(r.Body) _ = r.Body.Close() From 9f5f848cdeebf4f8d2d96d3e6390655d4f1dd6ac Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 3 Sep 2024 15:56:32 -0500 Subject: [PATCH 3/8] Website: add fixed width to Github stars button in website navigation (#21783) Closes: #21469 Changes: - Updated the styles for the GitHub stars button in the websites desktop header navigation to prevent layout shifts when navigating between pages. --- website/assets/styles/layout.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/assets/styles/layout.less b/website/assets/styles/layout.less index 94e56945a871..6eefec24a939 100644 --- a/website/assets/styles/layout.less +++ b/website/assets/styles/layout.less @@ -444,8 +444,9 @@ html, body { } } [purpose='gh-button'] { - margin-left: 20px; - margin-right: 20px; + padding: 0px 20px; + min-width: 140px; + width: 140px; } [purpose='header-dropdown'] { box-shadow: 0px 4px 40px rgba(0, 0, 0, 0.4); From 271368c72d39d12d9c6565501802cc6c6e19b5d7 Mon Sep 17 00:00:00 2001 From: Harrison Ravazzolo <38767391+harrisonravazzolo@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:01:33 -0700 Subject: [PATCH 4/8] Add Harrison to humans list (#21794) --- website/api/controllers/webhooks/receive-from-github.js | 1 + 1 file changed, 1 insertion(+) diff --git a/website/api/controllers/webhooks/receive-from-github.js b/website/api/controllers/webhooks/receive-from-github.js index 05067166ec98..4dcbad029b2c 100644 --- a/website/api/controllers/webhooks/receive-from-github.js +++ b/website/api/controllers/webhooks/receive-from-github.js @@ -90,6 +90,7 @@ module.exports = { 'ddribeiro', 'rebeccaui', 'allenhouchins', + 'harrisonravazzolo', ]; let GREEN_LABEL_COLOR = 'C2E0C6';// « Used in multiple places below. (FUTURE: Use the "+" prefix for this instead of color. 2022-05-05) From 09b6402f76332b431e16bf37c83d5913cbcb12f4 Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:35:33 -0700 Subject: [PATCH 5/8] =?UTF-8?q?UI=20=E2=80=93=20Policy=20software=20instal?= =?UTF-8?q?l=20automations=20(#21792)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Front end for #19551 Feature branch merge to `main` – all work as been previously approved in individual PRs to the feature branch. - [x] Changes file added for user-visible changes in `changes/` - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling --- changes/19551-policy-software-automations | 1 + frontend/__mocks__/policyMock.ts | 4 + frontend/components/Editor/Editor.tsx | 6 + frontend/components/Editor/_styles.scss | 1 - frontend/components/FleetAce/FleetAce.tsx | 3 + frontend/components/FleetAce/_styles.scss | 10 + .../forms/fields/Dropdown/Dropdown.jsx | 15 +- frontend/interfaces/policy.ts | 8 + frontend/interfaces/software.ts | 1 + .../AddProfileModal/AddProfileModal.tsx | 2 +- .../AdvancedOptionsModal.tsx | 2 + .../DeleteSoftwareModal.tsx | 13 +- .../SoftwarePackageCard.tsx | 112 +++---- .../SoftwarePackageCard/_styles.scss | 41 ++- .../SoftwareTitleDetailsPage.tsx | 1 + .../SoftwareTitleDetailsTable.tsx | 23 +- .../components/AddPackage/AddPackage.tsx | 25 +- .../AddPackageAdvancedOptions.tsx | 101 +++++++ .../_styles.scss | 2 +- .../AddPackageAdvancedOptions/index.ts | 1 + ...AddSoftwareForm.tsx => AddPackageForm.tsx} | 116 ++------ .../components/AddPackageForm/_styles.scss | 2 +- .../components/AddPackageForm/helpers.ts | 92 +----- .../components/AddPackageForm/index.ts | 2 +- .../AddSoftwareAdvancedOptions.tsx | 110 ------- .../AddSoftwareAdvancedOptions/index.ts | 1 - .../InstallStatusCell/InstallStatusCell.tsx | 26 +- .../SelfService/SelfService.tests.tsx | 4 +- .../SelfServiceItem/SelfServiceItem.tsx | 32 +- .../SelfService/SelfServiceItem/_styles.scss | 4 - .../ManagePoliciesPage/ManagePoliciesPage.tsx | 109 ++++++- .../policies/ManagePoliciesPage/_styles.scss | 8 +- .../CalendarEventsModal.tsx | 10 +- .../InstallSoftwareModal.tsx | 276 ++++++++++++++++++ .../InstallSoftwareModal/_styles.scss | 41 +++ .../components/InstallSoftwareModal/index.ts | 1 + .../OtherWorkflowsModal.tsx | 4 +- frontend/services/entities/software.ts | 11 +- frontend/services/entities/team_policies.ts | 2 + frontend/utilities/constants.tsx | 8 +- 40 files changed, 817 insertions(+), 414 deletions(-) create mode 100644 changes/19551-policy-software-automations create mode 100644 frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/AddPackageAdvancedOptions.tsx rename frontend/pages/SoftwarePage/components/{AddSoftwareAdvancedOptions => AddPackageAdvancedOptions}/_styles.scss (88%) create mode 100644 frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/index.ts rename frontend/pages/SoftwarePage/components/AddPackageForm/{AddSoftwareForm.tsx => AddPackageForm.tsx} (55%) delete mode 100644 frontend/pages/SoftwarePage/components/AddSoftwareAdvancedOptions/AddSoftwareAdvancedOptions.tsx delete mode 100644 frontend/pages/SoftwarePage/components/AddSoftwareAdvancedOptions/index.ts create mode 100644 frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/InstallSoftwareModal.tsx create mode 100644 frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/_styles.scss create mode 100644 frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/index.ts diff --git a/changes/19551-policy-software-automations b/changes/19551-policy-software-automations new file mode 100644 index 000000000000..4b88cb4c1fba --- /dev/null +++ b/changes/19551-policy-software-automations @@ -0,0 +1 @@ +* Implement features allowing automatic installation of software on hosts that fail policies. diff --git a/frontend/__mocks__/policyMock.ts b/frontend/__mocks__/policyMock.ts index b14095463ec6..ba60c55c74db 100644 --- a/frontend/__mocks__/policyMock.ts +++ b/frontend/__mocks__/policyMock.ts @@ -23,6 +23,10 @@ const DEFAULT_POLICY_MOCK: IPolicyStats = { has_run: true, next_update_ms: 3600000, calendar_events_enabled: true, + install_software: { + name: "testSw0", + software_title_id: 1, + }, }; const createMockPolicy = (overrides?: Partial): IPolicyStats => { diff --git a/frontend/components/Editor/Editor.tsx b/frontend/components/Editor/Editor.tsx index e8f230e3799d..b724a296c39e 100644 --- a/frontend/components/Editor/Editor.tsx +++ b/frontend/components/Editor/Editor.tsx @@ -29,6 +29,10 @@ interface IEditorProps { * @default "editor" */ name?: string; + /** Include correct styles as a form field. + * @default false + */ + isFormField?: boolean; maxLines?: number; className?: string; onChange?: (value: string, event?: any) => void; @@ -52,11 +56,13 @@ const Editor = ({ readOnly = false, wrapEnabled = false, name = "editor", + isFormField = false, maxLines = 20, className, onChange, }: IEditorProps) => { const classNames = classnames(baseClass, className, { + "form-field": isFormField, [`${baseClass}__error`]: !!error, }); diff --git a/frontend/components/Editor/_styles.scss b/frontend/components/Editor/_styles.scss index 676172697dd5..22fbacfd337c 100644 --- a/frontend/components/Editor/_styles.scss +++ b/frontend/components/Editor/_styles.scss @@ -3,7 +3,6 @@ &__label { font-size: $x-small; font-weight: $bold; - margin-bottom: $pad-small; &--error { color: $core-vibrant-red; diff --git a/frontend/components/FleetAce/FleetAce.tsx b/frontend/components/FleetAce/FleetAce.tsx index c30232cb596b..b0422d4cde21 100644 --- a/frontend/components/FleetAce/FleetAce.tsx +++ b/frontend/components/FleetAce/FleetAce.tsx @@ -29,6 +29,7 @@ export interface IFleetAceProps { label?: string; name?: string; value?: string; + placeholder?: string; readOnly?: boolean; maxLines?: number; showGutter?: boolean; @@ -55,6 +56,7 @@ const FleetAce = ({ labelActionComponent, name = "query-editor", value, + placeholder, readOnly, maxLines = 20, showGutter = true, @@ -266,6 +268,7 @@ const FleetAce = ({ showPrintMargin={false} theme="fleet" value={value} + placeholder={placeholder} width="100%" wrapEnabled={wrapEnabled} style={style} diff --git a/frontend/components/FleetAce/_styles.scss b/frontend/components/FleetAce/_styles.scss index c12237a3a771..f9f0dccf8960 100644 --- a/frontend/components/FleetAce/_styles.scss +++ b/frontend/components/FleetAce/_styles.scss @@ -25,6 +25,16 @@ } } + .ace_content { + padding-left: 4px; + } + + .ace_placeholder { + font-family: "SourceCodePro", $monospace; + margin: initial; + font-size: 15px; + } + &__help-text { @include help-text; diff --git a/frontend/components/forms/fields/Dropdown/Dropdown.jsx b/frontend/components/forms/fields/Dropdown/Dropdown.jsx index 1edde66fec07..302233e5d674 100644 --- a/frontend/components/forms/fields/Dropdown/Dropdown.jsx +++ b/frontend/components/forms/fields/Dropdown/Dropdown.jsx @@ -27,6 +27,19 @@ class Dropdown extends Component { onClose: PropTypes.func, options: PropTypes.arrayOf(dropdownOptionInterface).isRequired, placeholder: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), + /** + value must correspond to the value of a dropdown option to render + e.g. with options: + + [ + { + label: "Display name", + value: 1, <– the id of the thing + } + ] + + set value to 1, not "Display name" + */ value: PropTypes.oneOfType([ PropTypes.array, PropTypes.string, @@ -75,7 +88,7 @@ class Dropdown extends Component { const { multi, onChange, clearable, name, parseTarget } = this.props; if (parseTarget) { - // Returns both name and value + // Returns both name of the Dropdown and value of the selected option return onChange({ value: selected.value, name }); } diff --git a/frontend/interfaces/policy.ts b/frontend/interfaces/policy.ts index 41586ea22da9..621c52f63872 100644 --- a/frontend/interfaces/policy.ts +++ b/frontend/interfaces/policy.ts @@ -41,6 +41,12 @@ export interface IPolicy { updated_at: string; critical: boolean; calendar_events_enabled: boolean; + install_software?: IPolicySoftwareToInstall; +} + +export interface IPolicySoftwareToInstall { + name: string; + software_title_id: number; } // Used on the manage hosts page and other places where aggregate stats are displayed @@ -94,6 +100,8 @@ export interface IPolicyFormData { team_id?: number | null; id?: number; calendar_events_enabled?: boolean; + // undefined from GET/LIST when not set, null for PATCH to unset + software_title_id?: number | null; } export interface IPolicyNew { diff --git a/frontend/interfaces/software.ts b/frontend/interfaces/software.ts index bf6ba786a17e..9d6d3617b2fb 100644 --- a/frontend/interfaces/software.ts +++ b/frontend/interfaces/software.ts @@ -109,6 +109,7 @@ export interface ISoftwareTitleDetails { source: string; // "apps" | "ios_apps" | "ipados_apps" | ? hosts_count: number; versions: ISoftwareTitleVersion[] | null; + versions_updated_at?: string; bundle_identifier?: string; browser?: string; versions_count?: number; 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 12191a96418f..694970c4ca1a 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 @@ -77,7 +77,7 @@ interface IFileDetailsProps { // TODO: if we reuse this one more time, we should consider moving this // into FileUploader as a default preview. Currently we have this in -// AddSoftwareForm.tsx and here. +// AddPackageForm.tsx and here. const FileDetails = ({ details: { name, platform } }: IFileDetailsProps) => (
diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/AdvancedOptionsModal/AdvancedOptionsModal.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/AdvancedOptionsModal/AdvancedOptionsModal.tsx index b3f7c31146b5..5cfc313e4416 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/AdvancedOptionsModal/AdvancedOptionsModal.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/AdvancedOptionsModal/AdvancedOptionsModal.tsx @@ -38,6 +38,7 @@ const AdvancedOptionsModal = ({ helpText="Fleet will run this command on hosts to install software." label="Install script" labelTooltip="For security agents, add the script provided by the vendor." + isFormField /> {preInstallQuery && (
@@ -72,6 +73,7 @@ const AdvancedOptionsModal = ({ maxLines={10} value={postInstallScript} helpText="Shell (macOS and Linux) or PowerShell (Windows)." + isFormField />
)} diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx index 23d03c58521c..fa75f1d5541d 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx @@ -3,11 +3,15 @@ import React, { useCallback, useContext } from "react"; import softwareAPI from "services/entities/software"; import { NotificationContext } from "context/notification"; +import { getErrorReason } from "interfaces/errors"; + import Modal from "components/Modal"; import Button from "components/buttons/Button"; const baseClass = "delete-software-modal"; +const DELETE_SW_USED_BY_POLICY_ERROR_MSG = + "Couldn't delete. Policy automation uses this software. Please disable policy automation for this software and try again."; interface IDeleteSoftwareModalProps { softwareId: number; teamId: number; @@ -28,8 +32,13 @@ const DeleteSoftwareModal = ({ await softwareAPI.deleteSoftwarePackage(softwareId, teamId); renderFlash("success", "Software deleted successfully!"); onSuccess(); - } catch { - renderFlash("error", "Couldn't delete. Please try again."); + } catch (error) { + const reason = getErrorReason(error); + if (reason.includes("Policy automation uses this software")) { + renderFlash("error", DELETE_SW_USED_BY_POLICY_ERROR_MSG); + } else { + renderFlash("error", "Couldn't delete. Please try again."); + } } onExit(); }, [softwareId, teamId, renderFlash, onSuccess, onExit]); diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwarePackageCard/SoftwarePackageCard.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwarePackageCard/SoftwarePackageCard.tsx index 8453abfbb6bf..1c6a31e9d769 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwarePackageCard/SoftwarePackageCard.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwarePackageCard/SoftwarePackageCard.tsx @@ -4,8 +4,6 @@ import React, { useLayoutEffect, useState, } from "react"; -import FileSaver from "file-saver"; -import { parse } from "content-disposition"; import PATHS from "router/paths"; import { AppContext } from "context/app"; @@ -45,10 +43,15 @@ function useTruncatedElement(ref: React.RefObject) { useLayoutEffect(() => { const element = ref.current; - if (element) { - const { scrollWidth, clientWidth } = element; - setIsTruncated(scrollWidth > clientWidth); + function updateIsTruncated() { + if (element) { + const { scrollWidth, clientWidth } = element; + setIsTruncated(scrollWidth > clientWidth); + } } + window.addEventListener("resize", updateIsTruncated); + updateIsTruncated(); + return () => window.removeEventListener("resize", updateIsTruncated); }, [ref]); return isTruncated; @@ -92,20 +95,29 @@ const STATUS_DISPLAY_OPTIONS: Record< iconName: "success", tooltip: ( <> - Fleet installed software on these hosts. Currently, if the software is - uninstalled, the "Installed" status won't be updated. + Software is installed on these hosts (install script finished +
+ with exit code 0). Currently, if the software is uninstalled, the +
+ "installed" status won't be updated. ), }, pending: { displayName: "Pending", iconName: "pending-outline", - tooltip: "Fleet will install software when these hosts come online.", + tooltip: "Fleet is installing or will install when the host comes online.", }, failed: { displayName: "Failed", iconName: "error", - tooltip: "Fleet failed to install software on these hosts.", + tooltip: ( + <> + These hosts failed to install software. Click on a host to view +
+ error(s). + + ), }, }; @@ -130,16 +142,18 @@ const PackageStatusCount = ({ })}`; return (
- {displayData.displayName} +
{displayData.displayName}
} @@ -305,7 +319,7 @@ const SoftwarePackageCard = ({ return ( -
+
{/* TODO: main-info could be a seperate component as its reused on a couple pages already. Come back and pull this into a component */}
@@ -315,46 +329,46 @@ const SoftwarePackageCard = ({ {renderDetails()}
-
- - - +
+ {isSelfService && ( +
+ + Self-service +
+ )} + {showActions && ( + + )}
-
- {isSelfService && ( -
- - Self-service -
- )} - {showActions && ( - - )} +
+ + +
{showAdvancedOptionsModal && ( diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx index 4eb9660e625a..6eaafa2a28e0 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx @@ -13,6 +13,7 @@ import TableContainer from "components/TableContainer"; import TableCount from "components/TableContainer/TableCount"; import EmptyTable from "components/EmptyTable"; import CustomLink from "components/CustomLink"; +import LastUpdatedText from "components/LastUpdatedText"; import generateSoftwareTitleDetailsTableConfig from "./SoftwareTitleDetailsTableConfig"; @@ -21,6 +22,21 @@ const DEFAULT_SORT_DIRECTION = "desc"; const baseClass = "software-title-details-table"; +const SoftwareLastUpdatedInfo = (lastUpdatedAt: string) => { + return ( + + The last time software data was
+ updated, including vulnerabilities
+ and host counts. + + } + /> + ); +}; + const NoVersionsDetected = (isAvailableForInstall = false): JSX.Element => { return ( { const handleRowSelect = (row: IRowProps) => { const hostsBySoftwareParams = { @@ -95,7 +113,10 @@ const SoftwareTitleDetailsTable = ({ ); const renderVersionsCount = () => ( - + <> + + {countsUpdatedAt && SoftwareLastUpdatedInfo(countsUpdatedAt)} + ); return ( diff --git a/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx b/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx index 2e7e4b17a566..52cb805f7f46 100644 --- a/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx +++ b/frontend/pages/SoftwarePage/components/AddPackage/AddPackage.tsx @@ -1,13 +1,19 @@ import React, { useContext, useEffect, useState } from "react"; import { InjectedRouter } from "react-router"; +import { getErrorReason } from "interfaces/errors"; + import PATHS from "router/paths"; import { NotificationContext } from "context/notification"; import softwareAPI from "services/entities/software"; import { QueryParams, buildQueryStringFromParams } from "utilities/url"; +import { LEARN_MORE_ABOUT_BASE_LINK } from "utilities/constants"; + +import CustomLink from "components/CustomLink"; + import AddPackageForm from "../AddPackageForm"; -import { IAddSoftwareFormData } from "../AddPackageForm/AddSoftwareForm"; +import { IAddPackageFormData } from "../AddPackageForm/AddPackageForm"; import { getErrorMessage } from "../AddSoftwareModal/helpers"; const baseClass = "add-package"; @@ -60,7 +66,7 @@ const AddPackage = ({ }; }, [isUploading]); - const onAddPackage = async (formData: IAddSoftwareFormData) => { + const onAddPackage = async (formData: IAddPackageFormData) => { setIsUploading(true); if (formData.software && formData.software.size > MAX_FILE_SIZE_BYTES) { @@ -98,6 +104,21 @@ const AddPackage = ({ `${PATHS.SOFTWARE_TITLES}?${buildQueryStringFromParams(newQueryParams)}` ); } catch (e) { + const reason = getErrorReason(e); + if ( + reason.includes("Couldn't add. Fleet couldn't read the version from") + ) { + renderFlash( + "error", + `${reason}. ${( + + )} ` + ); + } renderFlash("error", getErrorMessage(e)); } diff --git a/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/AddPackageAdvancedOptions.tsx b/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/AddPackageAdvancedOptions.tsx new file mode 100644 index 000000000000..5d6524e8dce1 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/AddPackageAdvancedOptions.tsx @@ -0,0 +1,101 @@ +import React, { useState } from "react"; + +import Editor from "components/Editor"; +import CustomLink from "components/CustomLink"; +import FleetAce from "components/FleetAce"; +import RevealButton from "components/buttons/RevealButton"; + +const baseClass = "add-package-advanced-options"; + +interface IAddPackageAdvancedOptionsProps { + errors: { preInstallQuery?: string; postInstallScript?: string }; + preInstallQuery?: string; + installScript: string; + postInstallScript?: string; + onChangePreInstallQuery: (value?: string) => void; + onChangeInstallScript: (value: string) => void; + onChangePostInstallScript: (value?: string) => void; +} + +const AddPackageAdvancedOptions = ({ + errors, + preInstallQuery, + installScript, + postInstallScript, + onChangePreInstallQuery, + onChangeInstallScript, + onChangePostInstallScript, +}: IAddPackageAdvancedOptionsProps) => { + const [showAdvancedOptions, setShowAdvancedOptions] = useState(false); + + return ( +
+ setShowAdvancedOptions(!showAdvancedOptions)} + /> + {showAdvancedOptions && ( +
+ + Software will be installed only if the{" "} + + + } + /> + + Fleet will run this script on hosts to install software. Use the +
+ $INSTALLER_PATH variable to point to the installer. + + } + isFormField + /> + +
+ )} +
+ ); +}; + +export default AddPackageAdvancedOptions; diff --git a/frontend/pages/SoftwarePage/components/AddSoftwareAdvancedOptions/_styles.scss b/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/_styles.scss similarity index 88% rename from frontend/pages/SoftwarePage/components/AddSoftwareAdvancedOptions/_styles.scss rename to frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/_styles.scss index 58f1f85892b9..0728e3241560 100644 --- a/frontend/pages/SoftwarePage/components/AddSoftwareAdvancedOptions/_styles.scss +++ b/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/_styles.scss @@ -1,4 +1,4 @@ -.add-software-advanced-options { +.add-package-advanced-options { display: flex; flex-direction: column; align-items: flex-start; diff --git a/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/index.ts b/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/index.ts new file mode 100644 index 000000000000..004c96332d47 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/AddPackageAdvancedOptions/index.ts @@ -0,0 +1 @@ +export { default } from "./AddPackageAdvancedOptions"; diff --git a/frontend/pages/SoftwarePage/components/AddPackageForm/AddSoftwareForm.tsx b/frontend/pages/SoftwarePage/components/AddPackageForm/AddPackageForm.tsx similarity index 55% rename from frontend/pages/SoftwarePage/components/AddPackageForm/AddSoftwareForm.tsx rename to frontend/pages/SoftwarePage/components/AddPackageForm/AddPackageForm.tsx index aab97985d0d0..cf3802b3f6f8 100644 --- a/frontend/pages/SoftwarePage/components/AddPackageForm/AddSoftwareForm.tsx +++ b/frontend/pages/SoftwarePage/components/AddPackageForm/AddPackageForm.tsx @@ -6,7 +6,6 @@ import getInstallScript from "utilities/software_install_scripts"; import Button from "components/buttons/Button"; import Checkbox from "components/forms/fields/Checkbox"; -import Editor from "components/Editor"; import { FileUploader, FileDetails, @@ -14,25 +13,25 @@ import { import Spinner from "components/Spinner"; import TooltipWrapper from "components/TooltipWrapper"; -import AddSoftwareAdvancedOptions from "../AddSoftwareAdvancedOptions"; +import AddPackageAdvancedOptions from "../AddPackageAdvancedOptions"; import { generateFormValidation } from "./helpers"; -export const baseClass = "add-software-form"; +export const baseClass = "add-package-form"; const UploadingSoftware = () => { return (
-

Uploading. It may take a few minutes to finish.

+

Adding software. This may take a few minutes to finish.

); }; -export interface IAddSoftwareFormData { +export interface IAddPackageFormData { software: File | null; installScript: string; - preInstallCondition?: string; + preInstallQuery?: string; postInstallScript?: string; selfService: boolean; } @@ -40,30 +39,28 @@ export interface IAddSoftwareFormData { export interface IFormValidation { isValid: boolean; software: { isValid: boolean }; - preInstallCondition?: { isValid: boolean; message?: string }; + preInstallQuery?: { isValid: boolean; message?: string }; postInstallScript?: { isValid: boolean; message?: string }; selfService?: { isValid: boolean }; } -interface IAddSoftwareFormProps { +interface IAddPackageFormProps { isUploading: boolean; onCancel: () => void; - onSubmit: (formData: IAddSoftwareFormData) => void; + onSubmit: (formData: IAddPackageFormData) => void; } -const AddSoftwareForm = ({ +const AddPackageForm = ({ isUploading, onCancel, onSubmit, -}: IAddSoftwareFormProps) => { +}: IAddPackageFormProps) => { const { renderFlash } = useContext(NotificationContext); - const [showPreInstallCondition, setShowPreInstallCondition] = useState(false); - const [showPostInstallScript, setShowPostInstallScript] = useState(false); - const [formData, setFormData] = useState({ + const [formData, setFormData] = useState({ software: null, installScript: "", - preInstallCondition: undefined, + preInstallQuery: undefined, postInstallScript: undefined, selfService: false, }); @@ -90,13 +87,7 @@ const AddSoftwareForm = ({ installScript, }; setFormData(newData); - setFormValidation( - generateFormValidation( - newData, - showPreInstallCondition, - showPostInstallScript - ) - ); + setFormValidation(generateFormValidation(newData)); } }; @@ -105,62 +96,26 @@ const AddSoftwareForm = ({ onSubmit(formData); }; - const onTogglePreInstallConditionCheckbox = (value: boolean) => { - const newData = { ...formData, preInstallCondition: undefined }; - setShowPreInstallCondition(value); - setFormData(newData); - setFormValidation( - generateFormValidation(newData, value, showPostInstallScript) - ); - }; - - const onTogglePostInstallScriptCheckbox = (value: boolean) => { - const newData = { ...formData, postInstallScript: undefined }; - setShowPostInstallScript(value); - setFormData(newData); - setFormValidation( - generateFormValidation(newData, showPreInstallCondition, value) - ); - }; - const onChangeInstallScript = (value: string) => { setFormData({ ...formData, installScript: value }); }; - const onChangePreInstallCondition = (value?: string) => { - const newData = { ...formData, preInstallCondition: value }; + const onChangePreInstallQuery = (value?: string) => { + const newData = { ...formData, preInstallQuery: value }; setFormData(newData); - setFormValidation( - generateFormValidation( - newData, - showPreInstallCondition, - showPostInstallScript - ) - ); + setFormValidation(generateFormValidation(newData)); }; const onChangePostInstallScript = (value?: string) => { const newData = { ...formData, postInstallScript: value }; setFormData(newData); - setFormValidation( - generateFormValidation( - newData, - showPreInstallCondition, - showPostInstallScript - ) - ); + setFormValidation(generateFormValidation(newData)); }; const onToggleSelfServiceCheckbox = (value: boolean) => { const newData = { ...formData, selfService: value }; setFormData(newData); - setFormValidation( - generateFormValidation( - newData, - showPreInstallCondition, - showPostInstallScript - ) - ); + setFormValidation(generateFormValidation(newData)); }; const isSubmitDisabled = !formValidation.isValid; @@ -185,25 +140,6 @@ const AddSoftwareForm = ({ ) } /> - {formData.software && ( - - For security agents, add the script provided by the vendor. -
- In custom scripts, you can use the $INSTALLER_PATH variable to - point to the installer. - - } - /> - )} -
-
+ ); })} -
+ A calendar event will be created for end users if one of their hosts fail any of these policies.{" "} diff --git a/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/InstallSoftwareModal.tsx b/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/InstallSoftwareModal.tsx new file mode 100644 index 000000000000..7c29b4979f3b --- /dev/null +++ b/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/InstallSoftwareModal.tsx @@ -0,0 +1,276 @@ +import React, { useCallback, useState } from "react"; + +import { useQuery } from "react-query"; +import { omit } from "lodash"; + +import { IPolicyStats } from "interfaces/policy"; +import softwareAPI, { + ISoftwareTitlesQueryKey, + ISoftwareTitlesResponse, +} from "services/entities/software"; +import { DEFAULT_USE_QUERY_OPTIONS } from "utilities/constants"; + +// @ts-ignore +import Dropdown from "components/forms/fields/Dropdown"; +import Modal from "components/Modal"; +import DataError from "components/DataError"; +import Spinner from "components/Spinner"; +import Checkbox from "components/forms/fields/Checkbox"; +import TooltipTruncatedText from "components/TooltipTruncatedText"; +import CustomLink from "components/CustomLink"; +import Button from "components/buttons/Button"; +import { ISoftwareTitle } from "interfaces/software"; + +const getPlatformDisplayFromPackageSuffix = (packageName: string) => { + const split = packageName.split("."); + const suff = split[split.length - 1]; + switch (suff) { + case "pkg": + return "macOS"; + case "deb": + return "Linux"; + case "exe": + return "Windows"; + case "msi": + return "Windows"; + default: + return null; + } +}; + +const AFI_SOFTWARE_BATCH_SIZE = 1000; + +const baseClass = "install-software-modal"; + +interface ISwDropdownField { + name: string; + value: number; +} +interface IFormPolicy { + name: string; + id: number; + installSoftwareEnabled: boolean; + swIdToInstall?: number; +} + +export type IInstallSoftwareFormData = IFormPolicy[]; + +interface IInstallSoftwareModal { + onExit: () => void; + onSubmit: (formData: IInstallSoftwareFormData) => void; + isUpdating: boolean; + policies: IPolicyStats[]; + teamId: number; +} +const InstallSoftwareModal = ({ + onExit, + onSubmit, + isUpdating, + policies, + teamId, +}: IInstallSoftwareModal) => { + const [formData, setFormData] = useState( + policies.map((policy) => ({ + name: policy.name, + id: policy.id, + installSoftwareEnabled: !!policy.install_software, + swIdToInstall: policy.install_software?.software_title_id, + })) + ); + + const anyPolicyEnabledWithoutSelectedSoftware = formData.some( + (policy) => policy.installSoftwareEnabled && !policy.swIdToInstall + ); + const { + data: titlesAFI, + isLoading: isTitlesAFILoading, + isError: isTitlesAFIError, + } = useQuery< + ISoftwareTitlesResponse, + Error, + ISoftwareTitle[], + [ISoftwareTitlesQueryKey] + >( + [ + { + scope: "software-titles", + page: 0, + perPage: AFI_SOFTWARE_BATCH_SIZE, + query: "", + orderDirection: "desc", + orderKey: "hosts_count", + teamId, + availableForInstall: true, + packagesOnly: true, + }, + ], + ({ queryKey: [queryKey] }) => + softwareAPI.getSoftwareTitles(omit(queryKey, "scope")), + { + select: (data) => data.software_titles, + ...DEFAULT_USE_QUERY_OPTIONS, + } + ); + + const onUpdateInstallSoftware = useCallback(() => { + onSubmit(formData); + }, [formData, onSubmit]); + + const onChangeEnableInstallSoftware = useCallback( + (newVal: { policyName: string; value: boolean }) => { + const { policyName, value } = newVal; + setFormData( + formData.map((policy) => { + if (policy.name === policyName) { + return { + ...policy, + installSoftwareEnabled: value, + swIdToInstall: value ? policy.swIdToInstall : undefined, + }; + } + return policy; + }) + ); + }, + [formData] + ); + + const onSelectPolicySoftware = useCallback( + ({ name, value }: ISwDropdownField) => { + const [policyName, softwareId] = [name, value]; + setFormData( + formData.map((policy) => { + if (policy.name === policyName) { + return { ...policy, swIdToInstall: softwareId }; + } + return policy; + }) + ); + }, + [formData] + ); + + const availableSoftwareOptions = titlesAFI?.map((title) => { + const platformDisplay = getPlatformDisplayFromPackageSuffix( + title.software_package?.name ?? "" + ); + const platformString = platformDisplay ? `${platformDisplay} • ` : ""; + return { + label: title.name, + value: title.id, + helpText: `${platformString}${title.software_package?.version ?? ""}`, + }; + }); + + const renderPolicySwInstallOption = (policy: IFormPolicy) => { + const { + name: policyName, + id: policyId, + installSoftwareEnabled: enabled, + swIdToInstall, + } = policy; + + return ( +
  • + { + onChangeEnableInstallSoftware({ + policyName, + value: !enabled, + }); + }} + > + + + {enabled && ( + + )} +
  • + ); + }; + + const renderContent = () => { + if (isTitlesAFIError) { + return ; + } + if (isTitlesAFILoading) { + return ; + } + if (!titlesAFI?.length) { + return ( +
    + No software available for install + + Go to Software to add software to this team. + +
    + ); + } + + return ( +
    +
    +
    Policies:
    +
      + {formData.map((policyData) => + renderPolicySwInstallOption(policyData) + )} +
    + + Selected software will be installed when hosts fail the chosen + policy.{" "} + + +
    +
    + + +
    +
    + ); + }; + + return ( + + {renderContent()} + + ); +}; + +export default InstallSoftwareModal; diff --git a/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/_styles.scss b/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/_styles.scss new file mode 100644 index 000000000000..de9cfc05be59 --- /dev/null +++ b/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/_styles.scss @@ -0,0 +1,41 @@ +.manage-policies-page { + .install-software-modal { + .form-field--dropdown { + width: 276px; + .Select-placeholder { + color: $ui-fleet-black-50; + } + .Select-menu { + max-height: none; + overflow: visible; + } + .Select-menu-outer { + max-height: 240px; + overflow-y: auto; + } + } + .policy-row { + height: 40px; + padding-top: 4px; + padding-bottom: 4px; + } + + &__no-software { + display: flex; + height: 178px; + flex-direction: column; + align-items: center; + gap: $pad-small; + justify-content: center; + font-size: $small; + + span { + color: $ui-fleet-black-75; + font-size: $xx-small; + } + } + .data-error { + padding: 78px; + } + } +} diff --git a/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/index.ts b/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/index.ts new file mode 100644 index 000000000000..a9f46a726a03 --- /dev/null +++ b/frontend/pages/policies/ManagePoliciesPage/components/InstallSoftwareModal/index.ts @@ -0,0 +1 @@ +export { default } from "./InstallSoftwareModal"; diff --git a/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx b/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx index d34ae56ff60f..7a9668e82544 100644 --- a/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx +++ b/frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx @@ -416,8 +416,8 @@ const OtherWorkflowsModal = ({ const { isChecked, name, id } = policyItem; return (
    { @@ -220,8 +219,8 @@ export default { formData.append("software", data.software); formData.append("self_service", data.selfService.toString()); data.installScript && formData.append("install_script", data.installScript); - data.preInstallCondition && - formData.append("pre_install_query", data.preInstallCondition); + data.preInstallQuery && + formData.append("pre_install_query", data.preInstallQuery); data.postInstallScript && formData.append("post_install_script", data.postInstallScript); teamId && formData.append("team_id", teamId.toString()); diff --git a/frontend/services/entities/team_policies.ts b/frontend/services/entities/team_policies.ts index a10d954e8b00..d2e13863729b 100644 --- a/frontend/services/entities/team_policies.ts +++ b/frontend/services/entities/team_policies.ts @@ -86,6 +86,7 @@ export default { platform, critical, calendar_events_enabled, + software_title_id, } = data; const { TEAMS } = endpoints; const path = `${TEAMS}/${team_id}/policies/${id}`; @@ -98,6 +99,7 @@ export default { platform, critical, calendar_events_enabled, + software_title_id, }); }, destroy: (teamId: number | undefined, ids: number[]) => { diff --git a/frontend/utilities/constants.tsx b/frontend/utilities/constants.tsx index c399b5e9c107..4b780aebc98c 100644 --- a/frontend/utilities/constants.tsx +++ b/frontend/utilities/constants.tsx @@ -60,9 +60,13 @@ export const HOST_STATUS_WEBHOOK_WINDOW_DROPDOWN_OPTIONS: IDropdownOption[] = [ export const GITHUB_NEW_ISSUE_LINK = "https://github.com/fleetdm/fleet/issues/new?assignees=&labels=bug%2C%3Areproduce&template=bug-report.md"; -export const SUPPORT_LINK = "https://fleetdm.com/support"; +export const FLEET_WEBSITE_URL = "https://fleetdm.com"; -export const CONTACT_FLEET_LINK = "https://fleetdm.com/contact"; +export const SUPPORT_LINK = `${FLEET_WEBSITE_URL}/support`; + +export const CONTACT_FLEET_LINK = `${FLEET_WEBSITE_URL}/contact`; + +export const LEARN_MORE_ABOUT_BASE_LINK = `${FLEET_WEBSITE_URL}/learn-more-about`; /** July 28, 2016 is the date of the initial commit to fleet/fleet. */ export const INITIAL_FLEET_DATE = "2016-07-28T00:00:00Z"; From 6a5c515dc4aa19d62d5dd431b9ce33c748608e4e Mon Sep 17 00:00:00 2001 From: Lucas Manuel Rodriguez Date: Tue, 3 Sep 2024 20:49:50 -0300 Subject: [PATCH 6/8] Attempt to use `go.mod` version instead of hidden Github var (#21768) Done as part of oncall improvements. `vars.GO_VERSION` can only be changed by admins and it's not public (Fleet devs don't know the current value of the variable), this approach uses the version specified in our `go.mod` file. --- ...ild-and-check-fleetctl-docker-and-deps.yml | 2 +- .github/workflows/build-binaries.yaml | 8 ++-- .github/workflows/build-orbit.yaml | 2 +- .github/workflows/check-automated-doc.yml | 9 ++-- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/deploy-fleet-website.yml | 2 +- .github/workflows/dogfood-deploy.yml | 5 ++- .github/workflows/fleet-and-orbit.yml | 42 +++++++------------ .github/workflows/fleetctl-preview-latest.yml | 9 ++-- .github/workflows/fleetd-tuf.yml | 10 ++--- .../workflows/generate-desktop-targets.yml | 32 +++++++------- .github/workflows/golangci-lint.yml | 3 +- .github/workflows/goreleaser-fleet.yaml | 2 +- .github/workflows/goreleaser-orbit.yaml | 8 ++-- .../workflows/goreleaser-snapshot-fleet.yaml | 2 +- .github/workflows/integration.yml | 8 ++-- .../release-fleetctl-docker-deps.yaml | 8 ++-- .github/workflows/release-fleetd-base.yml | 10 ++--- .github/workflows/test-db-changes.yml | 9 ++-- .github/workflows/test-go.yaml | 3 +- .../test-native-tooling-packaging.yml | 9 ++-- .github/workflows/test-packaging.yml | 9 ++-- .github/workflows/test-yml-specs.yml | 9 ++-- handbook/engineering/README.md | 3 +- 24 files changed, 97 insertions(+), 109 deletions(-) diff --git a/.github/workflows/build-and-check-fleetctl-docker-and-deps.yml b/.github/workflows/build-and-check-fleetctl-docker-and-deps.yml index 50f4e58f13ae..ff20260409ac 100644 --- a/.github/workflows/build-and-check-fleetctl-docker-and-deps.yml +++ b/.github/workflows/build-and-check-fleetctl-docker-and-deps.yml @@ -47,7 +47,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' - name: Install Go Dependencies run: make deps-go diff --git a/.github/workflows/build-binaries.yaml b/.github/workflows/build-binaries.yaml index ed18437c74a5..278f958b2842 100644 --- a/.github/workflows/build-binaries.yaml +++ b/.github/workflows/build-binaries.yaml @@ -29,10 +29,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' # Set the Node.js version - name: Set up Node.js ${{ vars.NODE_VERSION }} @@ -40,9 +43,6 @@ jobs: with: node-version: ${{ vars.NODE_VERSION }} - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - name: JS Dependency Cache id: js-cache uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v2 diff --git a/.github/workflows/build-orbit.yaml b/.github/workflows/build-orbit.yaml index 09f296aece9e..002d2657f6ed 100644 --- a/.github/workflows/build-orbit.yaml +++ b/.github/workflows/build-orbit.yaml @@ -59,7 +59,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' - name: Build, codesign and notarize orbit run: go run ./orbit/tools/build/build.go diff --git a/.github/workflows/check-automated-doc.yml b/.github/workflows/check-automated-doc.yml index c654e7ae4fdc..d289c55318de 100644 --- a/.github/workflows/check-automated-doc.yml +++ b/.github/workflows/check-automated-doc.yml @@ -36,15 +36,16 @@ jobs: with: egress-policy: audit - - name: Install Go - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 - with: - go-version: ${{ vars.GO_VERSION }} - name: Checkout Code uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2 with: fetch-depth: 0 + - name: Install Go + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + with: + go-version-file: 'go.mod' + - name: Verify golang generated documentation is up-to-date run: | make generate-doc diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 246c6418a170..c69888f874db 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/deploy-fleet-website.yml b/.github/workflows/deploy-fleet-website.yml index 9fc044e13b3f..371a0014f075 100644 --- a/.github/workflows/deploy-fleet-website.yml +++ b/.github/workflows/deploy-fleet-website.yml @@ -64,7 +64,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' # Download top-level dependencies and build Storybook in the website's assets/ folder - run: npm install --legacy-peer-deps && npm run build-storybook -- -o ./website/assets/storybook --loglevel verbose diff --git a/.github/workflows/dogfood-deploy.yml b/.github/workflows/dogfood-deploy.yml index f9d8cff07156..f17768eec7c5 100644 --- a/.github/workflows/dogfood-deploy.yml +++ b/.github/workflows/dogfood-deploy.yml @@ -51,14 +51,17 @@ jobs: - id: fail-on-main run: "false" if: ${{ github.ref == 'main' }} + - uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # v1.7.0 with: role-to-assume: ${{env.AWS_IAM_ROLE}} aws-region: ${{ env.AWS_REGION }} + - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' + - uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3 with: terraform_version: 1.6.3 diff --git a/.github/workflows/fleet-and-orbit.yml b/.github/workflows/fleet-and-orbit.yml index 571d59d067e0..f4dfb2780eb7 100644 --- a/.github/workflows/fleet-and-orbit.yml +++ b/.github/workflows/fleet-and-orbit.yml @@ -62,7 +62,6 @@ jobs: timeout-minutes: 60 strategy: matrix: - go-version: ["${{ vars.GO_VERSION }}"] mysql: ["mysql:8.0.36"] runs-on: ubuntu-latest needs: gen @@ -72,10 +71,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} + go-version-file: 'go.mod' # Set the Node.js version - name: Set up Node.js ${{ vars.NODE_VERSION }} @@ -83,9 +85,6 @@ jobs: with: node-version: ${{ vars.NODE_VERSION }} - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - name: Start tunnel env: CERT_PEM: ${{ secrets.CLOUDFLARE_TUNNEL_FLEETUEM_CERT_B64 }} @@ -175,9 +174,6 @@ jobs: # This job also makes sure the Fleet server is up and running. set-enroll-secret: timeout-minutes: 60 - strategy: - matrix: - go-version: ["${{ vars.GO_VERSION }}"] runs-on: ubuntu-latest needs: gen steps: @@ -186,13 +182,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Build Fleetctl run: make fleetctl @@ -218,9 +214,6 @@ jobs: # Here we generate the Fleet Desktop and osqueryd targets for # macOS which can only be generated from a macOS host. build-macos-targets: - strategy: - matrix: - go-version: ["${{ vars.GO_VERSION }}"] # Set macOS version to '12' (current equivalent to macos-latest) for # building the binary. This ensures compatibility with macOS version 13 and # later, avoiding runtime errors on systems using macOS 13 or newer. @@ -234,13 +227,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Build desktop.app.tar.gz and osqueryd.app.tar.gz run: | @@ -269,9 +262,6 @@ jobs: # installed, and installing it is time consuming and unreliable. run-tuf-and-gen-pkgs: timeout-minutes: 60 - strategy: - matrix: - go-version: ["${{ vars.GO_VERSION }}"] runs-on: ubuntu-latest needs: [gen, build-macos-targets] steps: @@ -280,13 +270,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Download macos pre-built apps id: download diff --git a/.github/workflows/fleetctl-preview-latest.yml b/.github/workflows/fleetctl-preview-latest.yml index dda4e0f73c2d..630cfd1dc325 100644 --- a/.github/workflows/fleetctl-preview-latest.yml +++ b/.github/workflows/fleetctl-preview-latest.yml @@ -53,7 +53,6 @@ jobs: # - Unattended installation of Docker on macOS fails. (see # https://github.com/docker/for-mac/issues/6450) os: [ubuntu-latest] - go-version: ['${{ vars.GO_VERSION }}'] runs-on: ${{ matrix.os }} steps: @@ -62,13 +61,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Build Fleetctl run: make fleetctl diff --git a/.github/workflows/fleetd-tuf.yml b/.github/workflows/fleetd-tuf.yml index ebeca889daa1..7641589f102b 100644 --- a/.github/workflows/fleetd-tuf.yml +++ b/.github/workflows/fleetd-tuf.yml @@ -30,16 +30,16 @@ jobs: with: egress-policy: audit - - name: Install Go - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 - with: - go-version: ${{ vars.GO_VERSION }} - - name: Checkout Code uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2 with: fetch-depth: 0 + - name: Install Go + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + with: + go-version-file: 'go.mod' + - name: Update orbit/TUF.md run: | make fleetd-tuf diff --git a/.github/workflows/generate-desktop-targets.yml b/.github/workflows/generate-desktop-targets.yml index 67313ea76286..d7324c9bf0ba 100644 --- a/.github/workflows/generate-desktop-targets.yml +++ b/.github/workflows/generate-desktop-targets.yml @@ -45,13 +45,13 @@ jobs: with: egress-policy: audit + - name: Checkout + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} - - - name: Checkout - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Import signing keys env: @@ -98,13 +98,13 @@ jobs: with: egress-policy: audit + - name: Checkout + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} - - - name: Checkout - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Generate fleet-desktop.exe run: | @@ -139,13 +139,13 @@ jobs: with: egress-policy: audit + - name: Checkout + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} - - - name: Checkout - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Generate desktop.tar.gz run: | @@ -167,13 +167,13 @@ jobs: with: egress-policy: audit + - name: Checkout + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} - - - name: Checkout - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Generate desktop.tar.gz run: | diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index df6b9792b73d..3d3e95ed2c8c 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -38,7 +38,6 @@ jobs: matrix: # See #9943, we just need to add windows-latest here once all issues are fixed. os: [ubuntu-latest, macos-latest] - go-version: ['${{ vars.GO_VERSION }}'] runs-on: ${{ matrix.os }} steps: - name: Harden Runner @@ -52,7 +51,7 @@ jobs: - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} + go-version-file: 'go.mod' - name: Install dependencies (Linux) if: matrix.os == 'ubuntu-latest' diff --git a/.github/workflows/goreleaser-fleet.yaml b/.github/workflows/goreleaser-fleet.yaml index f4224907e0fa..6ba9aff8f08f 100644 --- a/.github/workflows/goreleaser-fleet.yaml +++ b/.github/workflows/goreleaser-fleet.yaml @@ -44,7 +44,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' # Set the Node.js version - name: Set up Node.js ${{ vars.NODE_VERSION }} diff --git a/.github/workflows/goreleaser-orbit.yaml b/.github/workflows/goreleaser-orbit.yaml index 666f28112051..54e16752b335 100644 --- a/.github/workflows/goreleaser-orbit.yaml +++ b/.github/workflows/goreleaser-orbit.yaml @@ -56,7 +56,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' - name: Run GoReleaser run: go run github.com/goreleaser/goreleaser@56c9d09a1b925e2549631c6d180b0a1c2ebfac82 release --debug --rm-dist --skip-publish -f orbit/goreleaser-macos.yml # v1.20.0 @@ -95,7 +95,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' - name: Run GoReleaser run: go run github.com/goreleaser/goreleaser@56c9d09a1b925e2549631c6d180b0a1c2ebfac82 release --debug --rm-dist --skip-publish -f orbit/goreleaser-linux.yml # v1.20.0 @@ -128,7 +128,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' - name: Run GoReleaser run: go run github.com/goreleaser/goreleaser@56c9d09a1b925e2549631c6d180b0a1c2ebfac82 release --debug --rm-dist --skip-publish -f orbit/goreleaser-linux-arm64.yml # v1.20.0 @@ -161,7 +161,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' - name: Run GoReleaser run: go run github.com/goreleaser/goreleaser@56c9d09a1b925e2549631c6d180b0a1c2ebfac82 release --debug --rm-dist --skip-publish -f orbit/goreleaser-windows.yml # v1.20.0 diff --git a/.github/workflows/goreleaser-snapshot-fleet.yaml b/.github/workflows/goreleaser-snapshot-fleet.yaml index 46c1da4193c1..927cf31be1da 100644 --- a/.github/workflows/goreleaser-snapshot-fleet.yaml +++ b/.github/workflows/goreleaser-snapshot-fleet.yaml @@ -57,7 +57,7 @@ jobs: - name: Set up Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} + go-version-file: 'go.mod' # Set the Node.js version - name: Set up Node.js ${{ vars.NODE_VERSION }} diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 015a464b4b84..98c9cd3a5973 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -264,13 +264,13 @@ jobs: npm install -g fleetctl fleetctl config set --address ${{ needs.gen.outputs.address }} --token ${{ needs.login.outputs.token }} + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Build Fleetctl run: make fleetctl diff --git a/.github/workflows/release-fleetctl-docker-deps.yaml b/.github/workflows/release-fleetctl-docker-deps.yaml index 8fc698f6ac38..c751655d9353 100644 --- a/.github/workflows/release-fleetctl-docker-deps.yaml +++ b/.github/workflows/release-fleetctl-docker-deps.yaml @@ -36,13 +36,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ vars.GO_VERSION }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Login to Docker Hub uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a diff --git a/.github/workflows/release-fleetd-base.yml b/.github/workflows/release-fleetd-base.yml index d7b02cfcf7fa..99099019641c 100644 --- a/.github/workflows/release-fleetd-base.yml +++ b/.github/workflows/release-fleetd-base.yml @@ -51,16 +51,16 @@ jobs: with: egress-policy: audit - - name: Install Go - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 - with: - go-version: ${{ vars.GO_VERSION }} - - name: Checkout Code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 + - name: Install Go + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version-file: 'go.mod' + - name: Check for fleetd component updates id: check-for-fleetd-component-updates run: | diff --git a/.github/workflows/test-db-changes.yml b/.github/workflows/test-db-changes.yml index ecfe464072fe..a5b7dd91e39e 100644 --- a/.github/workflows/test-db-changes.yml +++ b/.github/workflows/test-db-changes.yml @@ -35,15 +35,16 @@ jobs: with: egress-policy: audit - - name: Install Go - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 - with: - go-version: ${{ vars.GO_VERSION }} - name: Checkout Code uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2 with: fetch-depth: 0 + - name: Install Go + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + with: + go-version-file: 'go.mod' + - name: Start Infra Dependencies # Use & to background this run: docker compose up -d mysql_test & diff --git a/.github/workflows/test-go.yaml b/.github/workflows/test-go.yaml index d7b93c5d28dd..b5f2b8fe943c 100644 --- a/.github/workflows/test-go.yaml +++ b/.github/workflows/test-go.yaml @@ -44,7 +44,6 @@ jobs: matrix: suite: ["integration", "core"] os: [ubuntu-latest] - go-version: ['${{ vars.GO_VERSION }}'] mysql: ["mysql:8.0.36", "mysql:8.4.2"] continue-on-error: ${{ matrix.suite == 'integration' }} # Since integration tests have a higher chance of failing, often for unrelated reasons, we don't want to fail the whole job if they fail runs-on: ${{ matrix.os }} @@ -65,7 +64,7 @@ jobs: - name: Install Go uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ matrix.go-version }} + go-version-file: 'go.mod' # Pre-starting dependencies here means they are ready to go when we need them. - name: Start Infra Dependencies diff --git a/.github/workflows/test-native-tooling-packaging.yml b/.github/workflows/test-native-tooling-packaging.yml index 7678e7eeaa0e..ff0dc4abadf6 100644 --- a/.github/workflows/test-native-tooling-packaging.yml +++ b/.github/workflows/test-native-tooling-packaging.yml @@ -41,7 +41,6 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - go-version: ['${{ vars.GO_VERSION }}'] runs-on: ${{ matrix.os }} steps: @@ -50,13 +49,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Install Go Dependencies run: make deps-go diff --git a/.github/workflows/test-packaging.yml b/.github/workflows/test-packaging.yml index f9643bd4e9b4..dbe5a96244ea 100644 --- a/.github/workflows/test-packaging.yml +++ b/.github/workflows/test-packaging.yml @@ -47,7 +47,6 @@ jobs: # `macos-latest` uses arm64 by default now, so please be careful when # updating this version. os: [ubuntu-latest, macos-13] - go-version: ['${{ vars.GO_VERSION }}'] runs-on: ${{ matrix.os }} steps: @@ -83,13 +82,13 @@ jobs: brew install colima colima start --mount $TMPDIR:w + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Install wine and wix if: startsWith(matrix.os, 'macos') diff --git a/.github/workflows/test-yml-specs.yml b/.github/workflows/test-yml-specs.yml index 75e46d6af046..fe8f3ecace97 100644 --- a/.github/workflows/test-yml-specs.yml +++ b/.github/workflows/test-yml-specs.yml @@ -33,7 +33,6 @@ jobs: strategy: matrix: os: [ubuntu-latest] - go-version: ['${{ vars.GO_VERSION }}'] runs-on: ${{ matrix.os }} steps: @@ -42,13 +41,13 @@ jobs: with: egress-policy: audit + - name: Checkout Code + uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - name: Install Go uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: ${{ matrix.go-version }} - - - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + go-version-file: 'go.mod' - name: Run apply spec tests run: | diff --git a/handbook/engineering/README.md b/handbook/engineering/README.md index d6f18bde2c82..70d9cd75f46e 100644 --- a/handbook/engineering/README.md +++ b/handbook/engineering/README.md @@ -111,11 +111,10 @@ If there is partially merged feature work when the release candidate is created, 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 -- Check the [version included in Fleet](https://github.com/fleetdm/fleet/settings/variables/actions). +- Check the [Go version specified in Fleet's go.mod file](https://github.com/fleetdm/fleet/blob/main/go.mod) (`go 1.XX.YY`). - Check the [latest minor version of Go](https://go.dev/dl/). For example, if we are using `go1.19.8`, and there is a new minor version `go1.19.9`, we will upgrade. - If the latest minor version is greater than the version included in Fleet, [file a bug](https://github.com/fleetdm/fleet/issues/new?assignees=&labels=bug%2C%3Areproduce&projects=&template=bug-report.md&title=) and assign it to the [release ritual DRI](https://fleetdm.com/handbook/engineering#rituals) and the current oncall engineer. Add the `~release blocker` label. We must upgrade to the latest minor version before publishing the next release. - If the latest major version is greater than the version included in Fleet, [create a story](https://github.com/fleetdm/fleet/issues/new?assignees=&labels=story%2C%3Aproduct&projects=&template=story.md&title=) and assign it to the [release ritual DRI](https://fleetdm.com/handbook/engineering#rituals) and the current oncall engineer. This will be considered for an upcoming sprint. The release can proceed without upgrading the major version. -- Note that major version upgrades also require an [update to go.mod](https://github.com/fleetdm/fleet/blob/7b3134498873a31ba748ca27fabb0059cef70db9/go.mod#L3). > In Go versioning, the number after the first dot is the "major" version, while the number after the second dot is the "minor" version. For example, in Go 1.19.9, "19" is the major version and "9" is the minor version. Major version upgrades are assessed separately by engineering. From 19db84352f400d49686c2d8a498cd80f4b13d318 Mon Sep 17 00:00:00 2001 From: Marko Lisica <83164494+marko-lisica@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:53:42 +0200 Subject: [PATCH 7/8] Update: Renew SCEP certificates 180 days before expiration (#21747) Updates related to: #19684 --- articles/macos-mdm-setup.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/articles/macos-mdm-setup.md b/articles/macos-mdm-setup.md index 7dab8b7de950..28252b62d13f 100644 --- a/articles/macos-mdm-setup.md +++ b/articles/macos-mdm-setup.md @@ -4,7 +4,7 @@ To turn on macOS, iOS, and iPadOS MDM features, follow the instructions on this To use automatic enrollment (aka zero-touch) features on macOS, iOS, and iPadOS, follow instructions to connect Fleet with Apple Business Manager (ABM). -To turn on Windows MDM features, head to this [Windows MDM setup article](https://fleetdm.com/guides/windows-mdm-setup). +To turn on Windows MDM features, head to this [Windows MDM setup article](https://fleetdm.com/guides/windows-mdm-setup). ## Apple Push Notification service (APNs) @@ -53,6 +53,10 @@ If no default team is set for a host platform (macOS, iOS, or iPadOS), then newl > A host can be transferred to a new (not default) team before it enrolls. In the Fleet UI, you can do this under **Settings** > **Teams**. +### Simple Certificate Enrollment Protocol (SCEP) + +Fleet uses SCEP certificates (1 year expiry) to authenticate the requests hosts make to Fleet. Fleet renews each host's SCEP certificates automatically every 180 days. + From a16733e02f4c849c839bbcb9400bf2ac11cf8544 Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Wed, 4 Sep 2024 10:08:22 -0400 Subject: [PATCH 8/8] MABM: fix/update non-integration MABM-related skipped tests (#21799) --- cmd/fleet/cron_test.go | 8 ++-- cmd/fleetctl/apply_test.go | 2 - cmd/fleetctl/get_test.go | 34 ++++++++++++++-- cmd/fleetctl/gitops_test.go | 10 ++--- .../macosSetupExpectedAppConfigSet.yml | 1 + server/mdm/apple/apple_mdm.go | 4 +- server/mdm/apple/apple_mdm_external_test.go | 39 +++++++++++-------- server/mdm/apple/apple_mdm_test.go | 7 ++-- server/service/appconfig.go | 4 +- server/worker/macos_setup_assistant_test.go | 15 ------- 10 files changed, 69 insertions(+), 55 deletions(-) diff --git a/cmd/fleet/cron_test.go b/cmd/fleet/cron_test.go index 8f0626f96c07..789b38c40565 100644 --- a/cmd/fleet/cron_test.go +++ b/cmd/fleet/cron_test.go @@ -36,8 +36,6 @@ func TestNewMDMProfileManagerWithoutConfig(t *testing.T) { } func TestMigrateABMTokenDuringDEPCronJob(t *testing.T) { - // FIXME - t.Skip() ctx := context.Background() ds := mysql.CreateMySQLDS(t) @@ -108,9 +106,9 @@ func TestMigrateABMTokenDuringDEPCronJob(t *testing.T) { require.NotEmpty(t, defProf.Token) // no profile UUID was assigned for no-team (because there are no hosts right now) - profUUID, _, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, nil, "") - require.NoError(t, err) - require.Equal(t, "", profUUID) + _, _, err = ds.GetMDMAppleDefaultSetupAssistant(ctx, nil, "") + require.Error(t, err) + require.ErrorAs(t, err, &nfe) // no teams, so no team-specific custom setup assistants teams, err := ds.ListTeams(ctx, fleet.TeamFilter{User: test.UserAdmin}, fleet.ListOptions{}) diff --git a/cmd/fleetctl/apply_test.go b/cmd/fleetctl/apply_test.go index 3980504e4853..1010e8ad1eeb 100644 --- a/cmd/fleetctl/apply_test.go +++ b/cmd/fleetctl/apply_test.go @@ -2231,8 +2231,6 @@ spec: }) t.Run("setup assistant get and apply roundtrip", func(t *testing.T) { - // FIXME - t.Skip() ds := setupServer(t, true) b, err := os.ReadFile(filepath.Join("testdata", "macosSetupExpectedAppConfigEmpty.yml")) diff --git a/cmd/fleetctl/get_test.go b/cmd/fleetctl/get_test.go index cc44450b11bf..f39ff1cd5551 100644 --- a/cmd/fleetctl/get_test.go +++ b/cmd/fleetctl/get_test.go @@ -2060,10 +2060,13 @@ func TestGetAppleBM(t *testing.T) { assert.Contains(t, err.Error(), expected) }) - t.Run("premium license", func(t *testing.T) { - // FIXME - t.Skip() - runServerWithMockedDS(t, &service.TestServerOpts{License: &fleet.LicenseInfo{Tier: fleet.TierPremium}, DEPStorage: depStorage}) + t.Run("premium license, single token", func(t *testing.T) { + _, ds := runServerWithMockedDS(t, &service.TestServerOpts{License: &fleet.LicenseInfo{Tier: fleet.TierPremium}, DEPStorage: depStorage}) + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{ + {ID: 1}, + }, nil + } out := runAppForTest(t, []string{"get", "mdm_apple_bm"}) assert.Contains(t, out, "Apple ID:") @@ -2072,6 +2075,29 @@ func TestGetAppleBM(t *testing.T) { assert.Contains(t, out, "Renew date:") assert.Contains(t, out, "Default team:") }) + + t.Run("premium license, no token", func(t *testing.T) { + _, ds := runServerWithMockedDS(t, &service.TestServerOpts{License: &fleet.LicenseInfo{Tier: fleet.TierPremium}, DEPStorage: depStorage}) + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return nil, nil + } + + out := runAppForTest(t, []string{"get", "mdm_apple_bm"}) + assert.Contains(t, out, "No Apple Business Manager server token found.") + }) + + t.Run("premium license, multiple tokens", func(t *testing.T) { + _, ds := runServerWithMockedDS(t, &service.TestServerOpts{License: &fleet.LicenseInfo{Tier: fleet.TierPremium}, DEPStorage: depStorage}) + ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) { + return []*fleet.ABMToken{ + {ID: 1}, + {ID: 2}, + }, nil + } + + _, err := runAppNoChecks([]string{"get", "mdm_apple_bm"}) + assert.ErrorContains(t, err, "This API endpoint has been deprecated. Please use the new GET /abm_tokens API endpoint") + }) } func TestGetCarves(t *testing.T) { diff --git a/cmd/fleetctl/gitops_test.go b/cmd/fleetctl/gitops_test.go index fc9acc58a5df..57c5b0d3910d 100644 --- a/cmd/fleetctl/gitops_test.go +++ b/cmd/fleetctl/gitops_test.go @@ -2144,8 +2144,6 @@ software: } func TestVPPGitOps(t *testing.T) { - // FIXME - t.Skip() global := func(mdm string) string { return fmt.Sprintf(` controls: @@ -2333,10 +2331,10 @@ software: name: "all teams is supported", cfgs: []string{ global(` - volume_purchasing_program: - - location: Fleet Device Management Inc. - teams: - - "All teams"`), + volume_purchasing_program: + - location: Fleet Device Management Inc. + teams: + - "All teams"`), workstations, iosTeam, }, diff --git a/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml b/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml index e63748bfb9db..2dd2f93adf1f 100644 --- a/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml +++ b/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml @@ -19,6 +19,7 @@ spec: zendesk: null mdm: apple_business_manager: + volume_purchasing_program: apple_bm_enabled_and_configured: false apple_bm_terms_expired: false enabled_and_configured: true diff --git a/server/mdm/apple/apple_mdm.go b/server/mdm/apple/apple_mdm.go index d85377bb209b..a280b36c2821 100644 --- a/server/mdm/apple/apple_mdm.go +++ b/server/mdm/apple/apple_mdm.go @@ -153,7 +153,7 @@ func (d *DEPService) createDefaultAutomaticProfile(ctx context.Context) error { // // On success, it returns the profile uuid and timestamp for the specific token // of interest to the caller (identified by its organization name). -func (d *DEPService) RegisterProfileWithAppleDEPServer(ctx context.Context, team *fleet.Team, setupAsst *fleet.MDMAppleSetupAssistant, abmTokeOrgName string) (string, time.Time, error) { +func (d *DEPService) RegisterProfileWithAppleDEPServer(ctx context.Context, team *fleet.Team, setupAsst *fleet.MDMAppleSetupAssistant, abmTokenOrgName string) (string, time.Time, error) { appCfg, err := d.ds.AppConfig(ctx) if err != nil { return "", time.Time{}, ctxerr.Wrap(ctx, err, "fetching app config") @@ -249,7 +249,7 @@ func (d *DEPService) RegisterProfileWithAppleDEPServer(ctx context.Context, team return "", time.Time{}, ctxerr.Wrap(ctx, err, "save default setup assistant profile UUID") } } - if orgName == abmTokeOrgName { + if orgName == abmTokenOrgName { requestedTokenProfileUUID = res.ProfileUUID } } diff --git a/server/mdm/apple/apple_mdm_external_test.go b/server/mdm/apple/apple_mdm_external_test.go index 1867b9357771..30287b0a32c6 100644 --- a/server/mdm/apple/apple_mdm_external_test.go +++ b/server/mdm/apple/apple_mdm_external_test.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" + "fmt" "io" "net/http" "net/http/httptest" @@ -21,11 +22,10 @@ import ( ) func TestDEPService_RunAssigner(t *testing.T) { - // FIXME - t.Skip() ctx := context.Background() ds := mysql.CreateMySQLDS(t) + const abmTokenOrgName = "test_org" depStorage, err := ds.NewMDMAppleDEPStorage() require.NoError(t, err) @@ -35,10 +35,10 @@ func TestDEPService_RunAssigner(t *testing.T) { t.Cleanup(srv.Close) t.Cleanup(func() { mysql.TruncateTables(t, ds) }) - err = depStorage.StoreConfig(ctx, "fleet", &nanodep_client.Config{BaseURL: srv.URL}) + err = depStorage.StoreConfig(ctx, abmTokenOrgName, &nanodep_client.Config{BaseURL: srv.URL}) require.NoError(t, err) - mysql.SetTestABMAssets(t, ds, "fleet") + mysql.SetTestABMAssets(t, ds, abmTokenOrgName) logger := log.NewNopLogger() return apple_mdm.NewDEPService(ds, depStorage, logger) @@ -54,7 +54,7 @@ func TestDEPService_RunAssigner(t *testing.T) { case "/session": _, _ = w.Write([]byte(`{"auth_session_token": "session123"}`)) case "/account": - _, _ = w.Write([]byte(`{"admin_id": "admin123", "org_name": "test_org"}`)) + _, _ = w.Write([]byte(fmt.Sprintf(`{"admin_id": "admin123", "org_name": "%s"}`, abmTokenOrgName))) case "/profile": err := encoder.Encode(godep.ProfileResponse{ProfileUUID: "profile123"}) require.NoError(t, err) @@ -78,7 +78,7 @@ func TestDEPService_RunAssigner(t *testing.T) { require.NotEmpty(t, defProf.Token) // a profile UUID was assigned for no-team - profUUID, modTime, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, nil, "") + profUUID, modTime, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, nil, abmTokenOrgName) require.NoError(t, err) require.Equal(t, "profile123", profUUID) require.False(t, modTime.Before(start)) @@ -87,6 +87,11 @@ func TestDEPService_RunAssigner(t *testing.T) { appCfg, err := ds.AppConfig(ctx) require.NoError(t, err) require.Empty(t, appCfg.MDM.DeprecatedAppleBMDefaultTeam) + abmTok, err := ds.GetABMTokenByOrgName(ctx, abmTokenOrgName) + require.NoError(t, err) + require.Nil(t, abmTok.MacOSDefaultTeamID) + require.Nil(t, abmTok.IPadOSDefaultTeamID) + require.Nil(t, abmTok.IOSDefaultTeamID) // no teams, so no team-specific custom setup assistants teams, err := ds.ListTeams(ctx, fleet.TeamFilter{User: test.UserAdmin}, fleet.ListOptions{}) @@ -120,7 +125,7 @@ func TestDEPService_RunAssigner(t *testing.T) { case "/session": _, _ = w.Write([]byte(`{"auth_session_token": "session123"}`)) case "/account": - _, _ = w.Write([]byte(`{"admin_id": "admin123", "org_name": "test_org"}`)) + _, _ = w.Write([]byte(fmt.Sprintf(`{"admin_id": "admin123", "org_name": "%s"}`, abmTokenOrgName))) case "/profile": err := encoder.Encode(godep.ProfileResponse{ProfileUUID: "profile123"}) require.NoError(t, err) @@ -158,7 +163,7 @@ func TestDEPService_RunAssigner(t *testing.T) { require.NotEmpty(t, defProf.Token) // a profile UUID was assigned to no-team - profUUID, modTime, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, nil, "") + profUUID, modTime, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, nil, abmTokenOrgName) require.NoError(t, err) require.Equal(t, "profile123", profUUID) require.False(t, modTime.Before(start)) @@ -192,7 +197,7 @@ func TestDEPService_RunAssigner(t *testing.T) { case "/session": _, _ = w.Write([]byte(`{"auth_session_token": "session123"}`)) case "/account": - _, _ = w.Write([]byte(`{"admin_id": "admin123", "org_name": "test_org"}`)) + _, _ = w.Write([]byte(fmt.Sprintf(`{"admin_id": "admin123", "org_name": "%s"}`, abmTokenOrgName))) case "/profile": reqBody, err := io.ReadAll(r.Body) require.NoError(t, err) @@ -236,12 +241,11 @@ func TestDEPService_RunAssigner(t *testing.T) { tm, err := ds.NewTeam(ctx, &fleet.Team{Name: "test_team"}) require.NoError(t, err) - appCfg, err := ds.AppConfig(ctx) + // set that team as default assignment for new macOS devices + tok, err := ds.GetABMTokenByOrgName(ctx, abmTokenOrgName) require.NoError(t, err) - - // set that team as default assignment for new devices - appCfg.MDM.DeprecatedAppleBMDefaultTeam = tm.Name - err = ds.SaveAppConfig(ctx, appCfg) + tok.MacOSDefaultTeamID = &tm.ID + err = ds.SaveABMToken(ctx, tok) require.NoError(t, err) // create a custom setup assistant for that team @@ -264,7 +268,7 @@ func TestDEPService_RunAssigner(t *testing.T) { require.NotEmpty(t, defProf.Token) // a profile UUID was assigned to the team - profUUID, modTime, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, &tm.ID, "") + profUUID, modTime, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, &tm.ID, abmTokenOrgName) require.NoError(t, err) require.Equal(t, "profile123", profUUID) require.False(t, modTime.Before(start)) @@ -272,8 +276,11 @@ func TestDEPService_RunAssigner(t *testing.T) { // the team-specific custom profile was registered tmAsst, err = ds.GetMDMAppleSetupAssistant(ctx, tmAsst.TeamID) require.NoError(t, err) - //require.Equal(t, "profile456", tmAsst.ProfileUUID) require.False(t, tmAsst.UploadedAt.Before(start)) + profileUUID, modTime, err := ds.GetMDMAppleSetupAssistantProfileForABMToken(ctx, &tm.ID, abmTokenOrgName) + require.NoError(t, err) + require.Equal(t, "profile456", profileUUID) + require.True(t, tmAsst.UploadedAt.Equal(modTime)) // a couple hosts were created and assigned to the team (except the op_type ignored) hosts, err := ds.ListHosts(ctx, fleet.TeamFilter{User: test.UserAdmin}, fleet.HostListOptions{}) diff --git a/server/mdm/apple/apple_mdm_test.go b/server/mdm/apple/apple_mdm_test.go index b1f4075f504d..156736ecd4e5 100644 --- a/server/mdm/apple/apple_mdm_test.go +++ b/server/mdm/apple/apple_mdm_test.go @@ -21,8 +21,6 @@ import ( ) func TestDEPService(t *testing.T) { - // FIXME - t.Skip() t.Run("EnsureDefaultSetupAssistant", func(t *testing.T) { ds := new(mock.Store) ctx := context.Background() @@ -70,6 +68,9 @@ func TestDEPService(t *testing.T) { Token: p.Token, Type: p.Type, DEPProfile: p.DEPProfile, + UpdateCreateTimestamps: fleet.UpdateCreateTimestamps{ + UpdateTimestamp: fleet.UpdateTimestamp{UpdatedAt: time.Now()}, + }, } savedProfile = res return res, nil @@ -122,7 +123,7 @@ func TestDEPService(t *testing.T) { return 0, nil } - profUUID, modTime, err := depSvc.EnsureDefaultSetupAssistant(ctx, nil, "") + profUUID, modTime, err := depSvc.EnsureDefaultSetupAssistant(ctx, nil, "org1") require.NoError(t, err) require.Equal(t, "abcd", profUUID) require.NotZero(t, modTime) diff --git a/server/service/appconfig.go b/server/service/appconfig.go index 956de2b96b6b..d8289a9dae88 100644 --- a/server/service/appconfig.go +++ b/server/service/appconfig.go @@ -1101,10 +1101,10 @@ func (svc *Service) validateVPPAssignments( token.Teams = nil } - var tokensToSave map[uint][]uint + tokensToSave := make(map[uint][]uint, len(mdm.VolumePurchasingProgram.Value)) for _, vpp := range mdm.VolumePurchasingProgram.Value { for _, tmName := range vpp.Teams { - if _, ok := teamsByName[norm.NFC.String(tmName)]; !ok { + if _, ok := teamsByName[norm.NFC.String(tmName)]; !ok && tmName != fleet.TeamNameAllTeams { invalid.Appendf("mdm.volume_purchasing_program", "team %s doesn't exist", tmName) return nil, nil } diff --git a/server/worker/macos_setup_assistant_test.go b/server/worker/macos_setup_assistant_test.go index ffb449491168..f137b418bb42 100644 --- a/server/worker/macos_setup_assistant_test.go +++ b/server/worker/macos_setup_assistant_test.go @@ -24,8 +24,6 @@ import ( ) func TestMacosSetupAssistant(t *testing.T) { - // FIXME - t.Skip() ctx := context.Background() ds := mysql.CreateMySQLDS(t) // call TruncateTables immediately as some DB migrations may create jobs @@ -195,19 +193,6 @@ func TestMacosSetupAssistant(t *testing.T) { require.False(t, modTime.Before(start)) } } - // the default token is not used by any team, only defined for no team (due - // to it defaulting to no team) - for _, tmID := range tmIDs { - profUUID, modTime, err := ds.GetMDMAppleDefaultSetupAssistant(ctx, tmID, "FIXME") - if tmID == nil { - require.NoError(t, err) - require.Equal(t, defaultProfileName, profUUID, "tmID", getTeamID(tmID)) - require.False(t, modTime.Before(start)) - } else { - require.Error(t, err) - require.ErrorIs(t, err, sql.ErrNoRows) - } - } require.Equal(t, map[string]string{ "serial-0": defaultProfileName, "serial-1": defaultProfileName,