Skip to content

Commit 59f99a0

Browse files
fix: codefresh_context disable decrypt when forbidDecrypt feature flag is set (#156)
1 parent f41f07f commit 59f99a0

File tree

9 files changed

+250
-31
lines changed

9 files changed

+250
-31
lines changed

codefresh/cfclient/client.go

+31-10
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import (
1111

1212
// Client token, host, htpp.Client
1313
type Client struct {
14-
Token string
15-
TokenHeader string
16-
Host string
17-
HostV2 string
18-
Client *http.Client
14+
Token string
15+
TokenHeader string
16+
Host string
17+
HostV2 string
18+
featureFlags map[string]bool
19+
Client *http.Client
1920
}
2021

2122
// RequestOptions path, method, etc
@@ -35,11 +36,12 @@ func NewClient(hostname string, hostnameV2 string, token string, tokenHeader str
3536
tokenHeader = "Authorization"
3637
}
3738
return &Client{
38-
Host: hostname,
39-
HostV2: hostnameV2,
40-
Token: token,
41-
TokenHeader: tokenHeader,
42-
Client: &http.Client{},
39+
Host: hostname,
40+
HostV2: hostnameV2,
41+
Token: token,
42+
TokenHeader: tokenHeader,
43+
Client: &http.Client{},
44+
featureFlags: map[string]bool{},
4345
}
4446

4547
}
@@ -112,6 +114,25 @@ func (client *Client) RequestApiXAccessToken(opt *RequestOptions) ([]byte, error
112114
return body, nil
113115
}
114116

117+
func (client *Client) isFeatureFlagEnabled(flagName string) (bool, error) {
118+
119+
if len(client.featureFlags) == 0 {
120+
currAcc, err := client.GetCurrentAccount()
121+
122+
if err != nil {
123+
return false, err
124+
}
125+
126+
client.featureFlags = currAcc.FeatureFlags
127+
}
128+
129+
if val, ok := client.featureFlags[flagName]; ok {
130+
return val, nil
131+
}
132+
133+
return false, nil
134+
}
135+
115136
// ToQS add extra parameters to path
116137
func ToQS(qs map[string]string) string {
117138
var arr = []string{}

codefresh/cfclient/context.go

+35-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@ import (
44
"fmt"
55
"log"
66
"net/url"
7+
8+
"golang.org/x/exp/slices"
79
)
810

11+
var encryptedContextTypes = []string{
12+
"secret",
13+
"secret-yaml",
14+
"storage.s3",
15+
"storage.azuref",
16+
}
17+
918
type ContextErrorResponse struct {
1019
Status int `json:"status,omitempty"`
1120
Message string `json:"message,omitempty"`
@@ -17,9 +26,10 @@ type ContextMetadata struct {
1726
}
1827

1928
type Context struct {
20-
Metadata ContextMetadata `json:"metadata,omitempty"`
21-
Spec ContextSpec `json:"spec,omitempty"`
22-
Version string `json:"version,omitempty"`
29+
Metadata ContextMetadata `json:"metadata,omitempty"`
30+
Spec ContextSpec `json:"spec,omitempty"`
31+
Version string `json:"version,omitempty"`
32+
IsEncrypred bool `json:"isEncrypted,omitempty"`
2333
}
2434

2535
type ContextSpec struct {
@@ -32,7 +42,18 @@ func (context *Context) GetID() string {
3242
}
3343

3444
func (client *Client) GetContext(name string) (*Context, error) {
35-
fullPath := fmt.Sprintf("/contexts/%s?decrypt=true", url.PathEscape(name))
45+
fullPath := fmt.Sprintf("/contexts/%s", url.PathEscape(name))
46+
47+
forbidDecrypt, err := client.isFeatureFlagEnabled("forbidDecrypt")
48+
49+
if err != nil {
50+
forbidDecrypt = false
51+
}
52+
53+
if !forbidDecrypt {
54+
fullPath += "?decrypt=true"
55+
}
56+
3657
opts := RequestOptions{
3758
Path: fullPath,
3859
Method: "GET",
@@ -49,8 +70,17 @@ func (client *Client) GetContext(name string) (*Context, error) {
4970
return nil, err
5071
}
5172

52-
return &respContext, nil
73+
// This is so not to break existing behavior while adding support for forbidDecrypt feature flag
74+
// The provider used to always decrypt the contexts, hence we treat all contexts as decrypted unless forbidDecrypt is set
75+
isEncryptedType := slices.Contains(encryptedContextTypes, respContext.Spec.Type)
5376

77+
respContext.IsEncrypred = false
78+
79+
if forbidDecrypt && isEncryptedType {
80+
respContext.IsEncrypred = true
81+
}
82+
83+
return &respContext, nil
5484
}
5585

5686
func (client *Client) CreateContext(context *Context) (*Context, error) {

codefresh/cfclient/current_account.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ type CurrentAccountUser struct {
1818

1919
// CurrentAccount spec
2020
type CurrentAccount struct {
21-
ID string
22-
Name string
23-
Users []CurrentAccountUser
24-
Admins []CurrentAccountUser
21+
ID string
22+
Name string
23+
Users []CurrentAccountUser
24+
Admins []CurrentAccountUser
25+
FeatureFlags map[string]bool
2526
}
2627

2728
// GetCurrentAccount -
@@ -46,9 +47,10 @@ func (client *Client) GetCurrentAccount() (*CurrentAccount, error) {
4647
return nil, fmt.Errorf("GetCurrentAccount - cannot get activeAccountName")
4748
}
4849
currentAccount := &CurrentAccount{
49-
Name: activeAccountName,
50-
Users: make([]CurrentAccountUser, 0),
51-
Admins: make([]CurrentAccountUser, 0),
50+
Name: activeAccountName,
51+
Users: make([]CurrentAccountUser, 0),
52+
Admins: make([]CurrentAccountUser, 0),
53+
FeatureFlags: make(map[string]bool),
5254
}
5355

5456
accountAdminsIDs := make([]string, 0)
@@ -62,6 +64,11 @@ func (client *Client) GetCurrentAccount() (*CurrentAccount, error) {
6264
for _, adminI := range admins {
6365
accountAdminsIDs = append(accountAdminsIDs, adminI.(string))
6466
}
67+
featureFlags := accX.Get("features").ObjxMap()
68+
69+
for k, v := range featureFlags {
70+
currentAccount.FeatureFlags[k] = v.(bool)
71+
}
6572
break
6673
}
6774
}

codefresh/context/storage.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func flattenStorageContextConfig(spec cfclient.ContextSpec, auth map[string]inte
5454
func FlattenJsonConfigStorageContextConfig(spec cfclient.ContextSpec) []interface{} {
5555
auth := make(map[string]interface{})
5656
auth["json_config"] = spec.Data["auth"].(map[string]interface{})["jsonConfig"]
57-
auth["type"] = spec.Data["type"]
57+
auth["type"] = spec.Data["auth"].(map[string]interface{})["type"]
5858
return flattenStorageContextConfig(spec, auth)
5959
}
6060

codefresh/provider.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55

66
"github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient"
77
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8-
98
"os"
109
)
1110

@@ -87,5 +86,6 @@ func configureProvider(d *schema.ResourceData) (interface{}, error) {
8786
if token == "" {
8887
token = os.Getenv(ENV_CODEFRESH_API_KEY)
8988
}
89+
9090
return cfclient.NewClient(apiURL, apiURLV2, token, ""), nil
9191
}

codefresh/resource_context.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,14 @@ func resourceContextRead(d *schema.ResourceData, meta interface{}) error {
180180
}
181181

182182
context, err := client.GetContext(contextName)
183+
183184
if err != nil {
184185
log.Printf("[DEBUG] Error while getting context. Error = %v", contextName)
185186
return err
186187
}
187188

188189
err = mapContextToResource(*context, d)
190+
189191
if err != nil {
190192
log.Printf("[DEBUG] Error while mapping context to resource. Error = %v", err)
191193
return err
@@ -225,14 +227,20 @@ func resourceContextDelete(d *schema.ResourceData, meta interface{}) error {
225227
func mapContextToResource(context cfclient.Context, d *schema.ResourceData) error {
226228

227229
err := d.Set("name", context.Metadata.Name)
230+
228231
if err != nil {
229232
return err
230233
}
231234

232-
err = d.Set("spec", flattenContextSpec(context.Spec))
233-
if err != nil {
234-
log.Printf("[DEBUG] Failed to flatten Context spec = %v", context.Spec)
235-
return err
235+
// Read spec from API if context is not encrypted or forbitDecrypt is not set
236+
if !context.IsEncrypred {
237+
238+
err = d.Set("spec", flattenContextSpec(context.Spec))
239+
240+
if err != nil {
241+
log.Printf("[DEBUG] Failed to flatten Context spec = %v", context.Spec)
242+
return err
243+
}
236244
}
237245

238246
return nil
@@ -253,7 +261,6 @@ func flattenContextSpec(spec cfclient.ContextSpec) []interface{} {
253261
case contextAzureStorage:
254262
m[schemautil.MustNormalizeFieldName(currentContextType)] = storageContext.FlattenAzureStorageContextConfig(spec)
255263
default:
256-
log.Printf("[DEBUG] Invalid context type = %v", currentContextType)
257264
return nil
258265
}
259266

codefresh/resource_context_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ resource "codefresh_context" "test" {
204204
205205
spec {
206206
config {
207-
data = {
207+
data = {
208208
%q = %q
209209
%q = %q
210210
}
@@ -223,7 +223,7 @@ resource "codefresh_context" "test" {
223223
224224
spec {
225225
secret {
226-
data = {
226+
data = {
227227
%q = %q
228228
%q = %q
229229
}

docs/resources/context.md

+77
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ YAML
8888
```hcl
8989
resource "codefresh_context" "test-secret-yaml" {
9090
name = "my-shared-secret-yaml"
91+
decrypt_spec = false
9192
spec {
9293
# NOTE: The `-` from secret-yaml is stripped because the character is not allowed in Field name
9394
# File passed MUST be a valid YAML
@@ -96,6 +97,82 @@ resource "codefresh_context" "test-secret-yaml" {
9697
}
9798
```
9899

100+
#### AWS S3 storage context
101+
102+
```hcl
103+
resource "codefresh_context" "test-s3" {
104+
name = "my-s3-context"
105+
106+
decrypt_spec = false
107+
108+
spec {
109+
storages3 {
110+
data {
111+
auth {
112+
type = "basic"
113+
json_config = {accessKeyId = "key", secretAccessKey = "secret"}
114+
}
115+
}
116+
}
117+
}
118+
}
119+
```
120+
121+
#### Azure file storage context
122+
123+
```hcl
124+
resource "codefresh_context" "test-azure" {
125+
name = "my-azure-file-context"
126+
127+
decrypt_spec = false
128+
129+
spec {
130+
storageazuref {
131+
data {
132+
auth {
133+
type = "basic"
134+
account_name = "account"
135+
account_key = "key"
136+
}
137+
}
138+
}
139+
}
140+
}
141+
```
142+
143+
#### Google cloud storage context
144+
145+
```hcl
146+
resource "codefresh_context" "test-google-cloud-storage" {
147+
name = "my-gcs-context"
148+
149+
spec {
150+
storagegc {
151+
data {
152+
auth {
153+
type = "basic"
154+
json_config = jsondecode(<<EOF
155+
{
156+
"type": "service_account",
157+
"project_id": "PROJECT_ID",
158+
"private_key_id": "KEY_ID",
159+
"private_key": "-----BEGIN PRIVATE KEY-----\nPRIVATE_KEY\n-----END PRIVATE KEY-----\n",
160+
"client_email": "SERVICE_ACCOUNT_EMAIL",
161+
"client_id": "CLIENT_ID",
162+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
163+
"token_uri": "https://accounts.google.com/o/oauth2/token",
164+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
165+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/SERVICE_ACCOUNT_EMAIL"
166+
}
167+
EOF
168+
)
169+
}
170+
}
171+
}
172+
}
173+
}
174+
```
175+
99176
<!-- schema generated by tfplugindocs -->
100177
## Schema
101178

0 commit comments

Comments
 (0)