Skip to content

Commit f352dfd

Browse files
authored
Updated BatchSetSoftwareInstallers to use bundle_identifier (#26252)
The software titles unique key was changed to include bundle identifier in #25794. This caused an issue when running gitops - installing a software with the same bundle identifier but different names. #26226 - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated automated tests - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality
1 parent 2dce287 commit f352dfd

File tree

2 files changed

+98
-23
lines changed

2 files changed

+98
-23
lines changed

server/datastore/mysql/software_installers.go

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,21 +1071,22 @@ func (ds *Datastore) CleanupUnusedSoftwareInstallers(ctx context.Context, softwa
10711071
func (ds *Datastore) BatchSetSoftwareInstallers(ctx context.Context, tmID *uint, installers []*fleet.UploadSoftwareInstallerPayload) error {
10721072
const upsertSoftwareTitles = `
10731073
INSERT INTO software_titles
1074-
(name, source, browser)
1074+
(name, source, browser, bundle_identifier)
10751075
VALUES
10761076
%s
10771077
ON DUPLICATE KEY UPDATE
10781078
name = VALUES(name),
10791079
source = VALUES(source),
1080-
browser = VALUES(browser)
1080+
browser = VALUES(browser),
1081+
bundle_identifier = VALUES(bundle_identifier)
10811082
`
10821083

10831084
const loadSoftwareTitles = `
10841085
SELECT
10851086
id
10861087
FROM
10871088
software_titles
1088-
WHERE (name, source, browser) IN (%s)
1089+
WHERE (unique_identifier, source, browser) IN (%s)
10891090
`
10901091

10911092
const unsetAllInstallersFromPolicies = `
@@ -1190,7 +1191,7 @@ COALESCE(post_install_script_content_id != ? OR
11901191
(post_install_script_content_id IS NULL AND ? IS NOT NULL) OR
11911192
(? IS NULL AND post_install_script_content_id IS NOT NULL)
11921193
, FALSE) is_metadata_modified FROM software_installers
1193-
WHERE global_or_team_id = ? AND title_id IN (SELECT id FROM software_titles WHERE name = ? AND source = ? AND browser = '')
1194+
WHERE global_or_team_id = ? AND title_id IN (SELECT id FROM software_titles WHERE unique_identifier = ? AND source = ? AND browser = '')
11941195
`
11951196

11961197
const insertNewOrEditedInstaller = `
@@ -1216,7 +1217,7 @@ INSERT INTO software_installers (
12161217
install_during_setup
12171218
) VALUES (
12181219
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
1219-
(SELECT id FROM software_titles WHERE name = ? AND source = ? AND browser = ''),
1220+
(SELECT id FROM software_titles WHERE unique_identifier = ? AND source = ? AND browser = ''),
12201221
?, (SELECT name FROM users WHERE id = ?), (SELECT email FROM users WHERE id = ?), ?, ?, COALESCE(?, false)
12211222
)
12221223
ON DUPLICATE KEY UPDATE
@@ -1245,7 +1246,7 @@ FROM
12451246
WHERE
12461247
global_or_team_id = ? AND
12471248
-- this is guaranteed to select a single title_id, due to unique index
1248-
title_id IN (SELECT id FROM software_titles WHERE name = ? AND source = ? AND browser = '')
1249+
title_id IN (SELECT id FROM software_titles WHERE unique_identifier = ? AND source = ? AND browser = '')
12491250
`
12501251

12511252
const deleteInstallerLabelsNotInList = `
@@ -1330,18 +1331,43 @@ WHERE
13301331

13311332
var args []any
13321333
for _, installer := range installers {
1333-
args = append(args, installer.Title, installer.Source, "")
1334+
args = append(
1335+
args,
1336+
installer.Title,
1337+
installer.Source,
1338+
"",
1339+
func() *string {
1340+
if strings.TrimSpace(installer.BundleIdentifier) != "" {
1341+
return &installer.BundleIdentifier
1342+
}
1343+
return nil
1344+
}(),
1345+
)
13341346
}
13351347

13361348
values := strings.TrimSuffix(
1337-
strings.Repeat("(?,?,?),", len(installers)),
1349+
strings.Repeat("(?,?,?,?),", len(installers)),
13381350
",",
13391351
)
13401352
if _, err := tx.ExecContext(ctx, fmt.Sprintf(upsertSoftwareTitles, values), args...); err != nil {
13411353
return ctxerr.Wrap(ctx, err, "insert new/edited software title")
13421354
}
13431355

13441356
var titleIDs []uint
1357+
args = []any{}
1358+
for _, installer := range installers {
1359+
args = append(
1360+
args,
1361+
BundleIdentifierOrName(installer.BundleIdentifier, installer.Title),
1362+
installer.Source,
1363+
"",
1364+
)
1365+
}
1366+
values = strings.TrimSuffix(
1367+
strings.Repeat("(?,?,?),", len(installers)),
1368+
",",
1369+
)
1370+
13451371
if err := sqlx.SelectContext(ctx, tx, &titleIDs, fmt.Sprintf(loadSoftwareTitles, values), args...); err != nil {
13461372
return ctxerr.Wrap(ctx, err, "load existing titles")
13471373
}
@@ -1441,7 +1467,7 @@ WHERE
14411467
postInstallScriptID,
14421468
// WHERE clause
14431469
globalOrTeamID,
1444-
installer.Title,
1470+
BundleIdentifierOrName(installer.BundleIdentifier, installer.Title),
14451471
installer.Source,
14461472
}
14471473

@@ -1472,7 +1498,7 @@ WHERE
14721498
postInstallScriptID,
14731499
installer.Platform,
14741500
installer.SelfService,
1475-
installer.Title,
1501+
BundleIdentifierOrName(installer.BundleIdentifier, installer.Title),
14761502
installer.Source,
14771503
installer.UserID,
14781504
installer.UserID,
@@ -1495,7 +1521,7 @@ WHERE
14951521
// ID (cannot use res.LastInsertID due to the upsert statement, won't
14961522
// give the id in case of update)
14971523
var installerID uint
1498-
if err := sqlx.GetContext(ctx, tx, &installerID, loadSoftwareInstallerID, globalOrTeamID, installer.Title, installer.Source); err != nil {
1524+
if err := sqlx.GetContext(ctx, tx, &installerID, loadSoftwareInstallerID, globalOrTeamID, BundleIdentifierOrName(installer.BundleIdentifier, installer.Title), installer.Source); err != nil {
14991525
return ctxerr.Wrapf(ctx, err, "load id of new/edited installer with name %q", installer.Filename)
15001526
}
15011527

server/datastore/mysql/software_installers_test.go

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -753,18 +753,19 @@ func testBatchSetSoftwareInstallers(t *testing.T, ds *Datastore) {
753753
tfr0, err := fleet.NewTempFileReader(ins0File, t.TempDir)
754754
require.NoError(t, err)
755755
err = ds.BatchSetSoftwareInstallers(ctx, &team.ID, []*fleet.UploadSoftwareInstallerPayload{{
756-
InstallScript: "install",
757-
InstallerFile: tfr0,
758-
StorageID: ins0,
759-
Filename: "installer0",
760-
Title: "ins0",
761-
Source: "apps",
762-
Version: "1",
763-
PreInstallQuery: "foo",
764-
UserID: user1.ID,
765-
Platform: "darwin",
766-
URL: "https://example.com",
767-
ValidatedLabels: &fleet.LabelIdentsWithScope{},
756+
InstallScript: "install",
757+
InstallerFile: tfr0,
758+
StorageID: ins0,
759+
Filename: "installer0",
760+
Title: "ins0",
761+
Source: "apps",
762+
Version: "1",
763+
PreInstallQuery: "foo",
764+
UserID: user1.ID,
765+
Platform: "darwin",
766+
URL: "https://example.com",
767+
ValidatedLabels: &fleet.LabelIdentsWithScope{},
768+
BundleIdentifier: "com.example.ins0",
768769
}})
769770
require.NoError(t, err)
770771
softwareInstallers, err = ds.GetSoftwareInstallers(ctx, team.ID)
@@ -950,6 +951,54 @@ func testBatchSetSoftwareInstallers(t *testing.T, ds *Datastore) {
950951
{Name: ins1, Source: "apps", Browser: ""},
951952
})
952953

954+
// Add software installer with same name different bundle id
955+
err = ds.BatchSetSoftwareInstallers(ctx, &team.ID, []*fleet.UploadSoftwareInstallerPayload{{
956+
InstallScript: "install",
957+
InstallerFile: tfr0,
958+
StorageID: ins0,
959+
Filename: "installer0",
960+
Title: "ins0",
961+
Source: "apps",
962+
Version: "1",
963+
PreInstallQuery: "foo",
964+
UserID: user1.ID,
965+
Platform: "darwin",
966+
URL: "https://example.com",
967+
ValidatedLabels: &fleet.LabelIdentsWithScope{},
968+
BundleIdentifier: "com.example.different.ins0",
969+
}})
970+
require.NoError(t, err)
971+
softwareInstallers, err = ds.GetSoftwareInstallers(ctx, team.ID)
972+
require.NoError(t, err)
973+
require.Len(t, softwareInstallers, 1)
974+
assertSoftware([]fleet.SoftwareTitle{
975+
{Name: ins0, Source: "apps", Browser: "", BundleIdentifier: ptr.String("com.example.different.ins0")},
976+
})
977+
978+
// Add software installer with the same bundle id but different name
979+
err = ds.BatchSetSoftwareInstallers(ctx, &team.ID, []*fleet.UploadSoftwareInstallerPayload{{
980+
InstallScript: "install",
981+
InstallerFile: tfr0,
982+
StorageID: ins0,
983+
Filename: "installer0",
984+
Title: "ins0-different",
985+
Source: "apps",
986+
Version: "1",
987+
PreInstallQuery: "foo",
988+
UserID: user1.ID,
989+
Platform: "darwin",
990+
URL: "https://example.com",
991+
ValidatedLabels: &fleet.LabelIdentsWithScope{},
992+
BundleIdentifier: "com.example.ins0",
993+
}})
994+
require.NoError(t, err)
995+
softwareInstallers, err = ds.GetSoftwareInstallers(ctx, team.ID)
996+
require.NoError(t, err)
997+
require.Len(t, softwareInstallers, 1)
998+
assertSoftware([]fleet.SoftwareTitle{
999+
{Name: "ins0-different", Source: "apps", Browser: "", BundleIdentifier: ptr.String("com.example.ins0")},
1000+
})
1001+
9531002
// remove everything
9541003
err = ds.BatchSetSoftwareInstallers(ctx, &team.ID, []*fleet.UploadSoftwareInstallerPayload{})
9551004
require.NoError(t, err)

0 commit comments

Comments
 (0)