Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Security
### Added

- **OEM Attribute Capture:** Instances now store OEM and Aleph version information from Omaha update requests. ([#1286](https://github.com/flatcar/nebraska/pull/1286))
- **Multi-Step Updates with Floor Packages:** Added support for mandatory intermediate update versions (floor packages) that clients must install before reaching the target version. This enables safe migration paths for breaking changes by ensuring clients update through specific versions in order. Floor packages can be configured per channel with optional reasons and are architecture-specific. ([#1195](https://github.com/flatcar/nebraska/pull/1195))
- **Nebraska backend is able to use OIDC userinfo endpoint:** Some OIDC providers do not return group membership inside the access token. The Nebraska frontend passes this access token via the header `Authorization: Bearer <token>` to the backend which can then (optionally) call the OIDC provider's userinfo endpoint to gather group membership. ([#1279](https://github.com/flatcar/nebraska/pull/1279))

Expand Down
6 changes: 3 additions & 3 deletions backend/pkg/api/activity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ func TestGetActivity(t *testing.T) {
tChannel, _ := a.AddChannel(&Channel{Name: "test_channel", Color: "blue", ApplicationID: tApp.ID, PackageID: null.StringFrom(tPkg.ID)})
tGroup, _ := a.AddGroup(&Group{Name: "group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
tGroup2, _ := a.AddGroup(&Group{Name: "group2", ApplicationID: tApp.ID, PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
tInstance, _ := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance2, _ := a.RegisterInstance(uuid.New().String(), "", "10.0.0.2", "1.0.0", tApp.ID, tGroup2.ID)
tFakeInstance, _ := a.RegisterInstance("{"+uuid.New().String()+"}", "", "10.0.0.2", "1.0.0", tApp.ID, tGroup2.ID)
tInstance, _ := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))
tInstance2, _ := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.2"}, NewInstanceApplication(tApp.ID, tGroup2.ID, "1.0.0"))
tFakeInstance, _ := a.RegisterInstance(Instance{ID: "{" + uuid.New().String() + "}", IP: "10.0.0.2"}, NewInstanceApplication(tApp.ID, tGroup2.ID, "1.0.0"))

_ = a.newGroupActivityEntry(activityRolloutStarted, activitySuccess, tVersion, tApp.ID, tGroup.ID)
_ = a.newGroupActivityEntry(activityRolloutStarted, activitySuccess, tVersion, tApp.ID, tGroup2.ID)
Expand Down
6 changes: 3 additions & 3 deletions backend/pkg/api/applications_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func TestGetApp(t *testing.T) {
assert.NoError(t, err)
tChannel, _ := a.AddChannel(&Channel{Name: "test_channel", Color: "blue", ApplicationID: tApp.ID})
tGroup, _ := a.AddGroup(&Group{Name: "group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
_, _ = a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

app, err := a.GetApp(tApp.ID)
assert.NoError(t, err)
Expand Down Expand Up @@ -290,8 +290,8 @@ func TestGetAppsFiltered(t *testing.T) {
tGroup, _ := a.AddGroup(&Group{Name: "group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
realInstanceID := uuid.New().String()
fakeInstanceID := "{" + uuid.New().String() + "}"
_, _ = a.RegisterInstance(realInstanceID, "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(fakeInstanceID, "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(Instance{ID: realInstanceID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))
_, _ = a.RegisterInstance(Instance{ID: fakeInstanceID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

// should ignore fake instance in Instances count
apps, err := a.GetApps(tTeam.ID, 1, 10)
Expand Down
9 changes: 9 additions & 0 deletions backend/pkg/api/db/migrations/0021_add_instance_oem.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- +migrate Up

ALTER TABLE instance ADD COLUMN oem VARCHAR(256) NOT NULL DEFAULT '';
ALTER TABLE instance ADD COLUMN aleph_version VARCHAR(256) NOT NULL DEFAULT '';

-- +migrate Down

ALTER TABLE instance DROP COLUMN aleph_version;
ALTER TABLE instance DROP COLUMN oem;
32 changes: 16 additions & 16 deletions backend/pkg/api/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestRegisterEvent_InvalidParams(t *testing.T) {
tPkg, _ := a.AddPackage(&Package{Type: PkgTypeOther, URL: "http://sample.url/pkg", Version: "12.1.0", ApplicationID: tApp.ID})
tChannel, _ := a.AddChannel(&Channel{Name: "test_channel", Color: "blue", ApplicationID: tApp.ID, PackageID: null.StringFrom(tPkg.ID)})
tGroup, _ := a.AddGroup(&Group{Name: "group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
tInstance, _ := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance, _ := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

err := a.RegisterEvent(uuid.New().String(), tApp.ID, tGroup.ID, EventUpdateComplete, ResultSuccessReboot, "", "")
assert.Equal(t, ErrInvalidInstance, err)
Expand All @@ -33,7 +33,7 @@ func TestRegisterEvent_InvalidParams(t *testing.T) {
err = a.RegisterEvent(tInstance.ID, tApp.ID, tGroup.ID, EventUpdateDownloadStarted, ResultSuccess, "", "")
assert.Equal(t, ErrNoUpdateInProgress, err)

_, _ = a.GetUpdatePackage(tInstance.ID, "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
_, _ = a.GetUpdatePackage(Instance{ID: tInstance.ID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

err = a.RegisterEvent(tInstance.ID, tApp.ID, tGroup.ID, 1000, ResultSuccess, "", "")
assert.Equal(t, ErrInvalidEventTypeOrResult, err)
Expand All @@ -51,10 +51,10 @@ func TestRegisterEvent_TriggerEventConsequences(t *testing.T) {
tPkg, _ := a.AddPackage(&Package{Type: PkgTypeOther, URL: "http://sample.url/pkg", Version: "12.1.0", ApplicationID: tApp.ID})
tChannel, _ := a.AddChannel(&Channel{Name: "test_channel", Color: "blue", ApplicationID: tApp.ID, PackageID: null.StringFrom(tPkg.ID)})
tGroup, _ := a.AddGroup(&Group{Name: "group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
tInstance, _ := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance2, _ := a.RegisterInstance(uuid.New().String(), "", "10.0.0.2", "1.0.0", tApp.ID, tGroup.ID)
tInstance, _ := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))
tInstance2, _ := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.2"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

_, err := a.GetUpdatePackage(tInstance.ID, "", "10.0.0.1", "12.0.0", tApp.ID, tGroup.ID)
_, err := a.GetUpdatePackage(Instance{ID: tInstance.ID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "12.0.0"))
assert.NoError(t, err)

err = a.RegisterEvent(tInstance.ID, "{"+tApp.ID+"}", tGroup.ID, EventUpdateDownloadStarted, ResultSuccess, "", "")
Expand All @@ -77,7 +77,7 @@ func TestRegisterEvent_TriggerEventConsequences(t *testing.T) {
instance, _ = a.GetInstance(tInstance.ID, tApp.ID)
assert.Equal(t, null.IntFrom(int64(InstanceStatusComplete)), instance.Application.Status)

_, err = a.GetUpdatePackage(tInstance2.ID, "", "10.0.0.2", "12.0.0", tApp.ID, tGroup.ID)
_, err = a.GetUpdatePackage(Instance{ID: tInstance2.ID, IP: "10.0.0.2"}, NewInstanceApplication(tApp.ID, tGroup.ID, "12.0.0"))
assert.NoError(t, err)

err = a.RegisterEvent(tInstance2.ID, tApp.ID, tGroup.ID, EventUpdateComplete, ResultFailed, "", "")
Expand All @@ -97,9 +97,9 @@ func TestRegisterEvent_TriggerEventConsequences_FirstUpdateAttemptFailed(t *test
tPkg, _ := a.AddPackage(&Package{Type: PkgTypeOther, URL: "http://sample.url/pkg", Version: "12.1.0", ApplicationID: tApp.ID})
tChannel, _ := a.AddChannel(&Channel{Name: "test_channel", Color: "blue", ApplicationID: tApp.ID, PackageID: null.StringFrom(tPkg.ID)})
tGroup, _ := a.AddGroup(&Group{Name: "group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
tInstance, _ := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance, _ := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

_, err := a.GetUpdatePackage(tInstance.ID, "", "10.0.0.1", "12.0.0", tApp.ID, tGroup.ID)
_, err := a.GetUpdatePackage(Instance{ID: tInstance.ID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "12.0.0"))
assert.NoError(t, err)

err = a.RegisterEvent(tInstance.ID, tApp.ID, tGroup.ID, EventUpdateComplete, ResultFailed, "", "")
Expand All @@ -115,10 +115,10 @@ func TestRegisterEvent_CheckSuccessResult(t *testing.T) {
defer a.Close()

performUpdate := func(tApp *Application, tGroup *Group, resultType int) {
tInstance, err := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance, err := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))
assert.NoError(t, err)

_, err = a.GetUpdatePackage(tInstance.ID, "", "10.0.0.1", "12.0.0", tApp.ID, tGroup.ID)
_, err = a.GetUpdatePackage(Instance{ID: tInstance.ID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "12.0.0"))
assert.NoError(t, err)

err = a.RegisterEvent(tInstance.ID, "{"+tApp.ID+"}", tGroup.ID, EventUpdateDownloadStarted, ResultSuccess, "", "")
Expand Down Expand Up @@ -159,10 +159,10 @@ func TestRegisterEvent_CheckFlatcarSuccessResult(t *testing.T) {
defer a.Close()

performUpdate := func(tApp *Application, tGroup *Group, resultType, expectedInstanceStatus int) {
tInstance, err := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance, err := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))
assert.NoError(t, err)

_, err = a.GetUpdatePackage(tInstance.ID, "", "10.0.0.1", "12.0.0", tApp.ID, tGroup.ID)
_, err = a.GetUpdatePackage(Instance{ID: tInstance.ID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "12.0.0"))
assert.NoError(t, err)

err = a.RegisterEvent(tInstance.ID, "{"+tApp.ID+"}", tGroup.ID, EventUpdateDownloadStarted, ResultSuccess, "11.0.0", "")
Expand Down Expand Up @@ -207,10 +207,10 @@ func TestRegisterEvent_CheckFlatcarIgnoredUpdate(t *testing.T) {
tGroup, _ := a.AddGroup(&Group{Name: "group9", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: false, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})

performUpdate := func(previousVersion string) {
tInstance, err := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance, err := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))
assert.NoError(t, err)

_, err = a.GetUpdatePackage(tInstance.ID, "", "10.0.0.1", "12.0.0", tApp.ID, tGroup.ID)
_, err = a.GetUpdatePackage(Instance{ID: tInstance.ID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "12.0.0"))
assert.NoError(t, err)

err = a.RegisterEvent(tInstance.ID, "{"+tApp.ID+"}", tGroup.ID, EventUpdateDownloadStarted, ResultSuccess, previousVersion, "")
Expand Down Expand Up @@ -247,9 +247,9 @@ func TestRegisterEvent_GetEvent(t *testing.T) {
tPkg, _ := a.AddPackage(&Package{Type: PkgTypeOther, URL: "http://sample.url/pkg", Version: "12.1.0", ApplicationID: tApp.ID})
tChannel, _ := a.AddChannel(&Channel{Name: "test_channel", Color: "blue", ApplicationID: tApp.ID, PackageID: null.StringFrom(tPkg.ID)})
tGroup, _ := a.AddGroup(&Group{Name: "group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
tInstance, _ := a.RegisterInstance(uuid.New().String(), "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
tInstance, _ := a.RegisterInstance(Instance{ID: uuid.New().String(), IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

_, err := a.GetUpdatePackage(tInstance.ID, "", "10.0.0.1", "12.0.0", tApp.ID, tGroup.ID)
_, err := a.GetUpdatePackage(Instance{ID: tInstance.ID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "12.0.0"))
assert.NoError(t, err)

_, err = a.GetEvent(tInstance.ID, tApp.ID, time.Now())
Expand Down
12 changes: 6 additions & 6 deletions backend/pkg/api/groups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ func TestGetGroupsFiltered(t *testing.T) {
realInstanceID := uuid.New().String()
fakeInstanceID1 := "{" + uuid.New().String() + "}"
fakeInstanceID2 := "{" + uuid.New().String() + "}"
_, _ = a.RegisterInstance(realInstanceID, "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(fakeInstanceID1, "", "10.0.0.1", "2.0.0", tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(fakeInstanceID2, "", "10.0.0.1", "1.0.0", tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(Instance{ID: realInstanceID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))
_, _ = a.RegisterInstance(Instance{ID: fakeInstanceID1, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "2.0.0"))
_, _ = a.RegisterInstance(Instance{ID: fakeInstanceID2, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, "1.0.0"))

groups, err := a.GetGroups(tApp.ID, 0, 0)
assert.NoError(t, err)
Expand Down Expand Up @@ -226,7 +226,7 @@ func TestGetVersionCountTimeline(t *testing.T) {
tGroup, _ := a.AddGroup(&Group{Name: "test_group1", ApplicationID: tApp.ID, ChannelID: null.StringFrom(tChannel.ID), PolicyUpdatesEnabled: true, PolicySafeMode: true, PolicyPeriodInterval: "15 minutes", PolicyMaxUpdatesPerPeriod: 2, PolicyUpdateTimeout: "60 minutes"})
instanceID := uuid.New().String()

_, _ = a.RegisterInstance(instanceID, "", "10.0.0.1", version, tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(Instance{ID: instanceID, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, version))

instance, err := a.GetInstance(instanceID, tApp.ID)
assert.NoError(t, err)
Expand Down Expand Up @@ -304,14 +304,14 @@ func TestGetStatusCountTimeline(t *testing.T) {
instanceID1 := uuid.New().String()
instanceID2 := uuid.New().String()

_, _ = a.RegisterInstance(instanceID1, "", "10.0.0.1", version, tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(Instance{ID: instanceID1, IP: "10.0.0.1"}, NewInstanceApplication(tApp.ID, tGroup.ID, version))

instance1, err := a.GetInstance(instanceID1, tApp.ID)
assert.NoError(t, err)

_ = a.grantUpdate(instance1, version)
_ = a.updateInstanceStatus(instanceID1, tApp.ID, InstanceStatusComplete)
_, _ = a.RegisterInstance(instanceID2, "", "10.0.0.2", version, tApp.ID, tGroup.ID)
_, _ = a.RegisterInstance(Instance{ID: instanceID2, IP: "10.0.0.2"}, NewInstanceApplication(tApp.ID, tGroup.ID, version))

instance2, err := a.GetInstance(instanceID2, tApp.ID)
assert.NoError(t, err)
Expand Down
Loading
Loading