From e184641c1cae5df232ef2f62597440d9e041a35f Mon Sep 17 00:00:00 2001 From: Matthew Donoughe Date: Mon, 29 Apr 2024 10:24:16 -0400 Subject: [PATCH] configure policy linting --- .github/workflows/lint.yml | 29 +++++++++++++++++ .regal/config.yaml | 16 ++++++++++ confirmed_malicious.rego | 60 ++++++++++++++++-------------------- data_exfiltration.rego | 38 ++++++++++------------- default.rego | 3 +- dependency_confusion.rego | 30 ++++++++---------- install_code.rego | 30 ++++++++---------- install_code_suspicious.rego | 39 ++++++++++------------- license_mismatch.rego | 30 ++++++++---------- minimal_code.rego | 30 ++++++++---------- obfuscated_code.rego | 29 ++++++++--------- per_domain.rego | 4 +-- secret_non_test.rego | 30 ++++++++---------- show_all.rego | 10 +++--- typosquat.rego | 56 ++++++++++++++++----------------- vuln_crit.rego | 34 +++++++++----------- vuln_crit_high.rego | 34 +++++++++----------- 17 files changed, 239 insertions(+), 263 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .regal/config.yaml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..e75b20c --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,29 @@ +name: Lint policies + +on: + push: + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup OPA + uses: open-policy-agent/setup-opa@v2.2.0 + with: + version: 0.61 + + - name: Setup Regal + uses: StyraInc/setup-regal@v1.0.0 + with: + version: 0.21 + + - name: OPA Check + if: ${{ !cancelled() }} + run: opa check --strict --max-errors 0 . + + - name: Regal Lint + if: ${{ !cancelled() }} + run: regal lint --format github ./policy diff --git a/.regal/config.yaml b/.regal/config.yaml new file mode 100644 index 0000000..ef8de92 --- /dev/null +++ b/.regal/config.yaml @@ -0,0 +1,16 @@ +capabilities: + from: + engine: opa + version: v0.61.0 + minus: + builtins: + - name: http.send +rules: + idiomatic: + no-defined-entrypoint: + level: ignore + imports: + unresolved-import: + level: error + except-imports: + - data.phylum.* diff --git a/confirmed_malicious.rego b/confirmed_malicious.rego index 39a795b..b61b12a 100644 --- a/confirmed_malicious.rego +++ b/confirmed_malicious.rego @@ -1,33 +1,27 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the author is known malicious -issue contains "Author has published malicious packages" if { - data.issue.tag == "CA0001" -} - -# Returns a violation if the package contains verified malware -issue contains "This package contains malware" if { - data.issue.tag == "CM0038" -} - -# Returns a violation if the package contains a known-bad compiled binary -issue contains "Contains known-bad compiled binary" if { - data.issue.tag == "CM0037" -} - -# Returns a violation if the package depends on a known malicious package -issue contains "This package depends on malware" if { - data.issue.tag == "CM0039" -} +package policy + +import rego.v1 + +# Returns a violation if the author is known malicious +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Author has published malicious packages" if { + data.issue.tag == "CA0001" +} + +# Returns a violation if the package contains verified malware +issue contains "This package contains malware" if { + data.issue.tag == "CM0038" +} + +# Returns a violation if the package contains a known-bad compiled binary +issue contains "Contains known-bad compiled binary" if { + data.issue.tag == "CM0037" +} + +# Returns a violation if the package depends on a known malicious package +issue contains "This package depends on malware" if { + data.issue.tag == "CM0039" +} diff --git a/data_exfiltration.rego b/data_exfiltration.rego index a212a23..cd06551 100644 --- a/data_exfiltration.rego +++ b/data_exfiltration.rego @@ -1,22 +1,16 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the package contains common data exfiltration techniques -issue contains "Package contains environment variable enumeration" if { - data.issue.tag == "HM0025" -} - -issue contains "Package contains webhook exfiltration" if { - data.issue.tag == "HM0036" -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if the package contains common data exfiltration techniques +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Package contains environment variable enumeration" if { + data.issue.tag == "HM0025" +} + +issue contains "Package contains webhook exfiltration" if { + data.issue.tag == "HM0036" +} diff --git a/default.rego b/default.rego index 76b3dd2..f36fd5c 100644 --- a/default.rego +++ b/default.rego @@ -1,8 +1,7 @@ package policy import data.phylum.level -import future.keywords.contains -import future.keywords.if +import rego.v1 issue contains "risk level cannot exceed medium" if { data.issue.severity > level.MEDIUM diff --git a/dependency_confusion.rego b/dependency_confusion.rego index 7c95d9d..9395058 100644 --- a/dependency_confusion.rego +++ b/dependency_confusion.rego @@ -1,18 +1,12 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the package appears to be a dependency confusion -issue contains "Package appears to be a dependency confusion" if { - data.issue.tag == "HM0018" -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if the package appears to be a dependency confusion +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Package appears to be a dependency confusion" if { + data.issue.tag == "HM0018" +} diff --git a/install_code.rego b/install_code.rego index 9896861..7bf766d 100644 --- a/install_code.rego +++ b/install_code.rego @@ -1,18 +1,12 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if there is code execution on package install -issue contains "Package contains code execution on install" if { - data.issue.tag in {"IM0042", "IM0043", "IM0044"} -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if there is code execution on package install +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Package contains code execution on install" if { + data.issue.tag in {"IM0042", "IM0043", "IM0044"} +} diff --git a/install_code_suspicious.rego b/install_code_suspicious.rego index 65c0a44..43b39cf 100644 --- a/install_code_suspicious.rego +++ b/install_code_suspicious.rego @@ -1,23 +1,16 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if there is suspicious code execution on package install - -issue contains "Package contains suspicious code execution on install" if { - data.issue.tag == "CM0007" -} - -issue contains "Package contains suspicious code execution on install" if { - endswith(data.issue.tag, "M0031") -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if there is suspicious code execution on package install +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Package contains suspicious code execution on install" if { + data.issue.tag == "CM0007" +} + +issue contains "Package contains suspicious code execution on install" if { + endswith(data.issue.tag, "M0031") +} diff --git a/license_mismatch.rego b/license_mismatch.rego index bb9c21b..37db533 100644 --- a/license_mismatch.rego +++ b/license_mismatch.rego @@ -1,18 +1,12 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if there is a license mismatch between metadata and files -issue contains "License mismatch" if { - data.issue.tag == "IL0022" -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if there is a license mismatch between metadata and files +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "License mismatch" if { + data.issue.tag == "IL0022" +} diff --git a/minimal_code.rego b/minimal_code.rego index ad9ec5c..acb6696 100644 --- a/minimal_code.rego +++ b/minimal_code.rego @@ -1,18 +1,12 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the package contains minimal code and is unlikley worth the security risk -issue contains "Package contains minimal code" if { - data.issue.tag == "IE0027" -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if the package contains minimal code and is unlikley worth the security risk +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Package contains minimal code" if { + data.issue.tag == "IE0027" +} diff --git a/obfuscated_code.rego b/obfuscated_code.rego index 6d7bfef..f663e46 100644 --- a/obfuscated_code.rego +++ b/obfuscated_code.rego @@ -1,17 +1,12 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the package contains obfuscated code -issue contains "Package contains obfuscated code" if { - data.issue.tag in {"HM0029", "HM0099", "HM0023", "IM0040", "IM0041"} -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if the package contains obfuscated code +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Package contains obfuscated code" if { + data.issue.tag in {"HM0029", "HM0099", "HM0023", "IM0040", "IM0041"} +} diff --git a/per_domain.rego b/per_domain.rego index 5a3e8b0..f49c67d 100644 --- a/per_domain.rego +++ b/per_domain.rego @@ -2,9 +2,7 @@ package policy import data.phylum.domain import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in +import rego.v1 issue contains "risk level cannot exceed medium" if { data.issue.domain in {domain.AUTHOR, domain.ENGINEERING, domain.VULNERABILITY} diff --git a/secret_non_test.rego b/secret_non_test.rego index a14f3a5..dddd294 100644 --- a/secret_non_test.rego +++ b/secret_non_test.rego @@ -1,18 +1,12 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the package contains secrets/tokens excluding test/example files -issue contains "Secrets in non-test file" if { - data.issue.tag == "ME0016" -} \ No newline at end of file +package policy + +import rego.v1 + +# Returns a violation if the package contains secrets/tokens excluding test/example files +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Secrets in non-test file" if { + data.issue.tag == "ME0016" +} diff --git a/show_all.rego b/show_all.rego index 1e35c4e..a1484de 100644 --- a/show_all.rego +++ b/show_all.rego @@ -1,5 +1,5 @@ -package policy - -import future.keywords.contains - -issue contains "Policy Violation" \ No newline at end of file +package policy + +import rego.v1 + +issue contains "Policy Violation" diff --git a/typosquat.rego b/typosquat.rego index 182ee0b..b580e39 100644 --- a/typosquat.rego +++ b/typosquat.rego @@ -1,30 +1,26 @@ -package policy - -import data.phylum.ecosystem -import data.phylum.domain -import data.phylum.level - -import future.keywords.contains -import future.keywords.if - -# Returns `true` if the given dependency has a typosquat issue -has_typosquat { - some i - data.dependency.issues[i].tag == "HM0008" -} - -# Returns `true` if the dependency has more than one malware issue -has_more_than_one_malware_issue { - issues := data.dependency.issues - count([dom | issues[i].domain == domain.MALICIOUS; dom := issues[i].domain]) > 1 -} - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -issue contains "Potential typosquat with malicious characteristics" if { - has_typosquat - has_more_than_one_malware_issue -} \ No newline at end of file +package policy + +import data.phylum.domain + +import rego.v1 + +# Returns `true` if the given dependency has a typosquat issue +has_typosquat if { + some issue in data.dependency.issues + issue.tag == "HM0008" +} + +# Returns `true` if the dependency has more than one malware issue +has_more_than_one_malware_issue if { + some issue in data.dependency.issues + count([dom | issue.domain == domain.MALICIOUS; dom := issue.domain]) > 1 +} + +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Potential typosquat with malicious characteristics" if { + has_typosquat + has_more_than_one_malware_issue +} diff --git a/vuln_crit.rego b/vuln_crit.rego index 9d4f818..56afbb8 100644 --- a/vuln_crit.rego +++ b/vuln_crit.rego @@ -1,19 +1,15 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the package has a Critical software vulnerability -issue contains "Critical software vulnerability" if { - data.issue.domain == domain.VULNERABILITY - data.issue.severity > level.HIGH -} \ No newline at end of file +package policy + +import data.phylum.domain +import data.phylum.level +import rego.v1 + +# Returns a violation if the package has a Critical software vulnerability +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Critical software vulnerability" if { + data.issue.domain == domain.VULNERABILITY + data.issue.severity > level.HIGH +} diff --git a/vuln_crit_high.rego b/vuln_crit_high.rego index cfb9023..fc57dfe 100644 --- a/vuln_crit_high.rego +++ b/vuln_crit_high.rego @@ -1,19 +1,15 @@ -package policy - -import data.phylum.domain -import data.phylum.level -import future.keywords.contains -import future.keywords.if -import future.keywords.in - - -# METADATA -# scope: rule -# schemas: -# - data.issue: schema.issue - -# Returns a violation if the package has a Critical or High software vulnerability -issue contains "Critical or High software vulnerability" if { - data.issue.domain == domain.VULNERABILITY - data.issue.severity > level.MEDIUM -} \ No newline at end of file +package policy + +import data.phylum.domain +import data.phylum.level +import rego.v1 + +# Returns a violation if the package has a Critical or High software vulnerability +# METADATA +# scope: rule +# schemas: +# - data.issue: schema.issue +issue contains "Critical or High software vulnerability" if { + data.issue.domain == domain.VULNERABILITY + data.issue.severity > level.MEDIUM +}