@@ -192,6 +192,125 @@ func TestResetState(t *testing.T) {
192192 require .ErrorIs (err , assert .AnError )
193193}
194194
195+ func TestResetStateInsecureRequiresOptIn (t * testing.T ) {
196+ ctx := t .Context ()
197+ require := require .New (t )
198+
199+ store := aferostore .New (& afero.Afero {Fs : afero .NewMemMapFs ()})
200+ hist := history .NewWithStore (slog .Default (), store )
201+ se := newSeedEngine (t )
202+ _ , manifestBytes , policies := newInsecureManifest (t )
203+
204+ originalGuard := New (hist , prometheus .NewRegistry (), slog .Default ())
205+ originalGuard .MakeInsecure ()
206+ state , err := originalGuard .UpdateState (ctx , nil , se , manifestBytes , policies )
207+ require .NoError (err )
208+ require .NotNil (state )
209+
210+ restartedGuard := New (hist , prometheus .NewRegistry (), slog .Default ())
211+ state , err = restartedGuard .ResetState (ctx , nil , & stubAuthorizer {err : assert .AnError })
212+ require .ErrorIs (err , ErrInsecureNotAllowed )
213+ require .Nil (state )
214+
215+ restartedGuard .MakeInsecure ()
216+ authz := & stubAuthorizer {
217+ se : se ,
218+ pk : testkeys .ECDSA (t ),
219+ }
220+ state , err = restartedGuard .ResetState (ctx , nil , authz )
221+ require .NoError (err )
222+ require .NotNil (state )
223+ }
224+
225+ func TestUpdateStateInsecure (t * testing.T ) {
226+ ctx := t .Context ()
227+
228+ _ , insecureManifestBytes , policies := newInsecureManifest (t )
229+ se := newSeedEngine (t )
230+
231+ t .Run ("rejected when allowInsecure is false" , func (t * testing.T ) {
232+ require := require .New (t )
233+
234+ store := aferostore .New (& afero.Afero {Fs : afero .NewMemMapFs ()})
235+ hist := history .NewWithStore (slog .Default (), store )
236+ g := New (hist , prometheus .NewRegistry (), slog .Default ())
237+
238+ state , err := g .UpdateState (ctx , nil , se , insecureManifestBytes , policies )
239+ require .ErrorIs (err , ErrInsecureNotAllowed )
240+ require .Nil (state )
241+ })
242+
243+ t .Run ("accepted when allowInsecure is true" , func (t * testing.T ) {
244+ require := require .New (t )
245+
246+ store := aferostore .New (& afero.Afero {Fs : afero .NewMemMapFs ()})
247+ hist := history .NewWithStore (slog .Default (), store )
248+ g := New (hist , prometheus .NewRegistry (), slog .Default ())
249+ g .MakeInsecure ()
250+
251+ state , err := g .UpdateState (ctx , nil , se , insecureManifestBytes , policies )
252+ require .NoError (err )
253+ require .NotNil (state )
254+ })
255+
256+ t .Run ("mixed manifest rejected even when allowInsecure is true" , func (t * testing.T ) {
257+ require := require .New (t )
258+
259+ _ , mixedManifestBytes , mixedPolicies := newMixedManifest (t )
260+
261+ store := aferostore .New (& afero.Afero {Fs : afero .NewMemMapFs ()})
262+ hist := history .NewWithStore (slog .Default (), store )
263+ g := New (hist , prometheus .NewRegistry (), slog .Default ())
264+ g .MakeInsecure ()
265+
266+ state , err := g .UpdateState (ctx , nil , se , mixedManifestBytes , mixedPolicies )
267+ require .ErrorIs (err , ErrMixedManifestNotAllowed )
268+ require .Nil (state )
269+ })
270+ }
271+
272+ func TestUpdateStateSecurityTransitions (t * testing.T ) {
273+ type manifestFixture struct {
274+ name string
275+ build func (* testing.T ) (* manifest.Manifest , []byte , [][]byte )
276+ }
277+ fixtures := []manifestFixture {
278+ {name : "secure" , build : newManifest },
279+ {name : "insecure" , build : newInsecureManifest },
280+ }
281+
282+ for _ , from := range fixtures {
283+ for _ , to := range fixtures {
284+ t .Run (from .name + " to " + to .name , func (t * testing.T ) {
285+ require := require .New (t )
286+ g , _ := newTestGuard (t )
287+ g .MakeInsecure ()
288+ se := newSeedEngine (t )
289+
290+ _ , fromManifestBytes , fromPolicies := from .build (t )
291+ oldState , err := g .UpdateState (t .Context (), nil , se , fromManifestBytes , fromPolicies )
292+ require .NoError (err )
293+ require .NotNil (oldState )
294+
295+ _ , toManifestBytes , toPolicies := to .build (t )
296+ nextState , err := g .UpdateState (t .Context (), oldState , se , toManifestBytes , toPolicies )
297+ if from .name == "insecure" && to .name == "secure" {
298+ require .ErrorIs (err , ErrInsecureToSecureTransition )
299+ require .Nil (nextState )
300+
301+ currentState , getErr := g .GetState (t .Context ())
302+ require .NoError (getErr )
303+ require .Same (oldState , currentState )
304+ return
305+ }
306+
307+ require .NoError (err )
308+ require .NotNil (nextState )
309+ })
310+ }
311+ }
312+ }
313+
195314func TestConcurrentUpdateState (t * testing.T ) {
196315 ctx := t .Context ()
197316 assert := assert .New (t )
@@ -543,6 +662,51 @@ func newManifest(t *testing.T) (*manifest.Manifest, []byte, [][]byte) {
543662 return mnfst , mnfstBytes , [][]byte {policy }
544663}
545664
665+ func newInsecureManifest (t * testing.T ) (* manifest.Manifest , []byte , [][]byte ) {
666+ t .Helper ()
667+ policy := []byte ("=== SOME REGO HERE ===" )
668+ policyHash := sha256 .Sum256 (policy )
669+ policyHashHex := manifest .NewHexString (policyHash [:])
670+
671+ mnfst := & manifest.Manifest {}
672+ mnfst .Policies = map [manifest.HexString ]manifest.PolicyEntry {
673+ policyHashHex : {
674+ SANs : []string {"test" },
675+ WorkloadSecretID : "test2" ,
676+ Role : manifest .RoleCoordinator ,
677+ },
678+ }
679+ mnfst .ReferenceValues .SNP = []manifest.SNPReferenceValues {
680+ {Platform : "Metal-QEMU-Insecure" },
681+ }
682+ mnfstBytes , err := json .Marshal (mnfst )
683+ require .NoError (t , err )
684+ return mnfst , mnfstBytes , [][]byte {policy }
685+ }
686+
687+ func newMixedManifest (t * testing.T ) (* manifest.Manifest , []byte , [][]byte ) {
688+ t .Helper ()
689+ policy := []byte ("=== SOME REGO HERE ===" )
690+ policyHash := sha256 .Sum256 (policy )
691+ policyHashHex := manifest .NewHexString (policyHash [:])
692+
693+ mnfst := & manifest.Manifest {}
694+ mnfst .Policies = map [manifest.HexString ]manifest.PolicyEntry {
695+ policyHashHex : {
696+ SANs : []string {"test" },
697+ WorkloadSecretID : "test2" ,
698+ Role : manifest .RoleCoordinator ,
699+ },
700+ }
701+ mnfst .ReferenceValues .SNP = []manifest.SNPReferenceValues {
702+ {Platform : "Metal-QEMU-Insecure" },
703+ {Platform : "Metal-QEMU-SNP" },
704+ }
705+ mnfstBytes , err := json .Marshal (mnfst )
706+ require .NoError (t , err )
707+ return mnfst , mnfstBytes , [][]byte {policy }
708+ }
709+
546710func newSeedEngine (t * testing.T ) * seedengine.SeedEngine {
547711 t .Helper ()
548712 data := make ([]byte , 32 )
0 commit comments