Fixed bundle identifier for privileges pkg (#33517)
**Related issue:** Resolves #32083 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [x] Added/updated automated tests - [x] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually ## Database migrations - [x] Checked table schema to confirm autoupdate - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* Corrected bundle identifier for privileges macos software pkg and fixed existing software installers to use corrected software title. The privileges application should show the correct status in software inventory.
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<installer-gui-script authoringTool="Packages" authoringToolVersion="1.2.10" authoringToolBuild="732" minSpecVersion="1.0">
|
||||
<options hostArchitectures="x86_64,arm64"/>
|
||||
<!--+==========================+
|
||||
| Presentation |
|
||||
+==========================+-->
|
||||
<title>DISTRIBUTION_TITLE</title>
|
||||
<background file="background" uti="public.png" scaling="proportional" alignment="bottomleft"/>
|
||||
<background-darkAqua file="background" uti="public.png" scaling="proportional" alignment="bottomleft"/>
|
||||
<!--+==========================+
|
||||
| Installer |
|
||||
+==========================+-->
|
||||
<choices-outline>
|
||||
<line choice="installer_choice_1"/>
|
||||
</choices-outline>
|
||||
<choice id="installer_choice_1" title="Privileges" description="">
|
||||
<pkg-ref id="corp.sap.privileges.pkg"/>
|
||||
</choice>
|
||||
<!--+==========================+
|
||||
| Package References |
|
||||
+==========================+-->
|
||||
<pkg-ref id="corp.sap.privileges.pkg" version="2.4.0" auth="Root" installKBytes="3905">#Privileges.pkg</pkg-ref>
|
||||
</installer-gui-script>
|
||||
@@ -329,6 +329,8 @@ var knownBadNames = map[string]struct{}{
|
||||
|
||||
var idTranslations = map[string]string{
|
||||
"com.sentinelone.sentinel-agent": "com.sentinelone.SentinelAgent",
|
||||
// This is present in Privileges.pkg/PackageInfo, however, current logic doesn't parse PackageInfo files if Distribution file is present
|
||||
"corp.sap.privileges.pkg": "corp.sap.privileges",
|
||||
}
|
||||
|
||||
// getDistributionInfo gets the name, bundle identifier and version of a PKG distribution file
|
||||
|
||||
@@ -224,6 +224,13 @@ func TestParseRealDistributionFiles(t *testing.T) {
|
||||
"com.getcoldturkey.blocker-firefox-ext", "com.getcoldturkey.coldturkeyblocker",
|
||||
},
|
||||
},
|
||||
{
|
||||
file: "distribution-privileges.xml",
|
||||
expectedName: "Privileges",
|
||||
expectedVersion: "2.4.0",
|
||||
expectedBundleID: "corp.sap.privileges",
|
||||
expectedPackageIDs: []string{"corp.sap.privileges.pkg"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func init() {
|
||||
MigrationClient.AddMigration(Up_20250926123048, Down_20250926123048)
|
||||
}
|
||||
|
||||
func Up_20250926123048(tx *sql.Tx) error {
|
||||
// Find incorrect/correct title
|
||||
titleRows, err := tx.Query(`
|
||||
SELECT id, bundle_identifier
|
||||
FROM software_titles
|
||||
WHERE bundle_identifier IN ('corp.sap.privileges.pkg', 'corp.sap.privileges')
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer titleRows.Close()
|
||||
|
||||
bundleIdToTitleId := map[string]string{}
|
||||
for titleRows.Next() {
|
||||
var id, bundleIdentifier string
|
||||
if err := titleRows.Scan(&id, &bundleIdentifier); err != nil {
|
||||
return err
|
||||
}
|
||||
bundleIdToTitleId[bundleIdentifier] = id
|
||||
}
|
||||
if err := titleRows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(bundleIdToTitleId) == 0 {
|
||||
// No "Privileges" titles, nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the "Privileges" app has not been indexed by osquery,
|
||||
// we will not have the correct title/bundle
|
||||
// so we need to insert it
|
||||
if _, ok := bundleIdToTitleId["corp.sap.privileges"]; !ok {
|
||||
res, err := tx.Exec(`
|
||||
INSERT INTO software_titles (name, source, bundle_identifier) VALUES
|
||||
('Privileges', 'apps', 'corp.sap.privileges')
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lastInsertId, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bundleIdToTitleId["corp.sap.privileges"] = fmt.Sprintf("%d", lastInsertId)
|
||||
}
|
||||
|
||||
// Find software installers with incorrect title
|
||||
installerRows, err := tx.Query(`
|
||||
SELECT id
|
||||
FROM software_installers
|
||||
WHERE title_id = ?
|
||||
AND extension = 'pkg'
|
||||
`, bundleIdToTitleId["corp.sap.privileges.pkg"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer installerRows.Close()
|
||||
|
||||
var softwareInstallerIds []string
|
||||
for installerRows.Next() {
|
||||
var id string
|
||||
if err := installerRows.Scan(&id); err != nil {
|
||||
return err
|
||||
}
|
||||
softwareInstallerIds = append(softwareInstallerIds, id)
|
||||
}
|
||||
if err := installerRows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update software installers to point to correct title
|
||||
for _, softwareInstallerId := range softwareInstallerIds {
|
||||
if _, err := tx.Exec(`
|
||||
UPDATE software_installers
|
||||
SET title_id = ?
|
||||
WHERE id = ?
|
||||
`, bundleIdToTitleId["corp.sap.privileges"], softwareInstallerId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Delete incorrect title if exists
|
||||
if incorrectTitleId, ok := bundleIdToTitleId["corp.sap.privileges.pkg"]; ok {
|
||||
if _, err := tx.Exec(`
|
||||
DELETE FROM software_titles
|
||||
WHERE id = ?
|
||||
`, incorrectTitleId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Down_20250926123048(tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUp_20250926123048_NoPrivileges(t *testing.T) {
|
||||
db := applyUpToPrev(t)
|
||||
|
||||
userId := execNoErrLastID(t, db, `INSERT INTO users (name, email, password, salt) VALUES (?, ?, ?, ?)`, "Alice", "alice@example.com", "password", "salt")
|
||||
installScriptID := execNoErrLastID(t, db, `INSERT INTO script_contents (md5_checksum, contents) VALUES (?, ?)`, "a", "echo 'install script'")
|
||||
uninstallScriptID := execNoErrLastID(t, db, `INSERT INTO script_contents (md5_checksum, contents) VALUES (?, ?)`, "b", "echo 'uninstall script'")
|
||||
|
||||
titleId := execNoErrLastID(t, db, `
|
||||
INSERT INTO software_titles (name, source, bundle_identifier) VALUES
|
||||
('Some App', 'apps', 'com.some.app')
|
||||
`)
|
||||
|
||||
_ = execNoErrLastID(t, db, `
|
||||
INSERT INTO software_installers (title_id, filename, version, platform, install_script_content_id, storage_id, user_id, user_name, user_email, url, package_ids, extension, uninstall_script_content_id, updated_at, fleet_maintained_app_id, install_during_setup, upgrade_code) VALUES
|
||||
((SELECT id FROM software_titles WHERE bundle_identifier = 'com.some.app'), 'some_app_installer.pkg', '1.0.0', 'darwin', ?, 'dummysha256', ?, 'Alice', 'alice@example.com', '', 'com.some.app.pkg', 'pkg', ?, NOW(), NULL, 0, '')
|
||||
`, installScriptID, userId, uninstallScriptID)
|
||||
|
||||
applyNext(t, db)
|
||||
|
||||
var count int
|
||||
err := db.Get(&count, `
|
||||
SELECT count(1) FROM
|
||||
software_titles
|
||||
WHERE bundle_identifier = 'corp.sap.privileges'
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, count, "expected 'corp.sap.privileges' not to be inserted into software_titles")
|
||||
|
||||
err = db.Get(&count, `
|
||||
SELECT count(1)
|
||||
FROM software_installers
|
||||
WHERE title_id = ?
|
||||
`, titleId)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, count, "expected existing software installer to remain unchanged")
|
||||
}
|
||||
|
||||
func TestUp_20250926123048_NoIndexedPrivileges(t *testing.T) {
|
||||
db := applyUpToPrev(t)
|
||||
|
||||
userId := execNoErrLastID(t, db, `INSERT INTO users (name, email, password, salt) VALUES (?, ?, ?, ?)`, "Alice", "alice@example.com", "password", "salt")
|
||||
installScriptID := execNoErrLastID(t, db, `INSERT INTO script_contents (md5_checksum, contents) VALUES (?, ?)`, "a", "echo 'install script'")
|
||||
uninstallScriptID := execNoErrLastID(t, db, `INSERT INTO script_contents (md5_checksum, contents) VALUES (?, ?)`, "b", "echo 'uninstall script'")
|
||||
|
||||
titleId := execNoErrLastID(t, db, `
|
||||
INSERT INTO software_titles (name, source, bundle_identifier) VALUES
|
||||
('Privileges', 'apps', 'corp.sap.privileges.pkg')
|
||||
`)
|
||||
|
||||
_ = execNoErrLastID(t, db, `
|
||||
INSERT INTO software_installers (title_id, filename, version, platform, install_script_content_id, storage_id, self_service, user_id, user_name, user_email, url, package_ids, extension, uninstall_script_content_id, updated_at, fleet_maintained_app_id, install_during_setup, upgrade_code) VALUES
|
||||
(?, 'Privileges_2.0.0.pkg', '2.0.0', 'darwin', ?, 'e18bde3e9c86ff5161e193976c68b29fded2fe91a058ec0c336827166d962989', 1, ?, 'Alice', 'alice@example.com', '', 'corp.sap.privileges.pkg', 'pkg', ?, NOW(), NULL, 0, '')
|
||||
`, titleId, installScriptID, userId, uninstallScriptID)
|
||||
|
||||
var count int
|
||||
err := db.Get(&count, `
|
||||
SELECT count(1) FROM
|
||||
software_titles
|
||||
WHERE bundle_identifier = 'corp.sap.privileges'
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, count, "did not expect 'corp.sap.privileges' to be present into software_titles")
|
||||
|
||||
applyNext(t, db)
|
||||
|
||||
titleRows, err := db.Query(`
|
||||
SELECT id, bundle_identifier
|
||||
FROM software_titles
|
||||
WHERE bundle_identifier IN ('corp.sap.privileges.pkg', 'corp.sap.privileges')
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
defer titleRows.Close()
|
||||
|
||||
bundleIdToTitleId := map[string]string{}
|
||||
for titleRows.Next() {
|
||||
var id int
|
||||
var bundleId string
|
||||
if err := titleRows.Scan(&id, &bundleId); err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
bundleIdToTitleId[bundleId] = fmt.Sprintf("%d", id)
|
||||
}
|
||||
require.NoError(t, titleRows.Err())
|
||||
require.Contains(t, bundleIdToTitleId, "corp.sap.privileges", "expected 'corp.sap.privileges' to be inserted into software_titles")
|
||||
require.NotContains(t, bundleIdToTitleId, "corp.sap.privileges.pkg", "expected 'corp.sap.privileges.pkg' to be deleted from software_titles")
|
||||
|
||||
installerRows, err := db.Query(`
|
||||
SELECT title_id
|
||||
FROM software_installers
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
defer installerRows.Close()
|
||||
var softwareInstallerTitleIds []string
|
||||
for installerRows.Next() {
|
||||
var titleId string
|
||||
if err := installerRows.Scan(&titleId); err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
softwareInstallerTitleIds = append(softwareInstallerTitleIds, titleId)
|
||||
}
|
||||
require.NoError(t, installerRows.Err())
|
||||
require.Len(t, softwareInstallerTitleIds, 1)
|
||||
require.Equal(t, bundleIdToTitleId["corp.sap.privileges"], softwareInstallerTitleIds[0], "expected existing software installer to point to correct software title")
|
||||
}
|
||||
|
||||
func TestUp_20250926123048_IndexedPrivileges(t *testing.T) {
|
||||
db := applyUpToPrev(t)
|
||||
|
||||
userId := execNoErrLastID(t, db, `INSERT INTO users (name, email, password, salt) VALUES (?, ?, ?, ?)`, "Alice", "alice@example.com", "password", "salt")
|
||||
installScriptID := execNoErrLastID(t, db, `INSERT INTO script_contents (md5_checksum, contents) VALUES (?, ?)`, "a", "echo 'install script'")
|
||||
uninstallScriptID := execNoErrLastID(t, db, `INSERT INTO script_contents (md5_checksum, contents) VALUES (?, ?)`, "b", "echo 'uninstall script'")
|
||||
|
||||
incorrectTitleId := execNoErrLastID(t, db, `
|
||||
INSERT INTO software_titles (name, source, bundle_identifier) VALUES
|
||||
('Privileges', 'apps', 'corp.sap.privileges.pkg')
|
||||
`)
|
||||
correctTitleId := execNoErrLastID(t, db, `
|
||||
INSERT INTO software_titles (name, source, bundle_identifier) VALUES
|
||||
('Privileges', 'apps', 'corp.sap.privileges')
|
||||
`)
|
||||
|
||||
_ = execNoErrLastID(t, db, `
|
||||
INSERT INTO software_installers (title_id, filename, version, platform, install_script_content_id, storage_id, self_service, user_id, user_name, user_email, url, package_ids, extension, uninstall_script_content_id, updated_at, fleet_maintained_app_id, install_during_setup, upgrade_code) VALUES
|
||||
(?, 'Privileges_2.0.0.pkg', '2.0.0', 'darwin', ?, 'e18bde3e9c86ff5161e193976c68b29fded2fe91a058ec0c336827166d962989', 1, ?, 'Alice', 'alice@example.com', '', 'corp.sap.privileges.pkg', 'pkg', ?, NOW(), NULL, 0, '')
|
||||
`, incorrectTitleId, installScriptID, userId, uninstallScriptID)
|
||||
|
||||
applyNext(t, db)
|
||||
|
||||
titleRows, err := db.Query(`
|
||||
SELECT id, bundle_identifier
|
||||
FROM software_titles
|
||||
WHERE bundle_identifier IN ('corp.sap.privileges.pkg', 'corp.sap.privileges')
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
defer titleRows.Close()
|
||||
|
||||
bundleIdToTitleId := map[string]string{}
|
||||
for titleRows.Next() {
|
||||
var id int
|
||||
var bundleId string
|
||||
if err := titleRows.Scan(&id, &bundleId); err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
bundleIdToTitleId[bundleId] = fmt.Sprintf("%d", id)
|
||||
}
|
||||
require.NoError(t, titleRows.Err())
|
||||
require.Contains(t, bundleIdToTitleId, "corp.sap.privileges", "expected 'corp.sap.privileges' to be in software_titles")
|
||||
require.NotContains(t, bundleIdToTitleId, "corp.sap.privileges.pkg", "expected 'corp.sap.privileges.pkg' to be deleted from software_titles")
|
||||
|
||||
installerRows, err := db.Query(`
|
||||
SELECT title_id
|
||||
FROM software_installers
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
defer installerRows.Close()
|
||||
var softwareInstallerTitleIds []string
|
||||
for installerRows.Next() {
|
||||
var titleId string
|
||||
if err := installerRows.Scan(&titleId); err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
softwareInstallerTitleIds = append(softwareInstallerTitleIds, titleId)
|
||||
}
|
||||
require.NoError(t, installerRows.Err())
|
||||
require.Len(t, softwareInstallerTitleIds, 1)
|
||||
require.Equal(t, fmt.Sprintf("%d", correctTitleId), softwareInstallerTitleIds[0], "expected existing software installer to point to correct software title")
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user