diff --git a/import-export-cli/box/resources/sample/sample_config.yaml b/import-export-cli/box/resources/sample/sample_config.yaml index be48df7b5..08ac24c4a 100644 --- a/import-export-cli/box/resources/sample/sample_config.yaml +++ b/import-export-cli/box/resources/sample/sample_config.yaml @@ -15,7 +15,7 @@ environments: devportal: https://localhost:9443 registration: https://localhost:9443 admin: https://localhost:9443 - token: https://localhost:8243/token + token: https://localhost:9443/oauth2/token mi: https://localhost:9164 sample-env2: apim: https://wso2am:9443 @@ -31,5 +31,5 @@ environments: devportal: https://localhost:9443 registration: https://localhost:9443 admin: https://localhost:9443 - token: https://localhost:8243/token + token: https://localhost:9443/oauth2/token mi: "" diff --git a/import-export-cli/cmd/add.go b/import-export-cli/cmd/add.go index 7a207a900..ee82c5f02 100644 --- a/import-export-cli/cmd/add.go +++ b/import-export-cli/cmd/add.go @@ -40,13 +40,13 @@ const addCmdExamples = utils.ProjectName + ` ` + AddCmdLiteral + ` ` + AddEnvCmd --publisher https://apim.com:9443 \ --devportal https://apps.com:9443 \ --admin https://apim.com:9443 \ ---token https://gw.com:8243/token \ +--token https://gw.com:9443/oauth2/token \ --mi https://localhost:9164 ` + utils.ProjectName + ` ` + AddCmdLiteral + ` ` + AddEnvCmdLiteralTrimmed + ` dev \ --apim https://apim.com:9443 \ --registration https://idp.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token NOTE: The flag --environment (-e) is mandatory. You can either provide only the flag --apim , or all the other 4 flags (--registration --publisher --devportal --admin) without providing --apim flag. diff --git a/import-export-cli/cmd/addEnv.go b/import-export-cli/cmd/addEnv.go index 06b74f6d1..7ccb978a8 100644 --- a/import-export-cli/cmd/addEnv.go +++ b/import-export-cli/cmd/addEnv.go @@ -54,13 +54,13 @@ const addEnvCmdExamples = utils.ProjectName + ` ` + AddCmdLiteral + ` ` + AddEnv --publisher https://apim.com:9443 \ --devportal https://apps.com:9443 \ --admin https://apim.com:9443 \ ---token https://gw.com:8243/token \ +--token https://gw.com:9443/oauth2/token \ --mi https://localhost:9164 ` + utils.ProjectName + ` ` + AddCmdLiteral + ` ` + AddEnvCmdLiteralTrimmed + ` dev \ --apim https://apim.com:9443 \ --registration https://idp.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token You can either provide only the flag --apim , or all the other 4 flags (--registration --publisher --devportal --admin) without providing --apim flag. If you are omitting any of --registration --publisher --devportal --admin flags, you need to specify --apim flag with the API Manager endpoint. In both of the diff --git a/import-export-cli/cmd/deprecated/addEnv.go b/import-export-cli/cmd/deprecated/addEnv.go index 02c75499f..6a0191f75 100644 --- a/import-export-cli/cmd/deprecated/addEnv.go +++ b/import-export-cli/cmd/deprecated/addEnv.go @@ -45,12 +45,12 @@ const addEnvCmdExamples = utils.ProjectName + ` ` + addEnvCmdLiteral + ` -e prod --publisher https://apim.com:9443 \ --devportal https://apps.com:9443 \ --admin https://apim.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token ` + utils.ProjectName + ` ` + addEnvCmdLiteral + ` -e dev \ --apim https://apim.com:9443 \ --registration https://idp.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token NOTE: The flag --environment (-e) is mandatory. You can either provide only the flag --apim , or all the other 4 flags (--registration --publisher --devportal --admin) without providing --apim flag. diff --git a/import-export-cli/cmd/deprecated/importAPI.go b/import-export-cli/cmd/deprecated/importAPI.go index f7e95a864..23b55930f 100644 --- a/import-export-cli/cmd/deprecated/importAPI.go +++ b/import-export-cli/cmd/deprecated/importAPI.go @@ -67,7 +67,7 @@ var ImportAPICmdDeprecated = &cobra.Command{ utils.HandleErrorAndExit("Error while getting an access token for importing API", err) } err = impl.ImportAPIToEnv(accessOAuthToken, importEnvironment, importAPIFile, importAPIParamsFile, importAPIUpdate, - importAPICmdPreserveProvider, importAPISkipCleanup, false, false) + importAPICmdPreserveProvider, importAPISkipCleanup, false, false, false, "") if err != nil { utils.HandleErrorAndExit("Error importing API", err) return diff --git a/import-export-cli/cmd/importAPI.go b/import-export-cli/cmd/importAPI.go index f2c32b28e..7a7d902c6 100644 --- a/import-export-cli/cmd/importAPI.go +++ b/import-export-cli/cmd/importAPI.go @@ -34,6 +34,8 @@ var ( importAPISkipCleanup bool importAPIRotateRevision bool importAPISkipDeployments bool + dryRun bool + apiLoggingCmdFormat string ) const ( @@ -67,7 +69,8 @@ var ImportAPICmd = &cobra.Command{ utils.HandleErrorAndExit("Error while getting an access token for importing API", err) } err = impl.ImportAPIToEnv(accessOAuthToken, importEnvironment, importAPIFile, importAPIParamsFile, importAPIUpdate, - importAPICmdPreserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments) + importAPICmdPreserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments, dryRun, + apiLoggingCmdFormat) if err != nil { utils.HandleErrorAndExit("Error importing API", err) return @@ -94,6 +97,10 @@ func init() { "or a directory generated using \"gen deployment-dir\" command") ImportAPICmd.Flags().BoolVarP(&importAPISkipCleanup, "skip-cleanup", "", false, "Leave "+ "all temporary files created during import process") + ImportAPICmd.Flags().BoolVarP(&dryRun, "dry-run", "", false, "Get "+ + "verification of the governance compliance of the API without importing it") + ImportAPICmd.Flags().StringVarP(&apiLoggingCmdFormat, "format", "", "", "Output format of violation results in "+ + "dry-run mode. Supported formats: [table, json, list]. If not provided, the default format is table.") // Mark required flags _ = ImportAPICmd.MarkFlagRequired("environment") _ = ImportAPICmd.MarkFlagRequired("file") diff --git a/import-export-cli/docs/apictl_add-env.md b/import-export-cli/docs/apictl_add-env.md index 11746630a..ad6a5c5bf 100644 --- a/import-export-cli/docs/apictl_add-env.md +++ b/import-export-cli/docs/apictl_add-env.md @@ -21,12 +21,12 @@ apictl add-env -e test \ --publisher https://apim.com:9443 \ --devportal https://apps.com:9443 \ --admin https://apim.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token apictl add-env -e dev \ --apim https://apim.com:9443 \ --registration https://idp.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token NOTE: The flag --environment (-e) is mandatory. You can either provide only the flag --apim , or all the other 4 flags (--registration --publisher --devportal --admin) without providing --apim flag. diff --git a/import-export-cli/docs/apictl_add.md b/import-export-cli/docs/apictl_add.md index d2864d0b6..89afd1264 100644 --- a/import-export-cli/docs/apictl_add.md +++ b/import-export-cli/docs/apictl_add.md @@ -24,13 +24,13 @@ apictl add env test \ --publisher https://apim.com:9443 \ --devportal https://apps.com:9443 \ --admin https://apim.com:9443 \ ---token https://gw.com:8243/token \ +--token https://gw.com:9443/oauth2/token \ --mi https://localhost:9164 apictl add env dev \ --apim https://apim.com:9443 \ --registration https://idp.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token NOTE: The flag --environment (-e) is mandatory. You can either provide only the flag --apim , or all the other 4 flags (--registration --publisher --devportal --admin) without providing --apim flag. diff --git a/import-export-cli/docs/apictl_add_env.md b/import-export-cli/docs/apictl_add_env.md index 60a65ae61..2fd649416 100644 --- a/import-export-cli/docs/apictl_add_env.md +++ b/import-export-cli/docs/apictl_add_env.md @@ -28,13 +28,13 @@ apictl add env test \ --publisher https://apim.com:9443 \ --devportal https://apps.com:9443 \ --admin https://apim.com:9443 \ ---token https://gw.com:8243/token \ +--token https://gw.com:9443/oauth2/token \ --mi https://localhost:9164 apictl add env dev \ --apim https://apim.com:9443 \ --registration https://idp.com:9443 \ ---token https://gw.com:8243/token +--token https://gw.com:9443/oauth2/token You can either provide only the flag --apim , or all the other 4 flags (--registration --publisher --devportal --admin) without providing --apim flag. If you are omitting any of --registration --publisher --devportal --admin flags, you need to specify --apim flag with the API Manager endpoint. In both of the diff --git a/import-export-cli/git/gitUtils.go b/import-export-cli/git/gitUtils.go index d1682d522..2f1f4872e 100644 --- a/import-export-cli/git/gitUtils.go +++ b/import-export-cli/git/gitUtils.go @@ -388,9 +388,12 @@ func handleIfError(err error, failedProjects map[string][]*params.ProjectParams, // updatedProjectsPerType is a map of string -> ProjectParams which consists of updated projects per each type (API, App..) // Returns bool, true if any deleted projects exists so the process should continue with project deletion path // Returns map[string][]*params.ProjectParams, a map of project type (API, App.. ) to each project detail which are -// deleted projects +// +// deleted projects +// // Returns map[string][]*params.ProjectParams, a map of project type (API, App.. ) to each project detail which are -// failed during the deployment +// +// failed during the deployment func deployUpdatedProjects(accessToken, sourceRepoId, deploymentRepoId, environment string, totalProjectsToUpdate int, updatedProjectsPerType map[string][]*params.ProjectParams) (bool, map[string][]*params.ProjectParams, map[string][]*params.ProjectParams) { @@ -432,7 +435,7 @@ func deployUpdatedProjects(accessToken, sourceRepoId, deploymentRepoId, environm importParams := projectParam.MetaData.DeployConfig.Import fmt.Println(strconv.Itoa(i+1) + ": " + projectParam.NickName + ": (" + projectParam.RelativePath + ")") err := impl.ImportAPIToEnv(accessToken, environment, generateSourceProjectPath(mainConfig, projectParam), - projectDeploymentParamsDirLocation, importParams.Update, importParams.PreserveProvider, false, importParams.RotateRevision, false) + projectDeploymentParamsDirLocation, importParams.Update, importParams.PreserveProvider, false, importParams.RotateRevision, false, false, "") if err != nil { fmt.Println("Error... ", err) failedProjects[projectParam.Type] = append(failedProjects[projectParam.Type], projectParam) @@ -629,8 +632,9 @@ func DeployChangedFiles(accessToken, environment string) map[string][]*params.Pr } // Create 'vcs.yaml' in the repository root folder with a unique id (uuid) for the repository. -// If the value of force is false, and the file is already created, gives an error. -// If the value of force is true, It will reinitialize the file even if it already exists. +// +// If the value of force is false, and the file is already created, gives an error. +// If the value of force is true, It will reinitialize the file even if it already exists. func InitializeRepo(force bool) error { vcsInfoPath, err := getVcsYamlPath() if err != nil { @@ -700,7 +704,9 @@ func logChangedFiles(changedFileList []string) { } // subPath denotes a single changed file retrieved from "git diff" command. This path is scanned and then identifies the -// project type (API, App,.. ) from this method. +// +// project type (API, App,.. ) from this method. +// // envVCSConfig is the environment related VCS configuration // repoBasePath is the basepath of the git repository // pathInfoMap is a map of path (string) to project info. This is used for caching and avoid repetitive checking diff --git a/import-export-cli/go.mod b/import-export-cli/go.mod index 23266d373..d1470260a 100644 --- a/import-export-cli/go.mod +++ b/import-export-cli/go.mod @@ -13,6 +13,7 @@ require ( github.com/json-iterator/go v1.1.12 github.com/magiconair/properties v1.8.1 github.com/mitchellh/mapstructure v1.3.2 + github.com/olekukonko/tablewriter v0.0.5 github.com/pavel-v-chernykh/keystore-go/v4 v4.1.0 github.com/renstrom/dedent v1.0.0 github.com/savaki/jq v0.0.0-20161209013833-0e6baecebbf8 @@ -45,6 +46,7 @@ require ( github.com/hashicorp/errwrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/mailru/easyjson v0.7.1 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/import-export-cli/go.sum b/import-export-cli/go.sum index e9cf64b8a..5d67b5566 100644 --- a/import-export-cli/go.sum +++ b/import-export-cli/go.sum @@ -624,6 +624,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -680,6 +682,8 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/import-export-cli/impl/importAPI.go b/import-export-cli/impl/importAPI.go index 2c12adac2..c3608ea79 100644 --- a/import-export-cli/impl/importAPI.go +++ b/import-export-cli/impl/importAPI.go @@ -40,6 +40,17 @@ import ( "github.com/wso2/product-apim-tooling/import-export-cli/utils" ) +// JSONData represents the JSON data +type JSONData struct { + ComplianceCheck ComplianceCheck `json:"compliance-check"` +} + +// ComplianceCheck represents the compliance check +type ComplianceCheck struct { + Result string `json:"result"` + Violations []Violation `json:"violations"` +} + var ( reAPIName = regexp.MustCompile(`[~!@#;:%^*()+={}|\\<>"',&/$]`) ) @@ -145,7 +156,8 @@ func replaceEnvVariables(apiFilePath string) error { } // importAPI imports an API to the API manager -func importAPI(endpoint, filePath, accessToken string, extraParams map[string]string, isOauth bool) error { +func importAPI(endpoint, filePath, accessToken string, extraParams map[string]string, isOauth bool, dryRun bool, + apiLoggingCmdFormat string) error { resp, err := ExecuteNewFileUploadRequest(endpoint, extraParams, "file", filePath, accessToken, isOauth) utils.Logf("Response : %v", resp) @@ -153,30 +165,53 @@ func importAPI(endpoint, filePath, accessToken string, extraParams map[string]st utils.Logln(utils.LogPrefixError, err) return err } - if resp.StatusCode() == http.StatusCreated || resp.StatusCode() == http.StatusOK { - // 201 Created or 200 OK - fmt.Println("Successfully imported API.") - return nil + if dryRun { + if resp.StatusCode() == http.StatusOK && resp.String() != "" { + // 200 OK + var data JSONData + err := json.Unmarshal([]byte(resp.String()), &data) + if err != nil { + utils.Logln(utils.LogPrefixError, err) + fmt.Println("Error occurred while validating API") + return errors.New(resp.Status()) + } + if data.ComplianceCheck.Result == "fail" { + PrintViolations(data.ComplianceCheck.Violations, apiLoggingCmdFormat) + } else if resp.StatusCode() == http.StatusOK { + fmt.Printf("No violations found for the API") + } + } else { + // We have an HTTP error + utils.Logln(utils.LogPrefixError, err) + fmt.Println("Error occurred while validating API") + return errors.New(resp.Status()) + } } else { - // We have an HTTP error - fmt.Println("Error importing API.") - fmt.Println("Status: " + resp.Status()) - fmt.Println("Response:", resp) - return errors.New(resp.Status()) + if resp.StatusCode() == http.StatusCreated || resp.StatusCode() == http.StatusOK { + // 201 Created or 200 OK + fmt.Println("Successfully imported API.") + } else { + // We have an HTTP error + utils.Logln(utils.LogPrefixError, err) + return errors.New(resp.Status()) + } } + return nil } // ImportAPIToEnv function is used with import-api command func ImportAPIToEnv(accessOAuthToken, importEnvironment, importPath, apiParamsPath string, importAPIUpdate, - preserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments bool) error { + preserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments bool, dryRun bool, + apiLoggingCmdFormat string) error { publisherEndpoint := utils.GetPublisherEndpointOfEnv(importEnvironment, utils.MainConfigFilePath) return ImportAPI(accessOAuthToken, publisherEndpoint, importEnvironment, importPath, apiParamsPath, importAPIUpdate, - preserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments) + preserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments, dryRun, apiLoggingCmdFormat) } // ImportAPI function is used with import-api command func ImportAPI(accessOAuthToken, publisherEndpoint, importEnvironment, importPath, apiParamsPath string, importAPIUpdate, - preserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments bool) error { + preserveProvider, importAPISkipCleanup, importAPIRotateRevision, importAPISkipDeployments bool, + dryRun bool, apiLoggingCmdFormat string) error { exportDirectory := filepath.Join(utils.ExportDirectory, utils.ExportedApisDirName) resolvedAPIFilePath, err := resolveImportFilePath(importPath, exportDirectory) if err != nil { @@ -246,9 +281,13 @@ func ImportAPI(accessOAuthToken, publisherEndpoint, importEnvironment, importPat publisherEndpoint += "?preserveProvider=" + strconv.FormatBool(preserveProvider) + "&rotateRevision=" + strconv.FormatBool(importAPIRotateRevision) } + + if dryRun { + publisherEndpoint += "&dryRun=" + strconv.FormatBool(true) + } utils.Logln(utils.LogPrefixInfo + "Import URL: " + publisherEndpoint) - err = importAPI(publisherEndpoint, apiFilePath, accessOAuthToken, extraParams, true) + err = importAPI(publisherEndpoint, apiFilePath, accessOAuthToken, extraParams, true, dryRun, apiLoggingCmdFormat) return err } diff --git a/import-export-cli/impl/printPolicyViolations.go b/import-export-cli/impl/printPolicyViolations.go new file mode 100644 index 000000000..e054b8751 --- /dev/null +++ b/import-export-cli/impl/printPolicyViolations.go @@ -0,0 +1,97 @@ +/* +* Copyright (c) 2025 WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except +* in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. + */ + +package impl + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/olekukonko/tablewriter" +) + +// Violation represents a violation +type Violation struct { + Policy string `json:"policy"` + Rulesets []Ruleset `json:"rulesets"` +} + +// Ruleset represents a ruleset +type Ruleset struct { + Ruleset string `json:"ruleset"` + Type string `json:"type"` + RuleViolations []RuleViolation `json:"rule-violations"` +} + +// RuleViolation represents a rule violation +type RuleViolation struct { + Path string `json:"path"` + Message string `json:"message"` + Severity string `json:"severity"` +} + +// PrintViolations prints the violations in the given format +// If apiLoggingCmdFormat is "json", it prints the violations in JSON format +// If apiLoggingCmdFormat is "list", it prints the violations in list format +// If apiLoggingCmdFormat is "table" or empty, it prints the violations in table format +// @param violations: List of violations +// @param apiLoggingCmdFormat: Format to print the violations +// @return None +func PrintViolations(violations []Violation, apiLoggingCmdFormat string) { + + if apiLoggingCmdFormat == "json" { + violationsJSON, err := json.MarshalIndent(violations, "", " ") + if err != nil { + fmt.Println("Error marshaling violations to JSON:", err) + return + } + fmt.Println(string(violationsJSON)) + return + + } else if apiLoggingCmdFormat == "list" { + // Print violations in list format + fmt.Println("\nViolations:") + for _, violation := range violations { + fmt.Println("- Policy:", violation.Policy) + for _, ruleset := range violation.Rulesets { + fmt.Println(" Ruleset:", ruleset.Ruleset) + for _, rule := range ruleset.RuleViolations { + fmt.Printf(" - Path: %s | Message: %s | Severity: %s\n", rule.Path, rule.Message, rule.Severity) + } + } + } + } else if apiLoggingCmdFormat == "" || apiLoggingCmdFormat == "table" { + // Print violations in table format + for _, violation := range violations { + + for _, ruleset := range violation.Rulesets { + fmt.Printf("\nPolicy: %s\nRuleset: %s\n\n", violation.Policy, ruleset.Ruleset) + // Create table for each ruleset + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Path", "Message", "Severity"}) + // Append violations to the table + for _, violation := range ruleset.RuleViolations { + table.Append([]string{violation.Path, violation.Message, violation.Severity}) + } + // Render the table + table.Render() + } + } + } +} diff --git a/import-export-cli/resources/README.html b/import-export-cli/resources/README.html index cf43c48aa..9b077b58e 100644 --- a/import-export-cli/resources/README.html +++ b/import-export-cli/resources/README.html @@ -457,13 +457,13 @@

add env [environment]

--publisher https://apim.com:9443 \ --devportal https://apps.com:9443 \ --admin https://apim.com:9443 \ - --token https://gw.com:8243/token \ + --token https://gw.com:9443/oauth2/token \ --mi https://localhost:9164 apictl add env prod \ --apim https://apim.com:9443 \ --registration https://idp.com:9443 \ - --token https://gw.com:8243/token + --token https://gw.com:9443/oauth2/token