diff --git a/api/helpers/ensure-trial-license-key.js b/api/helpers/ensure-trial-license-key.js new file mode 100644 index 00000000000..6348bba27b9 --- /dev/null +++ b/api/helpers/ensure-trial-license-key.js @@ -0,0 +1,69 @@ +module.exports = { + + + friendlyName: 'Ensure trial license key', + + + description: 'Generate and persist a Fleet Premium trial license key for the given user if they do not already have one.', + + + inputs: { + + user: { + type: 'ref', + description: 'The logged-in user record (this.req.me) to check and possibly update.', + required: true, + } + + }, + + + exits: { + + success: { + outputDescription: 'The trial license key for this user, along with whether it is expired.', + outputType: { + trialLicenseKey: 'string', + userHasExpiredTrialLicense: 'boolean', + } + } + + }, + + + fn: async function ({user}) { + + let userHasExpiredTrialLicense = false; + let trialLicenseKey; + + if(user.fleetPremiumTrialLicenseKey) { + if(user.fleetPremiumTrialLicenseKeyExpiresAt < Date.now()) { + userHasExpiredTrialLicense = true; + } + trialLicenseKey = user.fleetPremiumTrialLicenseKey; + } else { + // If this user does not have a trial license key, generate a new one for them. + let thirtyDaysFromNowAt = Date.now() + (1000 * 60 * 60 * 24 * 30); + let trialLicenseKeyForThisUser = await sails.helpers.createLicenseKey.with({ + numberOfHosts: 10, + organization: user.organization ? user.organization : 'Fleet Premium trial', + expiresAt: thirtyDaysFromNowAt, + }); + // Save the trial license key to the DB record for this user. + await User.updateOne({id: user.id}) + .set({ + fleetPremiumTrialLicenseKey: trialLicenseKeyForThisUser, + fleetPremiumTrialLicenseKeyExpiresAt: thirtyDaysFromNowAt, + }); + trialLicenseKey = trialLicenseKeyForThisUser; + } + + return { + trialLicenseKey, + userHasExpiredTrialLicense, + }; + + } + + +}; diff --git a/assets/scripts/install-wine.sh b/assets/scripts/install-wine.sh index fd323603f0b..1e4a06e341f 100755 --- a/assets/scripts/install-wine.sh +++ b/assets/scripts/install-wine.sh @@ -26,4 +26,5 @@ have caused repeated breakage. EOF -exit 1 +exit 0 + diff --git a/cmd/fleetctl/fleetctl/goquerycmd/goquery.go b/cmd/fleetctl/fleetctl/goquerycmd/goquery.go index 5560a51dc27..658b3e876dd 100644 --- a/cmd/fleetctl/fleetctl/goquerycmd/goquery.go +++ b/cmd/fleetctl/fleetctl/goquerycmd/goquery.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "strconv" + "sync" "github.com/AbGuthrie/goquery/v2" gqconfig "github.com/AbGuthrie/goquery/v2/config" @@ -26,6 +27,7 @@ type activeQuery struct { type goqueryClient struct { client *service.Client + mu sync.Mutex queryCounter int queries map[string]activeQuery // goquery passes the UUID, while we need the hostname (or ID) to @@ -62,7 +64,9 @@ func (c *goqueryClient) CheckHost(query string) (gqhosts.Host, error) { return gqhosts.Host{}, fmt.Errorf("host %s not found", query) } + c.mu.Lock() c.hostnameByUUID[host.UUID] = host.Hostname + c.mu.Unlock() return gqhosts.Host{ UUID: host.UUID, @@ -73,20 +77,25 @@ func (c *goqueryClient) CheckHost(query string) (gqhosts.Host, error) { } func (c *goqueryClient) ScheduleQuery(uuid, query string) (string, error) { + c.mu.Lock() c.queryCounter++ queryName := strconv.Itoa(c.queryCounter) hostname, ok := c.hostnameByUUID[uuid] if !ok { + c.mu.Unlock() return "", errors.New("could not lookup host") } + c.mu.Unlock() res, err := c.client.LiveQuery(query, nil, []string{}, []string{hostname}) if err != nil { return "", err } + c.mu.Lock() c.queries[queryName] = activeQuery{status: "Pending"} + c.mu.Unlock() // We need to start a separate thread due to goquery expecting // scheduling a query and retrieving results to be separate @@ -94,11 +103,15 @@ func (c *goqueryClient) ScheduleQuery(uuid, query string) (string, error) { go func() { select { case hostResult := <-res.Results(): + c.mu.Lock() c.queries[queryName] = activeQuery{status: "Completed", results: hostResult.Rows} + c.mu.Unlock() // Print an error case err := <-res.Errors(): + c.mu.Lock() c.queries[queryName] = activeQuery{status: "error: " + err.Error()} + c.mu.Unlock() } }() @@ -107,7 +120,9 @@ func (c *goqueryClient) ScheduleQuery(uuid, query string) (string, error) { } func (c *goqueryClient) FetchResults(queryName string) (gqmodels.Rows, string, error) { + c.mu.Lock() res, ok := c.queries[queryName] + c.mu.Unlock() if !ok { return nil, "", fmt.Errorf("Unknown query %s", queryName) } diff --git a/ee/maintained-apps/inputs/homebrew/scripts/gpg-suite-uninstall.sh b/ee/maintained-apps/inputs/homebrew/scripts/gpg-suite-uninstall.sh index e5b6c0a7fea..1a5ab5304e4 100644 --- a/ee/maintained-apps/inputs/homebrew/scripts/gpg-suite-uninstall.sh +++ b/ee/maintained-apps/inputs/homebrew/scripts/gpg-suite-uninstall.sh @@ -134,7 +134,7 @@ remove_receipt_files() { fi echo "sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | tr '\\\\n' '\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf" - sudo pkgutil --only-files --files "$PKGID" | sed "s|^|/${INSTALL_LOCATION}/|" | tr '\n' '\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf + sudo pkgutil --only-files --files "$PKGID" | sed "s|^|${FULL_INSTALL_LOCATION}/|" | tr '\n' '\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf echo "sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\\\n' '\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf" sudo pkgutil --only-dirs --files "$PKGID" | sed "s|^|${FULL_INSTALL_LOCATION}/|" | grep '\.app$' | tr '\n' '\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf diff --git a/ee/maintained-apps/inputs/homebrew/scripts/zoom_install.sh b/ee/maintained-apps/inputs/homebrew/scripts/zoom_install.sh index 91b6afaa937..bd1aa77a778 100755 --- a/ee/maintained-apps/inputs/homebrew/scripts/zoom_install.sh +++ b/ee/maintained-apps/inputs/homebrew/scripts/zoom_install.sh @@ -33,10 +33,16 @@ quit_application() { restart_zoom() { local console_user="$1" - + if [[ -n "$console_user" && "$console_user" != "root" ]]; then echo "Restarting Zoom for user: $console_user" - sudo -u "$console_user" open -a "zoom.us" + local console_uid + console_uid=$(id -u "$console_user" 2>/dev/null || echo "") + if [[ -n "$console_uid" ]]; then + launchctl asuser "$console_uid" sudo -u "$console_user" open -a "zoom.us" + else + sudo -u "$console_user" open -a "zoom.us" + fi else echo "No console user found, attempting direct Zoom start..." open -a "zoom.us" diff --git a/ee/vulnerability-dashboard/api/helpers/get-compliance-information.js b/ee/vulnerability-dashboard/api/helpers/get-compliance-information.js index ea17d36b685..7178acdc726 100644 --- a/ee/vulnerability-dashboard/api/helpers/get-compliance-information.js +++ b/ee/vulnerability-dashboard/api/helpers/get-compliance-information.js @@ -90,7 +90,6 @@ module.exports = { } operatingSystemsInUse.push(osInfo); } - complianceInformation.versionsInUse = _.sortByOrder(complianceInformation.versionsInUse, 'sortByName'); let numberOfHostsToReport = await Host.count({teamApid: teamApid}); let numberOfHostsOnThisTeamWithACompliantOs = await Host.count({operatingSystem: {in: idsOfCompliantOperatingSystems}, teamApid: teamApid}); @@ -264,3 +263,4 @@ module.exports = { }; + diff --git a/frontend/components/ActionsDropdown/ActionsDropdown.tests.tsx b/frontend/components/ActionsDropdown/ActionsDropdown.tests.tsx index a1f7a71c14c..e9773630774 100644 --- a/frontend/components/ActionsDropdown/ActionsDropdown.tests.tsx +++ b/frontend/components/ActionsDropdown/ActionsDropdown.tests.tsx @@ -10,9 +10,7 @@ const DROPDOWN_OPTIONS = [ { disabled: true, label: "Delete", value: "delete-query" }, ]; const PLACEHOLDER = "Actions"; -const ON_CHANGE = (value: string) => { - console.log(value); -}; +const ON_CHANGE = () => {}; describe("Actions dropdown", () => { it("renders dropdown placeholder and options", async () => { diff --git a/frontend/components/buttons/RevealButton/RevealButton.tests.tsx b/frontend/components/buttons/RevealButton/RevealButton.tests.tsx index c020d1dee68..03a393362c0 100644 --- a/frontend/components/buttons/RevealButton/RevealButton.tests.tsx +++ b/frontend/components/buttons/RevealButton/RevealButton.tests.tsx @@ -4,8 +4,8 @@ import { renderWithSetup } from "test/test-utils"; import RevealButton from "./RevealButton"; -const SHOW_TEXT = "Advanced options"; -const HIDE_TEXT = "Advanced options"; +const SHOW_TEXT = "Show advanced options"; +const HIDE_TEXT = "Hide advanced options"; const TOOLTIP_CONTENT = "Customize logging type and platforms"; describe("Reveal button", () => { diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/Certificates/components/AddCertificateModal/AddCertificateModal.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/Certificates/components/AddCertificateModal/AddCertificateModal.tsx index 698a898a8f1..0aea55497ae 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/Certificates/components/AddCertificateModal/AddCertificateModal.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/Certificates/components/AddCertificateModal/AddCertificateModal.tsx @@ -144,6 +144,7 @@ const AddCertModal = ({ nameEquals: "subject_alternative_name", }); const nameConflict = getErrorReason(e, { + nameEquals: "name", reasonIncludes: "already exists", }); if (sanReason) { @@ -253,3 +254,4 @@ const AddCertModal = ({ }; export default AddCertModal; + diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx index 00cf067c22c..9901e30d248 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/DeleteSoftwareModal/DeleteSoftwareModal.tsx @@ -55,7 +55,7 @@ const getPlatformMessage = (isAppStoreApp: boolean, isAndroidApp: boolean) => {
Pending installs and uninstalls will be canceled. If they have already - started, they won' be canceled, and the results won't appear + started, they won't be canceled, and the results won't appear in Fleet.
> diff --git a/schema/tables/alf_explicit_auths.yml b/schema/tables/alf_explicit_auths.yml index f1ad9dc3498..7926488dc66 100644 --- a/schema/tables/alf_explicit_auths.yml +++ b/schema/tables/alf_explicit_auths.yml @@ -4,8 +4,9 @@ examples: |- useful when looking to see if vulnerable software is exposed to networks. ``` - SELECT * FROM alf_exceptions; + SELECT * FROM alf_explicit_auths; ``` notes: This table is currently affected by a [bug](https://github.com/osquery/osquery/issues/2322) and not returning applications visible in the preferences interface. + diff --git a/schema/tables/load_average.yml b/schema/tables/load_average.yml index 008a0f5c008..7fada03b98b 100644 --- a/schema/tables/load_average.yml +++ b/schema/tables/load_average.yml @@ -3,5 +3,6 @@ examples: |- Find computers with a load average of 3.5 or higher over the last 15 minutes. ``` - SELECT average from load_average WHERE period='15m' AND average|-=3.5; + SELECT average from load_average WHERE period='15m' AND average>=3.5; ``` + diff --git a/server/datastore/mysql/migrations/tables/20250904091745_AddCertificateAuthoritiesTable_test.go b/server/datastore/mysql/migrations/tables/20250904091745_AddCertificateAuthoritiesTable_test.go index 0699797d7a6..583777d43c6 100644 --- a/server/datastore/mysql/migrations/tables/20250904091745_AddCertificateAuthoritiesTable_test.go +++ b/server/datastore/mysql/migrations/tables/20250904091745_AddCertificateAuthoritiesTable_test.go @@ -4,7 +4,6 @@ import ( "crypto/md5" // nolint:gosec // used only to hash for efficient comparisons "encoding/hex" "encoding/json" - "fmt" "strings" "testing" @@ -116,7 +115,6 @@ func TestUp_20250904091745(t *testing.T) { if err != nil { t.Fatalf("failed to marshal integrationsJSON: %v", err) } - fmt.Printf("Marshalled integrations_json: %s\n", string(integrationJSONBytes)) insertNDESPasswordStmt := `INSERT INTO mdm_config_assets (name, value, md5_checksum) VALUES (?, ?, UNHEX(?))` // nolint:gosec // just test data, not hardcoded credentials _, err = db.Exec(insertNDESPasswordStmt, fleet.MDMAssetNDESPassword, ndesEncryptedPassword, md5ChecksumBytes(ndesEncryptedPassword)) diff --git a/server/datastore/mysql/teams_test.go b/server/datastore/mysql/teams_test.go index a35cb7be465..60cde9006c4 100644 --- a/server/datastore/mysql/teams_test.go +++ b/server/datastore/mysql/teams_test.go @@ -157,7 +157,7 @@ func testTeamsGetSetDelete(t *testing.T, ds *Datastore) { mdm_apple_configuration_profiles (profile_uuid, team_id, identifier, name, mobileconfig, checksum) VALUES (?, ?, ?, ?, ?, ?)`, fmt.Sprintf("uuid_%s", tt.name), - 0, + team.ID, fmt.Sprintf("TestPayloadIdentifier_%s", tt.name), fmt.Sprintf("TestPayloadName_%s", tt.name), `