SSVL: add timestamp-based check for the exclude-any case (#24889)
Co-authored-by: Jahziel Villasana-Espinoza <jahziel@fleetdm.com>
This commit is contained in:
co-authored by
Jahziel Villasana-Espinoza
parent
89862b012b
commit
b4516df1d3
@@ -2386,7 +2386,7 @@ INNER JOIN software_cve scve ON scve.software_id = s.id
|
||||
SELECT 1 FROM (
|
||||
|
||||
-- no labels
|
||||
SELECT 0 AS count_installer_labels, 0 AS count_host_labels
|
||||
SELECT 0 AS count_installer_labels, 0 AS count_host_labels, 0 as count_host_updated_after_labels
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM software_installer_labels sil WHERE sil.software_installer_id = si.id
|
||||
)
|
||||
@@ -2396,7 +2396,8 @@ INNER JOIN software_cve scve ON scve.software_id = s.id
|
||||
-- include any
|
||||
SELECT
|
||||
COUNT(*) AS count_installer_labels,
|
||||
COUNT(lm.label_id) AS count_host_labels
|
||||
COUNT(lm.label_id) AS count_host_labels,
|
||||
0 as count_host_updated_after_labels
|
||||
FROM
|
||||
software_installer_labels sil
|
||||
LEFT OUTER JOIN label_membership lm ON lm.label_id = sil.label_id
|
||||
@@ -2405,27 +2406,33 @@ INNER JOIN software_cve scve ON scve.software_id = s.id
|
||||
sil.software_installer_id = si.id
|
||||
AND sil.exclude = 0
|
||||
HAVING
|
||||
count_installer_labels > 0 AND count_host_labels > 0
|
||||
|
||||
count_installer_labels > 0 AND count_host_labels > 0
|
||||
|
||||
UNION
|
||||
|
||||
-- exclude any
|
||||
-- exclude any, ignore software that depends on labels created
|
||||
-- _after_ the label_updated_at timestamp of the host (because
|
||||
-- we don't have results for that label yet, the host may or may
|
||||
-- not be a member).
|
||||
SELECT
|
||||
COUNT(*) AS count_installer_labels,
|
||||
COUNT(lm.label_id) AS count_host_labels
|
||||
COUNT(lm.label_id) AS count_host_labels,
|
||||
SUM(CASE WHEN lbl.created_at IS NOT NULL AND :host_label_updated_at >= lbl.created_at THEN 1 ELSE 0 END) as count_host_updated_after_labels
|
||||
FROM
|
||||
software_installer_labels sil
|
||||
LEFT OUTER JOIN label_membership lm ON lm.label_id = sil.label_id
|
||||
AND lm.host_id = :host_id
|
||||
LEFT OUTER JOIN labels lbl
|
||||
ON lbl.id = sil.label_id
|
||||
LEFT OUTER JOIN label_membership lm
|
||||
ON lm.label_id = sil.label_id AND lm.host_id = :host_id
|
||||
WHERE
|
||||
sil.software_installer_id = si.id
|
||||
AND sil.exclude = 1
|
||||
HAVING
|
||||
count_installer_labels > 0 AND count_host_labels = 0
|
||||
count_installer_labels > 0 AND count_installer_labels = count_host_updated_after_labels AND count_host_labels = 0
|
||||
) t
|
||||
)
|
||||
)
|
||||
-- it's some other type of software that has been checked above
|
||||
-- it's some other type of software that has been checked above
|
||||
ELSE true END
|
||||
)
|
||||
%s %s
|
||||
@@ -2472,6 +2479,7 @@ INNER JOIN software_cve scve ON scve.software_id = s.id
|
||||
stmt := stmtInstalled
|
||||
if opts.OnlyAvailableForInstall || (opts.IncludeAvailableForInstall && !opts.VulnerableOnly) {
|
||||
namedArgs["vpp_apps_platforms"] = fleet.VPPAppsPlatforms
|
||||
namedArgs["host_label_updated_at"] = host.LabelUpdatedAt
|
||||
if fleet.IsLinux(host.Platform) {
|
||||
namedArgs["host_compatible_platforms"] = fleet.HostLinuxOSs
|
||||
} else {
|
||||
|
||||
@@ -1174,7 +1174,7 @@ WHERE
|
||||
`
|
||||
|
||||
const deleteAllInstallerLabels = `
|
||||
DELETE FROM
|
||||
DELETE FROM
|
||||
software_installer_labels
|
||||
WHERE
|
||||
software_installer_id = ?
|
||||
@@ -1611,7 +1611,7 @@ func (ds *Datastore) IsSoftwareInstallerLabelScoped(ctx context.Context, install
|
||||
SELECT 1 FROM (
|
||||
|
||||
-- no labels
|
||||
SELECT 0 AS count_installer_labels, 0 AS count_host_labels
|
||||
SELECT 0 AS count_installer_labels, 0 AS count_host_labels, 0 as count_host_updated_after_labels
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM software_installer_labels sil WHERE sil.software_installer_id = :installer_id
|
||||
)
|
||||
@@ -1621,7 +1621,8 @@ func (ds *Datastore) IsSoftwareInstallerLabelScoped(ctx context.Context, install
|
||||
-- include any
|
||||
SELECT
|
||||
COUNT(*) AS count_installer_labels,
|
||||
COUNT(lm.label_id) AS count_host_labels
|
||||
COUNT(lm.label_id) AS count_host_labels,
|
||||
0 as count_host_updated_after_labels
|
||||
FROM
|
||||
software_installer_labels sil
|
||||
LEFT OUTER JOIN label_membership lm ON lm.label_id = sil.label_id
|
||||
@@ -1630,23 +1631,34 @@ func (ds *Datastore) IsSoftwareInstallerLabelScoped(ctx context.Context, install
|
||||
sil.software_installer_id = :installer_id
|
||||
AND sil.exclude = 0
|
||||
HAVING
|
||||
count_installer_labels > 0 AND count_host_labels > 0
|
||||
|
||||
count_installer_labels > 0 AND count_host_labels > 0
|
||||
|
||||
UNION
|
||||
|
||||
-- exclude any
|
||||
-- exclude any, ignore software that depends on labels created
|
||||
-- _after_ the label_updated_at timestamp of the host (because
|
||||
-- we don't have results for that label yet, the host may or may
|
||||
-- not be a member).
|
||||
SELECT
|
||||
COUNT(*) AS count_installer_labels,
|
||||
COUNT(lm.label_id) AS count_host_labels
|
||||
COUNT(lm.label_id) AS count_host_labels,
|
||||
SUM(CASE
|
||||
WHEN
|
||||
lbl.created_at IS NOT NULL AND (SELECT label_updated_at FROM hosts WHERE id = :host_id) >= lbl.created_at THEN 1
|
||||
ELSE
|
||||
0
|
||||
END) as count_host_updated_after_labels
|
||||
FROM
|
||||
software_installer_labels sil
|
||||
LEFT OUTER JOIN label_membership lm ON lm.label_id = sil.label_id
|
||||
AND lm.host_id = :host_id
|
||||
LEFT OUTER JOIN labels lbl
|
||||
ON lbl.id = sil.label_id
|
||||
LEFT OUTER JOIN label_membership lm
|
||||
ON lm.label_id = sil.label_id AND lm.host_id = :host_id
|
||||
WHERE
|
||||
sil.software_installer_id = :installer_id
|
||||
AND sil.exclude = 1
|
||||
HAVING
|
||||
count_installer_labels > 0 AND count_host_labels = 0
|
||||
count_installer_labels > 0 AND count_installer_labels = count_host_updated_after_labels AND count_host_labels = 0
|
||||
) t
|
||||
`
|
||||
namedArgs := map[string]any{
|
||||
|
||||
@@ -5258,6 +5258,8 @@ func testListHostSoftwareWithLabelScoping(t *testing.T, ds *Datastore) {
|
||||
nanoEnroll(t, ds, host, false)
|
||||
user1 := test.NewUser(t, ds, "Alice", "alice@example.com", true)
|
||||
|
||||
time.Sleep(time.Second) // ensure the labels_updated_at timestamp is before labels creation
|
||||
|
||||
// create a software installer
|
||||
tfr1, err := fleet.NewTempFileReader(strings.NewReader("hello"), t.TempDir)
|
||||
require.NoError(t, err)
|
||||
@@ -5324,6 +5326,10 @@ func testListHostSoftwareWithLabelScoping(t *testing.T, ds *Datastore) {
|
||||
|
||||
// assign the label to the host
|
||||
require.NoError(t, ds.AddLabelsToHost(ctx, host.ID, []uint{label1.ID}))
|
||||
host.LabelUpdatedAt = time.Now()
|
||||
err = ds.UpdateHost(ctx, host)
|
||||
require.NoError(t, err)
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// assign the label to the software installer
|
||||
err = setOrUpdateSoftwareInstallerLabelsDB(ctx, ds.writer(ctx), installerID1, fleet.LabelIdentsWithScope{
|
||||
@@ -5407,6 +5413,10 @@ func testListHostSoftwareWithLabelScoping(t *testing.T, ds *Datastore) {
|
||||
|
||||
// Now host has label1, label2
|
||||
require.NoError(t, ds.AddLabelsToHost(ctx, host.ID, []uint{label2.ID}))
|
||||
host.LabelUpdatedAt = time.Now()
|
||||
err = ds.UpdateHost(ctx, host)
|
||||
require.NoError(t, err)
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// List should be back to just installer1
|
||||
software, _, err = ds.ListHostSoftware(ctx, host, opts)
|
||||
@@ -5443,6 +5453,7 @@ func testListHostSoftwareWithLabelScoping(t *testing.T, ds *Datastore) {
|
||||
installerID3, _, err := ds.MatchOrCreateSoftwareInstaller(ctx, installer3)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
expectedInstallers[installer3.Filename] = &fleet.SoftwarePackageOrApp{
|
||||
Name: installer3.Filename,
|
||||
Version: installer3.Version,
|
||||
@@ -5459,7 +5470,29 @@ func testListHostSoftwareWithLabelScoping(t *testing.T, ds *Datastore) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// We should have [installerID1, installerID3]
|
||||
// We should have [installerID1, installerID3], but the exclude any label has
|
||||
// no results for this host yet, so it's just installerID1 for now.
|
||||
software, _, err = ds.ListHostSoftware(ctx, host, opts)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, software, 1)
|
||||
|
||||
// installer1 is still in scope
|
||||
scoped, err = ds.IsSoftwareInstallerLabelScoped(ctx, installerID1, host.ID)
|
||||
require.NoError(t, err)
|
||||
require.True(t, scoped)
|
||||
|
||||
// installer3 is not in scope yet, because label is "exclude any" and host doesn't have results
|
||||
scoped, err = ds.IsSoftwareInstallerLabelScoped(ctx, installerID3, host.ID)
|
||||
require.NoError(t, err)
|
||||
require.False(t, scoped)
|
||||
|
||||
// mark as if label had been reported (but host is still not a member)
|
||||
host.LabelUpdatedAt = time.Now()
|
||||
err = ds.UpdateHost(ctx, host)
|
||||
require.NoError(t, err)
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// now has 2 software (installer1 and 3)
|
||||
software, _, err = ds.ListHostSoftware(ctx, host, opts)
|
||||
require.NoError(t, err)
|
||||
checkSoftware(software, installer2.Filename)
|
||||
@@ -5470,9 +5503,9 @@ func testListHostSoftwareWithLabelScoping(t *testing.T, ds *Datastore) {
|
||||
require.True(t, scoped)
|
||||
|
||||
// installer3 is in scope, because label is "exclude any" and host doesn't have the label
|
||||
scoped, err = ds.IsSoftwareInstallerLabelScoped(ctx, installerID2, host.ID)
|
||||
scoped, err = ds.IsSoftwareInstallerLabelScoped(ctx, installerID3, host.ID)
|
||||
require.NoError(t, err)
|
||||
require.False(t, scoped)
|
||||
require.True(t, scoped)
|
||||
|
||||
// Now include hosts with label4. No host has this label, so we shouldn't see installerID3 anymore.
|
||||
err = setOrUpdateSoftwareInstallerLabelsDB(ctx, ds.writer(ctx), installerID3, fleet.LabelIdentsWithScope{
|
||||
@@ -5490,4 +5523,9 @@ func testListHostSoftwareWithLabelScoping(t *testing.T, ds *Datastore) {
|
||||
scoped, err = ds.IsSoftwareInstallerLabelScoped(ctx, installerID1, host.ID)
|
||||
require.NoError(t, err)
|
||||
require.True(t, scoped)
|
||||
|
||||
// installer3 is not in scope
|
||||
scoped, err = ds.IsSoftwareInstallerLabelScoped(ctx, installerID3, host.ID)
|
||||
require.NoError(t, err)
|
||||
require.False(t, scoped)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user