diff --git a/e2e/testcases/e2e-cli-082_critical_severity_all_report_formats.go b/e2e/testcases/e2e-cli-082_critical_severity_all_report_formats.go new file mode 100644 index 00000000000..3d4ae4fdcb1 --- /dev/null +++ b/e2e/testcases/e2e-cli-082_critical_severity_all_report_formats.go @@ -0,0 +1,28 @@ +package testcases + +// E2E-CLI-082 - Kics scan command with --report-formats and --output-path flags +// should export the results based on the formats provided by this flag, with critical severity +func init() { //nolint + testSample := TestCase{ + Name: "should export the results based on the formats provided by this flag, with critical severity [E2E-CLI-082]", + Args: args{ + Args: []cmdArgs{ + []string{"scan", "-o", "/path/e2e/output", + "--output-name", "E2E_CLI_082_RESULT", + "--report-formats", "asff,codeclimate,csv,cyclonedx,glsast,html,json,junit,pdf,sarif,sonarqube", + "-p", "\"/path/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test\"", + "-q", "\"/path/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/query\"", + }, + }, + ExpectedResult: []ResultsValidation{ + { + ResultsFile: "E2E_CLI_082_RESULT", + ResultsFormats: []string{"asff", "codeclimate", "csv", "cyclonedx", "glsast", "html", "json", "junit", "pdf", "sarif", "sonarqube"}, + }, + }, + }, + WantStatus: []int{60}, + } + + Tests = append(Tests, testSample) +} diff --git a/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/query/metadata.json b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/query/metadata.json new file mode 100644 index 00000000000..ba9304dfc3f --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/query/metadata.json @@ -0,0 +1,12 @@ +{ + "id": "316278b3-87ac-444c-8f8f-a733a28da60z", + "queryName": "AmazonMQ Broker Encryption Disabled", + "severity": "CRITICAL", + "category": "Encryption", + "descriptionText": "AmazonMQ Broker should have Encryption Options defined", + "descriptionUrl": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amazonmq-broker.html#cfn-amazonmq-broker-encryptionoptions", + "platform": "CloudFormation", + "descriptionID": "c5d562dz", + "cloudProvider": "aws", + "cwe": "" +} \ No newline at end of file diff --git a/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/query/query.rego b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/query/query.rego new file mode 100644 index 00000000000..f9807221666 --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/query/query.rego @@ -0,0 +1,22 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.cloudformation as cf_lib + +CxPolicy[result] { + document := input.document + resource = document[i].Resources[name] + resource.Type == "AWS::AmazonMQ::Broker" + properties := resource.Properties + not common_lib.valid_key(properties, "EncryptionOptions") + + result := { + "documentId": input.document[i].id, + "resourceType": resource.Type, + "resourceName": cf_lib.get_resource_name(resource, name), + "searchKey": sprintf("Resources.%s.Properties.EncryptionOptions", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("Resources.%s.Properties.EncryptionOptions should be defined", [name]), + "keyActualValue": sprintf("Resources.%s.Properties.EncryptionOptions is not defined", [name]), + } +} diff --git a/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/negative1.yaml b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/negative1.yaml new file mode 100644 index 00000000000..3409ba5b986 --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/negative1.yaml @@ -0,0 +1,24 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: "Create a basic ActiveMQ broker" +Resources: + BasicBroker: + Type: "AWS::AmazonMQ::Broker" + Properties: + AutoMinorVersionUpgrade: "false" + BrokerName: MyBasicBroker + DeploymentMode: SINGLE_INSTANCE + EncryptionOptions: + UseAwsOwnedKey: true + EngineType: ActiveMQ + EngineVersion: "5.15.0" + HostInstanceType: mq.t2.micro + PubliclyAccessible: "true" + Users: + - + ConsoleAccess: "true" + Groups: + - MyGroup + Password: + Ref: "BrokerPassword" + Username: + Ref: "BrokerUsername" diff --git a/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/positive1.yaml b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/positive1.yaml new file mode 100644 index 00000000000..608d090dbc2 --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/positive1.yaml @@ -0,0 +1,22 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: "Create a basic ActiveMQ broker" +Resources: + BasicBroker: + Type: "AWS::AmazonMQ::Broker" + Properties: + AutoMinorVersionUpgrade: "false" + BrokerName: MyBasicBroker + DeploymentMode: SINGLE_INSTANCE + EngineType: ActiveMQ + EngineVersion: "5.15.0" + HostInstanceType: mq.t2.micro + PubliclyAccessible: "true" + Users: + - + ConsoleAccess: "true" + Groups: + - MyGroup + Password: + Ref: "BrokerPassword" + Username: + Ref: "BrokerUsername" diff --git a/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/positive_expected_result.json b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/positive_expected_result.json new file mode 100644 index 00000000000..918c86deee0 --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/amazon_mq_broker_encryption_disabled/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "AmazonMQ Broker Encryption Disabled", + "severity": "CRITICAL", + "line": 1, + "fileName": "positive1.yaml" + } +] diff --git a/test/fixtures/test_critical_custom_queries/run_block_injection/query/metadata.json b/test/fixtures/test_critical_custom_queries/run_block_injection/query/metadata.json new file mode 100644 index 00000000000..8ed40e55983 --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/run_block_injection/query/metadata.json @@ -0,0 +1,12 @@ +{ + "id": "20f14e1a-a899-4e79-9f09-b6a84cd4649b", + "queryName": "Run Block Injection", + "severity": "CRITICAL", + "category": "Insecure Configurations", + "descriptionText": "GitHub Actions workflows can be triggered by a variety of events. Every workflow trigger is provided with a GitHub context that contains information about the triggering event, such as which user triggered it, the branch name, and other event context details. Some of this event data, like the base repository name, hash value of a changeset, or pull request number, is unlikely to be controlled or used for injection by the user that triggered the event.", + "descriptionUrl": "https://securitylab.github.com/research/github-actions-untrusted-input/", + "platform": "CICD", + "descriptionID": "02044a75", + "cloudProvider": "common", + "cwe": "" +} \ No newline at end of file diff --git a/test/fixtures/test_critical_custom_queries/run_block_injection/query/query.rego b/test/fixtures/test_critical_custom_queries/run_block_injection/query/query.rego new file mode 100644 index 00000000000..ae9a223c10e --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/run_block_injection/query/query.rego @@ -0,0 +1,186 @@ +package Cx + +import data.generic.common as common_lib + +CxPolicy[result] { + + input.document[i].on["pull_request_target"] + run := input.document[i].jobs[j].steps[k].run + + patterns := [ + "github.head_ref", + "github.event.pull_request.body", + "github.event.pull_request.head.label", + "github.event.pull_request.head.ref", + "github.event.pull_request.head.repo.default_branch", + "github.event.pull_request.head.repo.description", + "github.event.pull_request.head.repo.homepage", + "github.event.pull_request.title" + ] + + matched = containsPatterns(run, patterns) + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("run={{%s}}", [run]), + "issueType": "IncorrectValue", + "keyExpectedValue": "Run block does not contain dangerous input controlled by user.", + "keyActualValue": "Run block contains dangerous input controlled by user.", + "searchLine": common_lib.build_search_line(["jobs", j, "steps", k, "run"],[]), + "searchValue": matched[m] + } +} + +CxPolicy[result] { + + input.document[i].on["issues"] + run := input.document[i].jobs[j].steps[k].run + + patterns := [ + "github.event.issue.body", + "github.event.issue.title" + ] + + matched = containsPatterns(run, patterns) + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("run={{%s}}", [run]), + "issueType": "IncorrectValue", + "keyExpectedValue": "Run block does not contain dangerous input controlled by user.", + "keyActualValue": "Run block contains dangerous input controlled by user.", + "searchLine": common_lib.build_search_line(["jobs", j, "steps", k, "run"],[]), + "searchValue": matched[m] + } +} + +CxPolicy[result] { + + input.document[i].on["issue_comment"] + run := input.document[i].jobs[j].steps[k].run + + patterns := [ + "github.event.comment.body", + "github.event.issue.body", + "github.event.issue.title" + ] + + matched = containsPatterns(run, patterns) + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("run={{%s}}", [run]), + "issueType": "IncorrectValue", + "keyExpectedValue": "Run block does not contain dangerous input controlled by user.", + "keyActualValue": "Run block contains dangerous input controlled by user.", + "searchLine": common_lib.build_search_line(["jobs", j, "steps", k, "run"],[]), + "searchValue": matched[m] + } +} + +CxPolicy[result] { + + input.document[i].on["discussion"] + run := input.document[i].jobs[j].steps[k].run + + patterns := [ + "github.event.discussion.body", + "github.event.discussion.title" + ] + + matched = containsPatterns(run, patterns) + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("run={{%s}}", [run]), + "issueType": "IncorrectValue", + "keyExpectedValue": "Run block does not contain dangerous input controlled by user.", + "keyActualValue": "Run block contains dangerous input controlled by user.", + "searchLine": common_lib.build_search_line(["jobs", j, "steps", k, "run"],[]), + "searchValue": matched[m] + } +} + +CxPolicy[result] { + + input.document[i].on["discussion_comment"] + run := input.document[i].jobs[j].steps[k].run + + patterns := [ + "github.event.comment.body", + "github.event.discussion.body", + "github.event.discussion.title" + ] + + matched = containsPatterns(run, patterns) + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("run={{%s}}", [run]), + "issueType": "IncorrectValue", + "keyExpectedValue": "Run block does not contain dangerous input controlled by user.", + "keyActualValue": "Run block contains dangerous input controlled by user.", + "searchLine": common_lib.build_search_line(["jobs", j, "steps", k, "run"],[]), + "searchValue": matched[m] + } +} + +CxPolicy[result] { + + input.document[i].on["workflow_run"] + run := input.document[i].jobs[j].steps[k].run + + patterns := [ + "github.event.workflow.path", + "github.event.workflow_run.head_branch", + "github.event.workflow_run.head_commit.author.email", + "github.event.workflow_run.head_commit.author.name", + "github.event.workflow_run.head_commit.message", + "github.event.workflow_run.head_repository.description" + ] + + matched = containsPatterns(run, patterns) + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("run={{%s}}", [run]), + "issueType": "IncorrectValue", + "keyExpectedValue": "Run block does not contain dangerous input controlled by user.", + "keyActualValue": "Run block contains dangerous input controlled by user.", + "searchLine": common_lib.build_search_line(["jobs", j, "steps", k, "run"],[]), + "searchValue": matched[m] + } +} + +CxPolicy[result] { + + input.document[i].on["author"] + run := input.document[i].jobs[j].steps[k].run + + patterns := [ + "github.*.authors.name", + "github.*.authors.email" + ] + + matched = containsPatterns(run, patterns) + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("run={{%s}}", [run]), + "issueType": "IncorrectValue", + "keyExpectedValue": "Run block does not contain dangerous input controlled by user.", + "keyActualValue": "Run block contains dangerous input controlled by user.", + "searchLine": common_lib.build_search_line(["jobs", j, "steps", k, "run"],[]), + "searchValue": matched[m] + } +} + + + +containsPatterns(str, patterns) = matched { + matched := {pattern | + pattern := patterns[_] + regex.match(pattern, str) + } +} + diff --git a/test/fixtures/test_critical_custom_queries/run_block_injection/test/negative.yaml b/test/fixtures/test_critical_custom_queries/run_block_injection/test/negative.yaml new file mode 100644 index 00000000000..5f9d4a2dfd5 --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/run_block_injection/test/negative.yaml @@ -0,0 +1,29 @@ +name: check-go-coverage + +on: + pull_request_target: + branches: [master] + +jobs: + coverage: + name: Check Go coverage + runs-on: ubuntu-latest + steps: + - name: Checkout Source + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up Go 1.20.x + uses: actions/setup-go@v4 + with: + go-version: 1.20.x + - name: Run test metrics script + id: testcov + run: | + make test-coverage-report | tee test-results + echo "coverage=$(cat test-results | grep "Total coverage: " test-results | cut -d ":" -f 2 | bc)" >> $GITHUB_ENV + - name: Checks if Go coverage is at least 80% + if: env.coverage < 80 + run: | + echo "Go coverage is lower than 80%: ${{ env.coverage }}%" + exit 1 \ No newline at end of file diff --git a/test/fixtures/test_critical_custom_queries/run_block_injection/test/positive1.yaml b/test/fixtures/test_critical_custom_queries/run_block_injection/test/positive1.yaml new file mode 100644 index 00000000000..6ee6d54c544 --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/run_block_injection/test/positive1.yaml @@ -0,0 +1,39 @@ +name: Web Page To Markdown +on: + issues: + types: [opened] +jobs: + WebPageToMarkdown: + runs-on: ubuntu-latest + steps: + - name: Does the issue need to be converted to markdown + run: | + if [ "${{ github.event.issue.body }}" ]; then + if [[ "${{ github.event.issue.title }}" =~ ^\[Auto\]* ]]; then + : + else + echo "This issue does not need to generate a markdown file." 1>&2 + exit 1; + fi; + else + echo "The description of the issue is empty." 1>&2 + exit 1; + fi; + shell: bash + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.head_ref }} + - name: Crawl pages and generate Markdown files + uses: freeCodeCamp-China/article-webpage-to-markdown-action@v0.1.8 + with: + newsLink: '${{ github.event.issue.Body }}' + markDownFilePath: './chinese/articles/' + githubToken: ${{ github.token }} + - name: Git Auto Commit + uses: stefanzweifel/git-auto-commit-action@v4.9.2 + with: + commit_message: '${{ github.event.issue.title }}' + file_pattern: chinese/articles/*.md + commit_user_name: PageToMarkdown Bot + commit_user_email: PageToMarkdown-bot@freeCodeCamp.org \ No newline at end of file diff --git a/test/fixtures/test_critical_custom_queries/run_block_injection/test/positive_expected_result.json b/test/fixtures/test_critical_custom_queries/run_block_injection/test/positive_expected_result.json new file mode 100644 index 00000000000..2c8cf126a1c --- /dev/null +++ b/test/fixtures/test_critical_custom_queries/run_block_injection/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Run Block Injection", + "severity": "CRITICAL", + "line": 10, + "fileName": "positive1.yaml" + } +]