-
Notifications
You must be signed in to change notification settings - Fork 392
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fetch installed apps from iPhone/iPad devices. (#20733)
Part 2 of #19447 - iOS and iPadOS user-installed apps are loaded into Fleet - Added an additional identifier into software_titles table to differentiate between iOS/iPadOS apps - Updated nano queue timestamp precision Note: TestIntegrationsMDM/TestVPPApps fails when run as part of the suite, but passes standalone. I'd like to proceed with merging this PR, and figure out the issue next week. # Checklist for submitter <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [x] Added support on fleet's osquery simulator `cmd/osquery-perf` for new osquery data ingestion features. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Roberto Dip <rroperzh@gmail.com>
- Loading branch information
Showing
18 changed files
with
788 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
- iOS and iPadOS device details refetch can now be triggered with the existing `POST /api/latest/fleet/hosts/:id/refetch` endpoint. | ||
- iOS and iPadOS user-installed apps can be viewed in Fleet |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
...tastore/mysql/migrations/tables/20240725182118_AddAdditionalIdentifierToSoftwareTitles.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package tables | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
) | ||
|
||
func init() { | ||
MigrationClient.AddMigration(Up_20240725182118, Down_20240725182118) | ||
} | ||
|
||
func Up_20240725182118(tx *sql.Tx) error { | ||
if columnExists(tx, "software_titles", "additional_identifier") { | ||
return nil | ||
} | ||
|
||
_, err := tx.Exec(` | ||
ALTER TABLE software_titles | ||
ADD COLUMN additional_identifier TINYINT UNSIGNED GENERATED ALWAYS AS | ||
(CASE | ||
WHEN source = 'ios_apps' then 1 | ||
WHEN source = 'ipados_apps' then 2 | ||
WHEN bundle_identifier IS NOT NULL THEN 0 | ||
ELSE NULL | ||
END) VIRTUAL`) | ||
if err != nil { | ||
return fmt.Errorf("adding additional_identifier to software_titles: %w", err) | ||
} | ||
|
||
_, err = tx.Exec(`ALTER TABLE software_titles DROP INDEX idx_software_titles_bundle_identifier`) | ||
if err != nil { | ||
return fmt.Errorf("dropping unique key for bundle_identifier in software_titles: %w", err) | ||
} | ||
|
||
_, err = tx.Exec(`ALTER TABLE software_titles ADD UNIQUE KEY idx_software_titles_bundle_identifier (bundle_identifier, additional_identifier)`) | ||
if err != nil { | ||
return fmt.Errorf("adding unique key for identifiers in software_titles: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func Down_20240725182118(_ *sql.Tx) error { | ||
return nil | ||
} |
86 changes: 86 additions & 0 deletions
86
...re/mysql/migrations/tables/20240725182118_AddAdditionalIdentifierToSoftwareTitles_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package tables | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/fleetdm/fleet/v4/server/ptr" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestUp_20240725182118(t *testing.T) { | ||
db := applyUpToPrev(t) | ||
|
||
// Data before ios and ipados apps were added | ||
dataStmt := ` | ||
INSERT INTO software_titles (id, name, source, browser, bundle_identifier) VALUES | ||
(1, 'Foo.app', 'apps', '', 'com.example.foo'), | ||
(2, 'Foo2.app', 'apps', '', 'com.example.foo2'), | ||
(3, 'Chrome Extension', 'chrome_extensions', 'chrome', NULL), | ||
(4, 'Microsoft Teams.exe', 'programs', '', NULL); | ||
` | ||
|
||
_, err := db.Exec(dataStmt) | ||
require.NoError(t, err) | ||
applyNext(t, db) | ||
|
||
type softwareTitle struct { | ||
Name string `db:"name"` | ||
Source string `db:"source"` | ||
Browser string `db:"browser"` | ||
BundleIdentifier *string `db:"bundle_identifier"` | ||
AdditionalIdentifier *uint32 `db:"additional_identifier"` | ||
} | ||
|
||
var titles []softwareTitle | ||
err = db.Select(&titles, `SELECT name, source, browser, bundle_identifier, additional_identifier FROM software_titles`) | ||
require.NoError(t, err) | ||
zero := uint32(0) | ||
expectedTitles := []softwareTitle{ | ||
{"Foo.app", "apps", "", ptr.String("com.example.foo"), &zero}, | ||
{"Foo2.app", "apps", "", ptr.String("com.example.foo2"), &zero}, | ||
{"Chrome Extension", "chrome_extensions", "chrome", nil, nil}, | ||
{"Microsoft Teams.exe", "programs", "", nil, nil}, | ||
} | ||
assert.ElementsMatch(t, expectedTitles, titles) | ||
|
||
// Ensure that the unique key is enforced | ||
dataStmt = ` | ||
INSERT INTO software_titles (id, name, source, browser, bundle_identifier) VALUES | ||
(100, 'Foo3', 'foo', '', 'com.example.foo'); | ||
` | ||
_, err = db.Exec(dataStmt) | ||
assert.ErrorContains(t, err, "Duplicate entry") | ||
|
||
// Add ios and ipados apps | ||
dataStmt = ` | ||
INSERT INTO software_titles (id, name, source, browser, bundle_identifier) VALUES | ||
(5, 'Foo', 'ios_apps', '', 'com.example.foo'), | ||
(6, 'Foo', 'ipados_apps', '', 'com.example.foo'), | ||
(7, 'Bar-Pocket', 'ios_apps', '', 'com.example.bar-pocket'), | ||
(8, 'Bar', 'ipados_apps', '', 'com.example.bar'); | ||
` | ||
_, err = db.Exec(dataStmt) | ||
require.NoError(t, err) | ||
|
||
err = db.Select(&titles, `SELECT name, source, browser, bundle_identifier, additional_identifier FROM software_titles`) | ||
require.NoError(t, err) | ||
one := uint32(1) | ||
two := uint32(2) | ||
expectedTitles = append(expectedTitles, []softwareTitle{ | ||
{"Foo", "ios_apps", "", ptr.String("com.example.foo"), &one}, | ||
{"Foo", "ipados_apps", "", ptr.String("com.example.foo"), &two}, | ||
{"Bar-Pocket", "ios_apps", "", ptr.String("com.example.bar-pocket"), &one}, | ||
{"Bar", "ipados_apps", "", ptr.String("com.example.bar"), &two}, | ||
}...) | ||
assert.ElementsMatch(t, expectedTitles, titles) | ||
|
||
// Ensure that the unique key is enforced | ||
dataStmt = ` | ||
INSERT INTO software_titles (id, name, source, browser, bundle_identifier) VALUES | ||
(200, 'Foo-Pocket', 'ipados_apps', '', 'com.example.foo'); | ||
` | ||
_, err = db.Exec(dataStmt) | ||
assert.ErrorContains(t, err, "Duplicate entry") | ||
|
||
} |
Oops, something went wrong.