Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add rego policy for provenance checks #11

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions policy/governance/governance.rego
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
package governance

import data.security

default allow = false

pullrequest_attestations :=
[att | json.unmarshal(input[i].Attestation).predicateType == "https://liatr.io/attestations/github-pull-request/v1"; att := json.unmarshal(input[i].Attestation)]
pullrequest_attestations := [att | json.unmarshal(input[i].Attestation).predicateType == "https://liatr.io/attestations/github-pull-request/v1"; att := json.unmarshal(input[i].Attestation)]

trivy_attestations :=
[att | json.unmarshal(input[i].Attestation).predicateType == "https://cosign.sigstore.dev/attestation/vuln/v1"; att := json.unmarshal(input[i].Attestation)]
trivy_attestations := [att | json.unmarshal(input[i].Attestation).predicateType == "https://cosign.sigstore.dev/attestation/vuln/v1"; att := json.unmarshal(input[i].Attestation)]

sbom_attestations :=
[att | json.unmarshal(input[i].Attestation).predicateType == "https://spdx.dev/Document"; att := json.unmarshal(input[i].Attestation)]
sbom_attestations := [att | json.unmarshal(input[i].Attestation).predicateType == "https://spdx.dev/Document"; att := json.unmarshal(input[i].Attestation)]

provenance_attestations := [att | json.unmarshal(input[i].Attestation).predicateType == "https://slsa.dev/provenance/v0.2"; att := json.unmarshal(input[i].Attestation)]

allow {
violations := pullrequest_violations | trivy_violations | sbom_violations
print(violations)
count(violations) == 0
violations := ((pullrequest_violations | trivy_violations) | sbom_violations) | provenance_violations
print(violations)
count(violations) == 0
}

provenance_violations[msg] {
count(provenance_attestations) == 0
msg := "no provenance attestation"
}

provenance_violations[msg] {
some i
attestation := provenance_attestations[i]
not security.provenance.allow with input as attestation
msg := "provenance violation found"
}

pullrequest_violations[msg] {
count(pullrequest_attestations) == 0
msg := "no pull request attestation"
count(pullrequest_attestations) == 0
msg := "no pull request attestation"
}

pullrequest_violations[msg] {
Expand All @@ -30,13 +41,13 @@ pullrequest_violations[msg] {
}

sbom_violations[msg] {
count(sbom_attestations) == 0
msg:= "no sbom attestation"
count(sbom_attestations) == 0
msg := "no sbom attestation"
}

trivy_violations[msg] {
count(trivy_attestations) == 0
msg := "no trivy attestation"
count(trivy_attestations) == 0
msg := "no trivy attestation"
}

trivy_violations[msg] {
Expand Down
12 changes: 6 additions & 6 deletions policy/governance/governance_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package governance_test
import data.governance.allow

test_all_pass {
case := [data.test.pullrequest.two_reviewers, data.test.trivy.no_results, data.test.sbom.app]
case := [data.test.pullrequest.two_reviewers, data.test.trivy.no_results, data.test.sbom.app, data.test.provenance]
allow with input as case
}

test_fail_no_pull_request {
case := [data.test.trivy.no_results]
not allow with input as case
case := [data.test.trivy.no_results]
not allow with input as case
}

test_fail_no_reviewer {
Expand All @@ -28,6 +28,6 @@ test_fail_medium_vuln {
}

test_fail_no_sbom {
case := [data.test.pullrequest.two_reviewers, data.test.trivy.no_results]
not allow with input as case
}
case := [data.test.pullrequest.two_reviewers, data.test.trivy.no_results]
not allow with input as case
}
16 changes: 8 additions & 8 deletions policy/governance/identities.rego
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package governance

signer_identities := [
{
"issuer": "https://token.actions.githubusercontent.com",
"subjectRegExp": `^https://github\.com/liatrio/gh-trusted-builds-workflows/\.github/workflows/build-and-push\.yaml@refs/tags/v\d+\.\d+\.\d+$`,
},
{
"issuer": "https://token.actions.githubusercontent.com",
"subjectRegExp": `^https://github\.com/liatrio/gh-trusted-builds-workflows/\.github/workflows/scan-image\.yaml@refs/tags/v\d+\.\d+\.\d+$`,
}
{
"issuer": "https://token.actions.githubusercontent.com",
"subjectRegExp": `^https://github\.com/liatrio/gh-trusted-builds-workflows/\.github/workflows/build-and-push\.yaml@refs/tags/v\d+\.\d+\.\d+$`,
},
{
"issuer": "https://token.actions.githubusercontent.com",
"subjectRegExp": `^https://github\.com/liatrio/gh-trusted-builds-workflows/\.github/workflows/scan-image\.yaml@refs/tags/v\d+\.\d+\.\d+$`,
},
]
21 changes: 21 additions & 0 deletions policy/security/provenance.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package security.provenance

default allow = false

allow {
count(violation) == 0
}

buildType := "https://github.com/slsa-framework/slsa-github-generator/container@v1"

orgName := "Liatrio"

violation[msg] {
input.predicate.buildType != buildType
msg := "provenance build type is incorrect"
}

violation[msg] {
input.predicate.invocation.environment.github_event_payload.enterprise.name != orgName
msg := "provenance enterprise name is not Liatrio"
}
33 changes: 33 additions & 0 deletions policy/security/provenance_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package security.provenance

# Test that allow is false when buildType is incorrect
test_fail_incorrect_buildType {
input := {"predicate": {"buildType": "incorrect_buildType", "invocation": {"environment": {"github_event_payload": {"enterprise": {"name": "Liatrio"}}}}}}
not allow with input as input
}

# Test that allow is false when enterprise name is not Liatrio
test_fail_incorrect_enterprise_name {
input := {"predicate": {"buildType": "https://github.com/slsa-framework/slsa-github-generator/container@v1", "invocation": {"environment": {"github_event_payload": {"enterprise": {"name": "NotLiatrio"}}}}}}
not allow with input as input
}

# Test that allow is true when buildType is correct and enterprise name is Liatrio
test_allow_correct_buildType_and_enterprise_name {
input := {"predicate": {"buildType": "https://github.com/slsa-framework/slsa-github-generator/container@v1", "invocation": {"environment": {"github_event_payload": {"enterprise": {"name": "Liatrio"}}}}}}
allow with input as input
}

# Test that violation message is correct when buildType is incorrect
test_violation_incorrect_buildType {
input := {"predicate": {"buildType": "incorrect_buildType", "invocation": {"environment": {"github_event_payload": {"enterprise": {"name": "Liatrio"}}}}}}
violation[msg] with input as input
msg == "provenance build type is incorrect"
}

# Test that violation message is correct when enterprise name is not Liatrio
test_violation_incorrect_enterprise_name {
input := {"predicate": {"buildType": "https://github.com/slsa-framework/slsa-github-generator/container@v1", "invocation": {"environment": {"github_event_payload": {"enterprise": {"name": "NotLiatrio"}}}}}}
violation[msg] with input as input
msg == "provenance enterprise name is not Liatrio"
}
33 changes: 33 additions & 0 deletions policy/security/pullrequest_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package security.pullrequest

# Test that allow is false when there are no reviewers
test_allow_no_reviewers {
input := {"predicate": {"reviewers": null}}
not allow with input as input
}

# Test that allow is false when reviewers count is less than 1
test_allow_less_than_one_reviewer {
input := {"predicate": {"reviewers": []}}
not allow with input as input
}

# Test that allow is true when reviewers count is 1 or more
test_allow_one_or_more_reviewers {
input := {"predicate": {"reviewers": ["Alice"]}}
allow with input as input
}

# Test that violation message is correct when there are no reviewers
test_violation_no_reviewers {
input := {"predicate": {"reviewers": null}}
violation[msg] with input as input
msg == "pull request reviewers is null"
}

# Test that violation message is correct when reviewers count is less than 1
test_violation_less_than_one_reviewer {
input := {"predicate": {"reviewers": []}}
violation[msg] with input as input
msg == "pull request reviewers is less than 1"
}
10 changes: 5 additions & 5 deletions policy/security/trivy.rego
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package security.trivy
default allow = false

allow {
count(violation) == 0
count(violation) == 0
}

violation[msg] {
severities := ["MEDIUM","HIGH","CRITICAL"]
input.predicate.scanner.result.Results[_].Vulnerabilities[_].Severity == severities[_]
msg := "vulnerability higher than medium"
}
severities := ["MEDIUM", "HIGH", "CRITICAL"]
input.predicate.scanner.result.Results[_].Vulnerabilities[_].Severity == severities[_]
msg := "vulnerability higher than medium"
}
Loading