@@ -23,6 +23,8 @@ import (
23
23
// BundlesBasePath is the storage path used for storing bundle metadata
24
24
var BundlesBasePath = storage .MustParsePath ("/system/bundles" )
25
25
26
+ var ModulesInfoBasePath = storage .MustParsePath ("/system/modules" )
27
+
26
28
// Note: As needed these helpers could be memoized.
27
29
28
30
// ManifestStoragePath is the storage path used for the given named bundle manifest.
@@ -59,6 +61,14 @@ func metadataPath(name string) storage.Path {
59
61
return append (BundlesBasePath , name , "manifest" , "metadata" )
60
62
}
61
63
64
+ func moduleRegoVersionPath (id string ) storage.Path {
65
+ return append (ModulesInfoBasePath , strings .Trim (id , "/" ), "rego_version" )
66
+ }
67
+
68
+ func moduleInfoPath (id string ) storage.Path {
69
+ return append (ModulesInfoBasePath , strings .Trim (id , "/" ))
70
+ }
71
+
62
72
func read (ctx context.Context , store storage.Store , txn storage.Transaction , path storage.Path ) (interface {}, error ) {
63
73
value , err := store .Read (ctx , txn , path )
64
74
if err != nil {
@@ -166,6 +176,16 @@ func eraseWasmModulesFromStore(ctx context.Context, store storage.Store, txn sto
166
176
return suppressNotFound (err )
167
177
}
168
178
179
+ func eraseModuleRegoVersionsFromStore (ctx context.Context , store storage.Store , txn storage.Transaction , modules []string ) error {
180
+ for _ , module := range modules {
181
+ err := store .Write (ctx , txn , storage .RemoveOp , moduleInfoPath (module ), nil )
182
+ if err := suppressNotFound (err ); err != nil {
183
+ return err
184
+ }
185
+ }
186
+ return nil
187
+ }
188
+
169
189
// ReadWasmMetadataFromStore will read Wasm module resolver metadata from the store.
170
190
func ReadWasmMetadataFromStore (ctx context.Context , store storage.Store , txn storage.Transaction , name string ) ([]WasmResolver , error ) {
171
191
path := wasmEntrypointsPath (name )
@@ -626,7 +646,7 @@ func eraseBundles(ctx context.Context, store storage.Store, txn storage.Transact
626
646
return nil , err
627
647
}
628
648
629
- remaining , err := erasePolicies (ctx , store , txn , parserOpts , roots )
649
+ remaining , removed , err := erasePolicies (ctx , store , txn , parserOpts , roots )
630
650
if err != nil {
631
651
return nil , err
632
652
}
@@ -649,6 +669,11 @@ func eraseBundles(ctx context.Context, store storage.Store, txn storage.Transact
649
669
}
650
670
}
651
671
672
+ err = eraseModuleRegoVersionsFromStore (ctx , store , txn , removed )
673
+ if err != nil {
674
+ return nil , err
675
+ }
676
+
652
677
return remaining , nil
653
678
}
654
679
@@ -668,44 +693,103 @@ func eraseData(ctx context.Context, store storage.Store, txn storage.Transaction
668
693
return nil
669
694
}
670
695
671
- func erasePolicies (ctx context.Context , store storage.Store , txn storage.Transaction , parserOpts ast.ParserOptions , roots map [string ]struct {}) (map [string ]* ast.Module , error ) {
696
+ type moduleInfo struct {
697
+ RegoVersion ast.RegoVersion `json:"rego_version"`
698
+ }
699
+
700
+ func readModuleInfoFromStore (ctx context.Context , store storage.Store , txn storage.Transaction ) (map [string ]moduleInfo , error ) {
701
+ value , err := read (ctx , store , txn , ModulesInfoBasePath )
702
+ if suppressNotFound (err ) != nil {
703
+ return nil , err
704
+ }
705
+
706
+ if value == nil {
707
+ return nil , nil
708
+ }
709
+
710
+ if m , ok := value .(map [string ]any ); ok {
711
+ versions := make (map [string ]moduleInfo , len (m ))
712
+
713
+ for k , v := range m {
714
+ if m0 , ok := v .(map [string ]any ); ok {
715
+ if ver , ok := m0 ["rego_version" ]; ok {
716
+ if vs , ok := ver .(json.Number ); ok {
717
+ i , err := vs .Int64 ()
718
+ if err != nil {
719
+ return nil , fmt .Errorf ("corrupt rego version" )
720
+ }
721
+ versions [k ] = moduleInfo {RegoVersion : ast .RegoVersionFromInt (int (i ))}
722
+ }
723
+ }
724
+ }
725
+ }
726
+ return versions , nil
727
+ }
728
+
729
+ return nil , fmt .Errorf ("corrupt rego version" )
730
+ }
731
+
732
+ func erasePolicies (ctx context.Context , store storage.Store , txn storage.Transaction , parserOpts ast.ParserOptions , roots map [string ]struct {}) (map [string ]* ast.Module , []string , error ) {
672
733
673
734
ids , err := store .ListPolicies (ctx , txn )
674
735
if err != nil {
675
- return nil , err
736
+ return nil , nil , err
737
+ }
738
+
739
+ modulesInfo , err := readModuleInfoFromStore (ctx , store , txn )
740
+ if err != nil {
741
+ return nil , nil , fmt .Errorf ("failed to read module info from store: %w" , err )
742
+ }
743
+
744
+ getRegoVersion := func (modId string ) (ast.RegoVersion , bool ) {
745
+ info , ok := modulesInfo [modId ]
746
+ if ! ok {
747
+ return ast .RegoUndefined , false
748
+ }
749
+ return info .RegoVersion , true
676
750
}
677
751
678
752
remaining := map [string ]* ast.Module {}
753
+ var removed []string
679
754
680
755
for _ , id := range ids {
681
756
bs , err := store .GetPolicy (ctx , txn , id )
682
757
if err != nil {
683
- return nil , err
758
+ return nil , nil , err
684
759
}
685
- module , err := ast .ParseModuleWithOpts (id , string (bs ), parserOpts )
760
+
761
+ parserOptsCpy := parserOpts
762
+ if regoVersion , ok := getRegoVersion (id ); ok {
763
+ parserOptsCpy .RegoVersion = regoVersion
764
+ }
765
+
766
+ module , err := ast .ParseModuleWithOpts (id , string (bs ), parserOptsCpy )
686
767
if err != nil {
687
- return nil , err
768
+ return nil , nil , err
688
769
}
689
770
path , err := module .Package .Path .Ptr ()
690
771
if err != nil {
691
- return nil , err
772
+ return nil , nil , err
692
773
}
693
774
deleted := false
694
775
for root := range roots {
695
776
if RootPathsContain ([]string {root }, path ) {
696
777
if err := store .DeletePolicy (ctx , txn , id ); err != nil {
697
- return nil , err
778
+ return nil , nil , err
698
779
}
699
780
deleted = true
700
781
break
701
782
}
702
783
}
703
- if ! deleted {
784
+
785
+ if deleted {
786
+ removed = append (removed , id )
787
+ } else {
704
788
remaining [id ] = module
705
789
}
706
790
}
707
791
708
- return remaining , nil
792
+ return remaining , removed , nil
709
793
}
710
794
711
795
func writeManifestToStore (opts * ActivateOpts , name string , manifest Manifest ) error {
@@ -758,6 +842,12 @@ func writeDataAndModules(ctx context.Context, store storage.Store, txn storage.T
758
842
if err := store .UpsertPolicy (ctx , txn , path , mf .Raw ); err != nil {
759
843
return err
760
844
}
845
+
846
+ if regoVersion , err := b .RegoVersionForFile (mf .Path , ast .RegoUndefined ); err == nil && regoVersion != ast .RegoUndefined {
847
+ if err := write (ctx , store , txn , moduleRegoVersionPath (path ), regoVersion .Int ()); err != nil {
848
+ return fmt .Errorf ("failed to write rego version for '%s' in bundle '%s': %w" , mf .Path , name , err )
849
+ }
850
+ }
761
851
}
762
852
} else {
763
853
params .BasePaths = * b .Manifest .Roots
@@ -766,6 +856,25 @@ func writeDataAndModules(ctx context.Context, store storage.Store, txn storage.T
766
856
if err != nil {
767
857
return fmt .Errorf ("store truncate failed for bundle '%s': %v" , name , err )
768
858
}
859
+
860
+ for _ , f := range b .Raw {
861
+ if strings .HasSuffix (f .Path , RegoExt ) {
862
+ p , err := getFileStoragePath (f .Path )
863
+ if err != nil {
864
+ return fmt .Errorf ("failed get storage path for module '%s' in bundle '%s': %w" , f .Path , name , err )
865
+ }
866
+
867
+ if m := f .module ; m != nil {
868
+ // 'f.module.Path' contains the module's path as it relates to the bundle root, and can be used for looking up the rego-version.
869
+ // 'f.Path' can differ, based on how the bundle reader was initialized.
870
+ if regoVersion , err := b .RegoVersionForFile (f .module .Path , ast .RegoUndefined ); err == nil && regoVersion != ast .RegoUndefined {
871
+ if err := write (ctx , store , txn , moduleRegoVersionPath (p .String ()), regoVersion .Int ()); err != nil {
872
+ return fmt .Errorf ("failed to write rego version for '%s' in bundle '%s': %w" , f .Path , name , err )
873
+ }
874
+ }
875
+ }
876
+ }
877
+ }
769
878
}
770
879
}
771
880
0 commit comments