-
Notifications
You must be signed in to change notification settings - Fork 13
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
Add a ruletype for enforcing a file being present in a repo #227
Changes from all commits
8c1dd74
78c83db
44dbfde
def8b78
36785c5
c0c4636
5adfbf7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.idea/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
tests: | ||
- name: "File should be present" | ||
def: | ||
file: README | ||
content: "" | ||
params: {} | ||
expect: "pass" | ||
git: | ||
repo_base: file_present | ||
- name: "File is missing" | ||
def: | ||
file: README | ||
params: {} | ||
expect: "fail" | ||
git: | ||
repo_base: file_missing | ||
- name: "File present and matches content" | ||
def: | ||
file: README | ||
content: "Test content" | ||
params: {} | ||
expect: "pass" | ||
git: | ||
repo_base: file_present | ||
- name: "File present, but has different content" | ||
def: | ||
file: README | ||
content: "Different content" | ||
params: {} | ||
expect: "fail" | ||
git: | ||
repo_base: file_present | ||
- name: "File present, but has more content than expected" | ||
def: | ||
file: README | ||
content: "Test" | ||
params: { } | ||
expect: "fail" | ||
git: | ||
repo_base: file_present | ||
- name: "File present, but has less content than expected" | ||
def: | ||
file: README | ||
content: "Test content with a subset" | ||
params: { } | ||
expect: "fail" | ||
git: | ||
repo_base: file_present |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Test content |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
--- | ||
version: v1 | ||
release_phase: alpha | ||
type: rule-type | ||
name: enforce_file | ||
display_name: Enforce a file in the repository | ||
short_failure_message: File does not exist or does not match the expected content | ||
severity: | ||
value: medium | ||
context: {} | ||
description: | | ||
Enforce the presence of a file and its content in the repository. | ||
guidance: | | ||
Ensures that the repository contains a specific file and its content. | ||
|
||
This rule is useful for enforcing the presence of various files in the repository, such as LICENSE, README, CONTRIBUTING, | ||
CODE_OF_CONDUCT, Dependabot configuration files and many more. It can also be used to enforce the presence of specific | ||
content in the file so you know that the file is not just a placeholder. | ||
def: | ||
in_entity: repository | ||
rule_schema: | ||
type: object | ||
properties: | ||
file: | ||
type: string | ||
description: | | ||
The file to enforce in the repository. | ||
For example, LICENSE, README, CONTRIBUTING, .github/dependabot.yml, etc. | ||
content: | ||
type: string | ||
description: | | ||
The content to enforce in the file. | ||
For example, the content of the LICENSE file. | ||
default: "" | ||
apply_if_file: | ||
type: string | ||
description: | | ||
Optional. If specified, the rule will only be evaluated if the given file exists. | ||
This is useful for rules that are only applicable to certain types of repositories. | ||
default: "" | ||
required: | ||
- file | ||
ingest: | ||
type: git | ||
git: | ||
# The following code checks for the presence of a file and its content. | ||
# If the content is not specified (content = ""), then only the presence of the file is checked. | ||
# If apply_if_file is specified, the rule is only evaluated if that file exists. | ||
eval: | ||
type: rego | ||
rego: | ||
type: deny-by-default | ||
def: | | ||
package minder | ||
|
||
import future.keywords.if | ||
|
||
default allow := false | ||
default skip := false | ||
fileStr := trim_space(file.read(input.profile.file)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. concern: I'm afraid this can't be used to implement How complex would it be to support folders as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me see what I can do 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the main difficulty is that On the other hand, OSSF is not currently interested in remediation. |
||
|
||
# Skip if apply_if_file is specified and the file doesn't exist | ||
skip if { | ||
input.profile.apply_if_file != "" | ||
not file.exists(input.profile.apply_if_file) | ||
} | ||
|
||
allow if { | ||
# Read the file and check if it contains the content | ||
fileStr == trim_space(input.profile.content) | ||
} else if { | ||
# Check if the file exists and the content is left blank | ||
file.exists(input.profile.file) | ||
input.profile.content == "" | ||
} | ||
|
||
message := sprintf("Skipping rule because file %v does not exist", [input.profile.apply_if_file]) if { | ||
input.profile.apply_if_file != "" | ||
not file.exists(input.profile.apply_if_file) | ||
} else := sprintf("File %v does not exist", [input.profile.file]) if { | ||
not file.exists(input.profile.file) | ||
} else := sprintf("File %v does not match the expected content %v", [input.profile.file, input.profile.content]) if { | ||
fileStr != trim_space(input.profile.content) | ||
} | ||
remediate: | ||
type: pull_request | ||
pull_request: | ||
title: "Ensure {{.Profile.file }} exists with the expected content" | ||
body: | | ||
This is a Minder automated pull request. | ||
|
||
This pull request ensures that this repository contains the file {{.Profile.file}} with the expected content set by your organization. | ||
contents: | ||
- path: "{{.Profile.file}}" | ||
action: replace | ||
content: | | ||
{{.Profile.content}} | ||
Comment on lines
+86
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah! This is a (current) reason not to use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly 👍 Of course, we can try to do that if we want. I was also thinking if I should try and make the path field optional for the pull request remediation type, but at the same time I like explicitly scoping it so you don't accidentally push another change. My concern for not looking at these is both will be considered breaking changes so I think it'll be out of scope for this one. |
||
# Defines the configuration for alerting on the rule | ||
alert: | ||
type: security_advisory | ||
security_advisory: {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect that Dependabot is trickier, because you probably want it to be adjusted based on the languages present. The others seem fairly likely to be consistent.