-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathfeature-flags.go
More file actions
171 lines (147 loc) · 4.03 KB
/
feature-flags.go
File metadata and controls
171 lines (147 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package wrappers
import (
"errors"
"github.com/checkmarx/ast-cli/internal/logger"
)
const tenantIDClaimKey = "tenant_id"
const PackageEnforcementEnabled = "PACKAGE_ENFORCEMENT_ENABLED"
const CVSSV3Enabled = "CVSS_V3_ENABLED"
const MinioEnabled = "MINIO_ENABLED"
const SCSEngineCLIEnabled = "NEW_2MS_SCORECARD_RESULTS_CLI_ENABLED"
const NewScanReportEnabled = "NEW_SAST_SCAN_REPORT_ENABLED"
const maxRetries = 3
var DefaultFFLoad bool = false
var FeatureFlagsBaseMap = []CommandFlags{
{
CommandName: "cx scan create",
FeatureFlags: []FlagBase{
{
Name: PackageEnforcementEnabled,
Default: true,
},
{
Name: MinioEnabled,
Default: true,
},
},
},
{
CommandName: "cx project create",
},
{
CommandName: "cx import",
FeatureFlags: []FlagBase{
{
Name: MinioEnabled,
Default: true,
},
},
},
{
CommandName: "cx results show",
FeatureFlags: []FlagBase{
{
Name: NewScanReportEnabled,
Default: false,
},
},
},
{
CommandName: "cx triage update",
FeatureFlags: []FlagBase{
{
Name: CVSSV3Enabled,
Default: false,
},
},
},
}
var featureFlags = map[string]bool{}
var featureFlagsCache = map[string]bool{}
func HandleFeatureFlags(featureFlagsWrapper FeatureFlagsWrapper) error {
allFlags, err := featureFlagsWrapper.GetAll()
if err != nil {
LoadFeatureFlagsDefaultValues()
return nil
}
loadFeatureFlagsMap(*allFlags)
return nil
}
func GetSpecificFeatureFlag(featureFlagsWrapper FeatureFlagsWrapper, flagName string) (*FeatureFlagResponseModel, error) {
if value, exists := featureFlagsCache[flagName]; exists {
return &FeatureFlagResponseModel{Name: flagName, Status: value}, nil
}
specificFlag, err := getSpecificFlagWithRetry(featureFlagsWrapper, flagName, maxRetries)
if err != nil {
if len(featureFlags) == 0 || DefaultFFLoad {
_ = HandleFeatureFlags(featureFlagsWrapper)
}
// Take the value from FeatureFlags
return &FeatureFlagResponseModel{Name: flagName, Status: featureFlags[flagName]}, nil
}
UpdateSpecificFeatureFlagMap(flagName, *specificFlag)
return specificFlag, nil
}
func getSpecificFlagWithRetry(wrapper FeatureFlagsWrapper, flagName string, retries int) (*FeatureFlagResponseModel, error) {
var flag *FeatureFlagResponseModel
var err error
for i := 0; i < retries; i++ {
flag, err = wrapper.GetSpecificFlag(flagName)
if err == nil {
return flag, nil
}
logger.PrintfIfVerbose("Retry %d/%d for flag %s failed with error: %v", i+1, retries, flagName, err)
}
logger.PrintfIfVerbose("Failed to get feature flag %s after %d retries", flagName, retries)
return nil, errors.New("failed to get feature flag after retries")
}
func UpdateSpecificFeatureFlagMap(flagName string, flag FeatureFlagResponseModel) {
featureFlagsCache[flagName] = flag.Status
}
func ClearCache() {
featureFlagsCache = map[string]bool{}
}
func loadFeatureFlagsMap(allFlags FeatureFlagsResponseModel) {
for _, flag := range allFlags {
featureFlags[flag.Name] = flag.Status
}
// Update FeatureFlags map with default values in case it does not exist in all flags response
for _, cmdFlag := range FeatureFlagsBaseMap {
for _, flag := range cmdFlag.FeatureFlags {
_, ok := featureFlags[flag.Name]
if !ok {
featureFlags[flag.Name] = flag.Default
}
}
}
DefaultFFLoad = false
}
func LoadFeatureFlagsDefaultValues() {
logger.PrintIfVerbose("Get feature flags failed. Loading defaults...")
for _, cmdFlag := range FeatureFlagsBaseMap {
for _, flag := range cmdFlag.FeatureFlags {
featureFlags[flag.Name] = flag.Default
}
}
DefaultFFLoad = true
}
type FeatureFlagsWrapper interface {
GetAll() (*FeatureFlagsResponseModel, error)
GetSpecificFlag(specificFlag string) (*FeatureFlagResponseModel, error)
}
type FeatureFlagsResponseModel []struct {
Name string `json:"name"`
Status bool `json:"status"`
}
type FeatureFlagResponseModel struct {
Name string `json:"name"`
Status bool `json:"status"`
}
type CommandFlags struct {
CommandName string
FeatureFlags []FlagBase
}
type FlagBase struct {
Name string
Default bool
}