Skip to content

Commit

Permalink
Add new attribute jas_enabled
Browse files Browse the repository at this point in the history
Use this new attribute to determine if JAS related config fields should be set or not with API.
  • Loading branch information
alexhung committed Feb 1, 2024
1 parent c24166c commit 59a6724
Show file tree
Hide file tree
Showing 7 changed files with 372 additions and 105 deletions.
22 changes: 17 additions & 5 deletions docs/resources/repository_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ resource "xray_repository_config" "xray-repo-config-pattern" {
}
resource "xray_repository_config" "xray-repo-config" {
repo_name = "example-repo-local"
repo_name = "example-repo-local"
jas_enabled = true
config {
vuln_contextual_analysis = true
Expand All @@ -56,6 +57,7 @@ resource "xray_repository_config" "xray-repo-config" {
### Optional

- `config` (Block Set, Max: 1) Single repository configuration. Only one of 'config' or 'paths_config' can be set. (see [below for nested schema](#nestedblock--config))
- `jas_enabled` (Boolean) Specified if JFrog Advanced Security is enabled or not. Default to 'false'
- `paths_config` (Block Set, Max: 1) Enables you to set a more granular retention period. It enables you to scan future artifacts within the specific path, and set a retention period for the historical data of artifacts after they are scanned (see [below for nested schema](#nestedblock--paths_config))

### Read-Only
Expand Down Expand Up @@ -123,8 +125,18 @@ Optional:

## Import

Import is supported using the following syntax:
To import repository configuration, you'll need to specific if your JFrog Platform has Advanced Security enabled as part of the resource ID along with repository name, separated by a colon (`:`).

For instance, using the following config during import:
```terraform
resource "xray_repository_config" "xray-repo-config" {
repo_name = "example-repo-local"
jas_enabled = false
config {
retention_in_days = 90
}
}
```

```shell
terraform import xray_repository_config.my-config config-repo-name
```
Then use `terraform import xray_repository_config.xray-repo-config example-repo-local:false` to import the repository configuration `xray-repo-config` with `jas_enabled` set to `false`.
2 changes: 1 addition & 1 deletion examples/resources/xray_repository_config/import.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
terraform import xray_repository_config.my-config config-repo-name
terraform import xray_repository_config.my-config config-repo-name:false
3 changes: 2 additions & 1 deletion examples/resources/xray_repository_config/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ resource "xray_repository_config" "xray-repo-config-pattern" {
}

resource "xray_repository_config" "xray-repo-config" {
repo_name = "example-repo-local"
repo_name = "example-repo-local"
jas_enabled = true

config {
vuln_contextual_analysis = true
Expand Down
5 changes: 5 additions & 0 deletions pkg/xray/resource_xray_operational_risk_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func TestAccOperationalRiskPolicy_withProjectKey(t *testing.T) {

testData := sdk.MergeMaps(testDataOperationalRisk)
testData["resource_name"] = resourceName
testData["policy_name"] = fmt.Sprintf("terraform-operational-risk-policy-%d", testutil.RandomInt())
testData["project_key"] = projectKey
testData["op_risk_min_risk"] = "Medium"

Expand Down Expand Up @@ -132,6 +133,7 @@ func TestAccOperationalRiskPolicy_minRiskCriteria(t *testing.T) {

testData := sdk.MergeMaps(testDataOperationalRisk)
testData["resource_name"] = resourceName
testData["policy_name"] = fmt.Sprintf("terraform-operational-risk-policy-%d", testutil.RandomInt())
testData["op_risk_min_risk"] = "Medium"

resource.Test(t, resource.TestCase{
Expand Down Expand Up @@ -194,6 +196,7 @@ func TestAccOperationalRiskPolicy_customCriteria(t *testing.T) {

testData := sdk.MergeMaps(testDataOperationalRisk)
testData["resource_name"] = resourceName
testData["policy_name"] = fmt.Sprintf("terraform-operational-risk-policy-%d", testutil.RandomInt())
testData["op_risk_custom_use_and_condition"] = "true"
testData["op_risk_custom_is_eol"] = "false"
testData["op_risk_custom_release_date_greater_than_months"] = testutil.RandSelect("6", "12", "18", "24", "30", "36").(string)
Expand Down Expand Up @@ -308,6 +311,7 @@ func TestAccOperationalRiskPolicy_customCriteria_migration(t *testing.T) {

testData := sdk.MergeMaps(testDataOperationalRisk)
testData["resource_name"] = resourceName
testData["policy_name"] = fmt.Sprintf("terraform-operational-risk-policy-%d", testutil.RandomInt())
testData["op_risk_custom_use_and_condition"] = "true"
testData["op_risk_custom_is_eol"] = "false"
testData["op_risk_custom_risk"] = testutil.RandSelect("high", "medium", "low").(string)
Expand Down Expand Up @@ -376,6 +380,7 @@ func TestAccOperationalRiskPolicy_criteriaValidation(t *testing.T) {

testData := sdk.MergeMaps(testDataOperationalRisk)
testData["resource_name"] = resourceName
testData["policy_name"] = fmt.Sprintf("terraform-operational-risk-policy-%d", testutil.RandomInt())

template := `
resource "xray_operational_risk_policy" "{{ .resource_name }}" {
Expand Down
105 changes: 85 additions & 20 deletions pkg/xray/resource_xray_repository_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"fmt"
"net/http"
"strconv"
"strings"

"github.com/go-resty/resty/v2"
"github.com/hashicorp/terraform-plugin-log/tflog"
Expand Down Expand Up @@ -78,6 +80,12 @@ func resourceXrayRepositoryConfig() *schema.Resource {
Description: "Repository name.",
ValidateDiagFunc: validator.StringIsNotEmpty,
},
"jas_enabled": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Specified if JFrog Advanced Security is enabled or not. Default to 'false'",
},
"config": {
Type: schema.TypeSet,
Optional: true,
Expand All @@ -101,7 +109,6 @@ func resourceXrayRepositoryConfig() *schema.Resource {
"exposures": {
Type: schema.TypeSet,
Optional: true,
MinItems: 1,
MaxItems: 1,
Description: "Enables Xray to perform scans for multiple categories that cover security issues in your configurations and the usage of open source libraries in your code. Available only to CLOUD (SaaS)/SELF HOSTED for ENTERPRISE X and ENTERPRISE+ with Advanced DevSecOps. Must be set together with `vuln_contextual_analysis`. Supported for Docker, Maven, NPM, PyPi, and Terraform Backend package type.",
Elem: &schema.Resource{
Expand Down Expand Up @@ -303,31 +310,36 @@ func resourceXrayRepositoryConfig() *schema.Resource {
return &exposures
}

var unpackRepoConfig = func(config *schema.Set, xrayVersion, packageType string) *RepoConfiguration {
var unpackRepoConfig = func(ctx context.Context, config *schema.Set, xrayVersion, packageType string, jasEnabled bool) *RepoConfiguration {
repoConfig := new(RepoConfiguration)

if config != nil {
data := config.List()[0].(map[string]interface{})
if slices.Contains(vulnContextualAnalysisPackageTypes(xrayVersion), packageType) {
vulnContextualAnalysis := data["vuln_contextual_analysis"].(bool)
repoConfig.VulnContextualAnalysis = &vulnContextualAnalysis
}
repoConfig.RetentionInDays = data["retention_in_days"].(int)
repoConfig.Exposures = unpackExposures(data["exposures"].(*schema.Set), xrayVersion, packageType)

if jasEnabled {
if slices.Contains(vulnContextualAnalysisPackageTypes(xrayVersion), packageType) {
vulnContextualAnalysis := data["vuln_contextual_analysis"].(bool)
repoConfig.VulnContextualAnalysis = &vulnContextualAnalysis
}
repoConfig.Exposures = unpackExposures(data["exposures"].(*schema.Set), xrayVersion, packageType)
}
}

return repoConfig
}

var unpackRepositoryConfig = func(s *schema.ResourceData, xrayVersion, packageType string) RepositoryConfiguration {
var unpackRepositoryConfig = func(ctx context.Context, s *schema.ResourceData, xrayVersion, packageType string) RepositoryConfiguration {
d := &sdk.ResourceData{ResourceData: s}

repositoryConfig := RepositoryConfiguration{
RepoName: d.GetString("repo_name", false),
}

jasEnabled := d.GetBool("jas_enabled", false)

if v, ok := s.GetOk("config"); ok {
repositoryConfig.RepoConfig = unpackRepoConfig(v.(*schema.Set), xrayVersion, packageType)
repositoryConfig.RepoConfig = unpackRepoConfig(ctx, v.(*schema.Set), xrayVersion, packageType, jasEnabled)
}

if v, ok := s.GetOk("paths_config"); ok {
Expand Down Expand Up @@ -365,7 +377,7 @@ func resourceXrayRepositoryConfig() *schema.Resource {
}
}

var packGeneralRepoConfig = func(repoConfig *RepoConfiguration, xrayVersion, packageType string) []interface{} {
var packGeneralRepoConfig = func(repoConfig *RepoConfiguration, xrayVersion, packageType string, jasEnabled bool) []interface{} {
if repoConfig == nil {
return []interface{}{}
}
Expand All @@ -374,12 +386,14 @@ func resourceXrayRepositoryConfig() *schema.Resource {
"retention_in_days": repoConfig.RetentionInDays,
}

if repoConfig.VulnContextualAnalysis != nil && slices.Contains(vulnContextualAnalysisPackageTypes(xrayVersion), packageType) {
m["vuln_contextual_analysis"] = *repoConfig.VulnContextualAnalysis
}
if jasEnabled {
if repoConfig.VulnContextualAnalysis != nil && slices.Contains(vulnContextualAnalysisPackageTypes(xrayVersion), packageType) {
m["vuln_contextual_analysis"] = *repoConfig.VulnContextualAnalysis
}

if repoConfig.Exposures != nil && slices.Contains(exposuresPackageTypes(xrayVersion), packageType) {
m["exposures"] = packExposures(repoConfig.Exposures, packageType)
if repoConfig.Exposures != nil && slices.Contains(exposuresPackageTypes(xrayVersion), packageType) {
m["exposures"] = packExposures(repoConfig.Exposures, packageType)
}
}

return []interface{}{m}
Expand Down Expand Up @@ -424,11 +438,17 @@ func resourceXrayRepositoryConfig() *schema.Resource {
return []interface{}{m}
}

var packRepositoryConfig = func(ctx context.Context, repositoryConfig RepositoryConfiguration, d *schema.ResourceData, xrayVersion, packageType string) diag.Diagnostics {
var packRepositoryConfig = func(repositoryConfig RepositoryConfiguration, d *schema.ResourceData, xrayVersion, packageType string) diag.Diagnostics {
if err := d.Set("repo_name", repositoryConfig.RepoName); err != nil {
return diag.FromErr(err)
}
if err := d.Set("config", packGeneralRepoConfig(repositoryConfig.RepoConfig, xrayVersion, packageType)); err != nil {

jasEnabled := false
if v, ok := d.GetOk("jas_enabled"); ok {
jasEnabled = v.(bool)
}

if err := d.Set("config", packGeneralRepoConfig(repositoryConfig.RepoConfig, xrayVersion, packageType, jasEnabled)); err != nil {
return diag.FromErr(err)
}
if err := d.Set("paths_config", packRepoPathsConfigList(repositoryConfig.RepoPathsConfig)); err != nil {
Expand Down Expand Up @@ -481,7 +501,7 @@ func resourceXrayRepositoryConfig() *schema.Resource {
return diag.FromErr(err)
}

return packRepositoryConfig(ctx, repositoryConfig, d, metadata.XrayVersion, packageType)
return packRepositoryConfig(repositoryConfig, d, metadata.XrayVersion, packageType)
}

var resourceXrayRepositoryConfigCreate = func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
Expand All @@ -491,7 +511,7 @@ func resourceXrayRepositoryConfig() *schema.Resource {
return diag.FromErr(err)
}

repositoryConfig := unpackRepositoryConfig(d, metadata.XrayVersion, packageType)
repositoryConfig := unpackRepositoryConfig(ctx, d, metadata.XrayVersion, packageType)

_, err = metadata.Client.R().SetBody(&repositoryConfig).Put("xray/api/v1/repos_config")
if err != nil {
Expand All @@ -517,16 +537,61 @@ func resourceXrayRepositoryConfig() *schema.Resource {
}}
}

var jasEnabledResourceDiff = func(ctx context.Context, diff *schema.ResourceDiff, v interface{}) error {
jasEnabled := false
if v, ok := diff.GetOk("jas_enabled"); ok {
jasEnabled = v.(bool)
}

if !jasEnabled {
configSet := diff.Get("config").(*schema.Set).List()
if len(configSet) == 0 {
return nil
}

config := configSet[0].(map[string]interface{})

if v, ok := config["vuln_contextual_analysis"]; ok && v.(bool) {
return fmt.Errorf("config.vuln_contextual_analysis can not be set when jas_enabled is set to 'true'")
}

tflog.Debug(ctx, "jasEnabledResourceDiff", map[string]any{
"config": config,
"config['exposures']": config["exposures"],
})
if v, ok := config["exposures"]; ok && v.(*schema.Set).Len() > 0 {
return fmt.Errorf("config.exposures can not be set when jas_enabled is set to 'true'")
}
}

return nil
}

return &schema.Resource{
CreateContext: resourceXrayRepositoryConfigCreate,
ReadContext: resourceXrayRepositoryConfigRead,
UpdateContext: resourceXrayRepositoryConfigCreate,
DeleteContext: resourceXrayRepositoryConfigDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
StateContext: func(_ context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) {
parts := strings.SplitN(d.Id(), ":", 2)

if len(parts) == 2 && parts[0] != "" && parts[1] != "" {
d.SetId(parts[0])
jasEnabled, err := strconv.ParseBool(parts[1])
if err != nil {
return nil, err
}
d.Set("jas_enabled", jasEnabled)
}

return []*schema.ResourceData{d}, nil
},
},

CustomizeDiff: jasEnabledResourceDiff,

Schema: repositoryConfigSchema,
Description: "Provides an Xray repository config resource. See [Xray Indexing Resources](https://www.jfrog.com/confluence/display/JFROG/Indexing+Xray+Resources#IndexingXrayResources-SetaRetentionPeriod) and [REST API](https://www.jfrog.com/confluence/display/JFROG/Xray+REST+API#XrayRESTAPI-UpdateRepositoriesConfigurations) for more details.",
}
Expand Down
Loading

0 comments on commit 59a6724

Please sign in to comment.