@@ -10,6 +10,7 @@ import (
1010 "os"
1111 "strconv"
1212 "testing"
13+ "time"
1314
1415 "github.com/google/go-cmp/cmp"
1516 "github.com/tailscale/setec/audit"
@@ -227,6 +228,165 @@ func TestPut(t *testing.T) {
227228 mustGetVersion (ver3 , "test value 2" )
228229}
229230
231+ func TestCreateVersion (t * testing.T ) {
232+ secretName := "secret1"
233+ checkVersion := func (d * setectest.DB , version api.SecretVersion , want []byte ) * api.SecretValue {
234+ t .Helper ()
235+ got := d .MustGetVersion (d .Superuser , secretName , version )
236+ if ! bytes .Equal (got .Value , want ) {
237+ t .Fatalf ("Get %q version %v: got %q, want %q" , secretName , version , string (got .Value ), string (want ))
238+ }
239+ return got
240+ }
241+ checkActiveVersion := func (d * setectest.DB , want []byte ) {
242+ t .Helper ()
243+ got := d .MustGet (d .Superuser , secretName )
244+ if ! bytes .Equal (got .Value , want ) {
245+ t .Fatalf ("Get active %q: got %q, want %q" , secretName , string (got .Value ), string (want ))
246+ }
247+ }
248+
249+ testValue1 := []byte ("test value 1" )
250+ testValue2 := []byte ("test value 2" )
251+ testValue3 := []byte ("test value 3" )
252+ testValue4 := []byte ("test value 4" )
253+
254+ // One use for setting explicit versions is doing time-based rotation using something like
255+ // UNIX timestamps. This simulates that.
256+ year2099 := api .SecretVersion (time .Date (2099 , 12 , 31 , 24 , 60 , 60 , 0 , time .UTC ).Unix ())
257+
258+ t .Run ("create" , func (t * testing.T ) {
259+ d := setectest .NewDB (t , nil )
260+
261+ // Creating first version should be allowed.
262+ err := d .Actual .CreateVersion (d .Superuser , secretName , 1 , testValue1 )
263+ if err != nil {
264+ t .Fatalf ("failed to create first version: %s" , err )
265+ }
266+ checkVersion (d , 1 , testValue1 )
267+ checkActiveVersion (d , testValue1 )
268+
269+ // Creating a disjoint version for the first time should be allowed.
270+ err = d .Actual .CreateVersion (d .Superuser , secretName , year2099 , testValue2 )
271+ if err != nil {
272+ t .Fatalf ("failed to create disjoint version: %s" , err )
273+ }
274+ checkVersion (d , year2099 , testValue2 )
275+ checkActiveVersion (d , testValue2 )
276+
277+ // Creating a disjoint version for the second time should not be allowed.
278+ err = d .Actual .CreateVersion (d .Superuser , secretName , year2099 , testValue2 )
279+ if ! errors .Is (err , db .ErrVersionTaken ) {
280+ t .Fatalf ("Setting existing version should have failed with %q but returned %q" , db .ErrVersionTaken , err )
281+ }
282+ checkVersion (d , year2099 , testValue2 )
283+ checkActiveVersion (d , testValue2 )
284+
285+ // Creating an in-between version should be allowed.
286+ err = d .Actual .CreateVersion (d .Superuser , secretName , 100 , testValue3 )
287+ if err != nil {
288+ t .Fatalf ("failed to create in-between version: %s" , err )
289+ }
290+ checkVersion (d , 100 , testValue3 )
291+ checkActiveVersion (d , testValue3 )
292+ })
293+
294+ t .Run ("create_disjoint_allowed" , func (t * testing.T ) {
295+ d := setectest .NewDB (t , nil )
296+
297+ // Creating with disjoint version should be allowed.
298+ err := d .Actual .CreateVersion (d .Superuser , secretName , 100 , testValue1 )
299+ if err != nil {
300+ t .Fatalf ("failed to create first version: %s" , err )
301+ }
302+ checkVersion (d , 100 , testValue1 )
303+ checkActiveVersion (d , testValue1 )
304+ })
305+
306+ t .Run ("create_zero_prohibited" , func (t * testing.T ) {
307+ d := setectest .NewDB (t , nil )
308+
309+ // Creating with disjoint version should be allowed.
310+ err := d .Actual .CreateVersion (d .Superuser , secretName , 0 , testValue1 )
311+ if ! errors .Is (err , db .ErrInvalidVersion ) {
312+ t .Fatalf ("Setting version to 0 should have failed with %q but returned %q" , db .ErrInvalidVersion , err )
313+ }
314+ })
315+
316+ t .Run ("put_create_put_delete" , func (t * testing.T ) {
317+ d := setectest .NewDB (t , nil )
318+
319+ // Putting a new secret works
320+ version , err := d .Actual .Put (d .Superuser , secretName , testValue1 )
321+ if err != nil {
322+ t .Fatalf ("failed to Put new secret: %s" , err )
323+ }
324+ if version != 1 {
325+ t .Fatalf ("expected first Put to create version 1, but created %d" , version )
326+ }
327+ checkVersion (d , 1 , testValue1 )
328+ checkActiveVersion (d , testValue1 )
329+
330+ // Creating a higher version works
331+ err = d .Actual .CreateVersion (d .Superuser , secretName , 100 , testValue3 )
332+ if err != nil {
333+ t .Fatalf ("failed to create higher version: %s" , err )
334+ }
335+ checkVersion (d , 100 , testValue3 )
336+ checkActiveVersion (d , testValue3 )
337+
338+ // Creating an in-between version works
339+ err = d .Actual .CreateVersion (d .Superuser , secretName , 10 , testValue2 )
340+ if err != nil {
341+ t .Fatalf ("failed to create in-between version: %s" , err )
342+ }
343+ checkVersion (d , 10 , testValue2 )
344+ checkActiveVersion (d , testValue2 )
345+
346+ // Putting gets the next higher version, but without activating
347+ version , err = d .Actual .Put (d .Superuser , secretName , testValue4 )
348+ if err != nil {
349+ t .Fatalf ("failed to Put new secret: %s" , err )
350+ }
351+ if version != 101 {
352+ t .Fatalf ("expected second Put to create version 101, but created %d" , version )
353+ }
354+ checkVersion (d , 101 , testValue4 )
355+ checkActiveVersion (d , testValue2 )
356+
357+ // Deleting highest version allowed
358+ err = d .Actual .DeleteVersion (d .Superuser , secretName , 101 )
359+ if err != nil {
360+ t .Fatalf ("failed to delete highest version: %s" , err )
361+ }
362+ checkActiveVersion (d , testValue2 )
363+
364+ // Deleting the next highest version also allowed
365+ err = d .Actual .DeleteVersion (d .Superuser , secretName , 100 )
366+ if err != nil {
367+ t .Fatalf ("failed to delete next-highest version: %s" , err )
368+ }
369+ checkActiveVersion (d , testValue2 )
370+
371+ // Re-creating deleted version is not allowed
372+ err = d .Actual .CreateVersion (d .Superuser , secretName , 100 , testValue2 )
373+ if ! errors .Is (err , db .ErrVersionTaken ) {
374+ t .Fatalf ("Recreating deleted version should have failed with %q but returned %q" , db .ErrVersionTaken , err )
375+ }
376+
377+ // Putting gets the next higher version despite deletes
378+ version , err = d .Actual .Put (d .Superuser , secretName , testValue4 )
379+ if err != nil {
380+ t .Fatalf ("failed to Put new secret: %s" , err )
381+ }
382+ if version != 102 {
383+ t .Fatalf ("expected second Put to create version 102, but created %d" , version )
384+ }
385+ checkVersion (d , 102 , testValue4 )
386+ checkActiveVersion (d , testValue2 )
387+ })
388+ }
389+
230390func TestDelete (t * testing.T ) {
231391 d := setectest .NewDB (t , nil )
232392 id := d .Superuser
0 commit comments