Skip to content

Commit 50f2fb9

Browse files
committed
Add OSPS Baseline Level 1 rules.
This change adds all currently implemented rule types for OSPS Baseline Level 1. Some rules were copy-pasted from rules like e.g. `branch_protection_allow_deletions` in order to (a) be able to change them independently and (b) change the name to something descriptive in the scope of Security Baseline. We generally do not foster this, but in this case we deemed simplicity was preferable to avoiding duplication. Along the rules themselves, tests were added to new, existing ones, and their copies. Fixes stacklok/minder-stories#198
1 parent 632390f commit 50f2fb9

File tree

25 files changed

+698
-33
lines changed

25 files changed

+698
-33
lines changed

data-sources/ghapi.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,13 @@ rest:
1414
type: string
1515
repo:
1616
type: string
17+
repo:
18+
endpoint: https://api.github.com/repos/{owner}/{repo}
19+
parse: json
20+
input_schema:
21+
type: object
22+
properties:
23+
owner:
24+
type: string
25+
repo:
26+
type: string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
tests:
2+
- name: "force push not allowed"
3+
def: {}
4+
params: {}
5+
entity:
6+
type: repository
7+
entity:
8+
owner: "mindersec"
9+
name: "minder"
10+
expect: "pass"
11+
http:
12+
status: 200
13+
body: '{"allow_deletions": {"enabled": false}}'
14+
- name: "force push allowed"
15+
def: {}
16+
params: {}
17+
entity:
18+
type: repository
19+
entity:
20+
owner: "mindersec"
21+
name: "minder"
22+
expect: "fail"
23+
http:
24+
status: 200
25+
body: '{"allow_deletions": {"enabled": true}}'
26+
- name: "not found"
27+
def: {}
28+
params: {}
29+
entity:
30+
type: repository
31+
entity:
32+
owner: "mindersec"
33+
name: "minder"
34+
expect: "fail"
35+
http:
36+
status: 404
37+
body: '{"woot": "woot"}'
38+
- name: "internal error"
39+
def: {}
40+
params: {}
41+
entity:
42+
type: repository
43+
entity:
44+
owner: "mindersec"
45+
name: "minder"
46+
expect: "fail"
47+
http:
48+
status: 502
49+
body: '{"woot": "woot"}'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
tests:
2+
- name: "force push not allowed"
3+
def: {}
4+
params: {}
5+
entity:
6+
type: repository
7+
entity:
8+
owner: "mindersec"
9+
name: "minder"
10+
expect: "pass"
11+
http:
12+
status: 200
13+
body: '{"allow_force_pushes": {"enabled": false}}'
14+
- name: "force push allowed"
15+
def: {}
16+
params: {}
17+
entity:
18+
type: repository
19+
entity:
20+
owner: "mindersec"
21+
name: "minder"
22+
expect: "fail"
23+
http:
24+
status: 200
25+
body: '{"allow_force_pushes": {"enabled": true}}'
26+
- name: "not found"
27+
def: {}
28+
params: {}
29+
entity:
30+
type: repository
31+
entity:
32+
owner: "mindersec"
33+
name: "minder"
34+
expect: "fail"
35+
http:
36+
status: 404
37+
body: '{"woot": "woot"}'
38+
- name: "internal error"
39+
def: {}
40+
params: {}
41+
entity:
42+
type: repository
43+
entity:
44+
owner: "mindersec"
45+
name: "minder"
46+
expect: "fail"
47+
http:
48+
status: 502
49+
body: '{"woot": "woot"}'

rules_test.go

+35-33
Original file line numberDiff line numberDiff line change
@@ -131,50 +131,52 @@ func TestRuleTypes(t *testing.T) {
131131

132132
require.NoError(t, os.Setenv("REGO_ENABLE_PRINT", "true"))
133133

134-
// iterate rule types directory
135-
err := walkRuleTypesTests(t, func(t *testing.T, rt *minderv1.RuleType, tc *RuleTest, rtDataPath string) {
136-
var opts []tkv1.Option
137-
if rt.Def.Ingest.Type == "git" {
138-
opts = append(opts, gitTestOpts(t, tc, rtDataPath))
139-
} else if rt.Def.Ingest.Type == "rest" {
140-
opts = append(opts, httpTestOpts(t, tc, rtDataPath))
141-
} else {
142-
t.Skipf("Unsupported ingest type %s", rt.Def.Ingest.Type)
143-
}
134+
for _, folder := range []string{"rule-types", "security-baseline/rule-types"} {
135+
// iterate rule types directory
136+
err := walkRuleTypesTests(t, folder, func(t *testing.T, rt *minderv1.RuleType, tc *RuleTest, rtDataPath string) {
137+
var opts []tkv1.Option
138+
if rt.Def.Ingest.Type == "git" {
139+
opts = append(opts, gitTestOpts(t, tc, rtDataPath))
140+
} else if rt.Def.Ingest.Type == "rest" {
141+
opts = append(opts, httpTestOpts(t, tc, rtDataPath))
142+
} else {
143+
t.Skipf("Unsupported ingest type %s", rt.Def.Ingest.Type)
144+
}
144145

145-
ztw := zerolog.NewTestWriter(t)
146-
zerolog.SetGlobalLevel(zerolog.DebugLevel)
147-
ctx := zerolog.New(ztw).With().Timestamp().Logger().WithContext(context.Background())
146+
ztw := zerolog.NewTestWriter(t)
147+
zerolog.SetGlobalLevel(zerolog.DebugLevel)
148+
ctx := zerolog.New(ztw).With().Timestamp().Logger().WithContext(context.Background())
148149

149-
tk := tkv1.NewTestKit(opts...)
150-
rte, err := rtengine.NewRuleTypeEngine(ctx, rt, tk, nil)
151-
require.NoError(t, err)
150+
tk := tkv1.NewTestKit(opts...)
151+
rte, err := rtengine.NewRuleTypeEngine(ctx, rt, tk, nil)
152+
require.NoError(t, err)
152153

153-
val := rte.GetRuleInstanceValidator()
154-
require.NoError(t, val.ValidateRuleDefAgainstSchema(tc.Def), "Failed to validate rule definition against schema")
155-
require.NoError(t, val.ValidateParamsAgainstSchema(tc.Params), "Failed to validate params against schema")
154+
val := rte.GetRuleInstanceValidator()
155+
require.NoError(t, val.ValidateRuleDefAgainstSchema(tc.Def), "Failed to validate rule definition against schema")
156+
require.NoError(t, val.ValidateParamsAgainstSchema(tc.Params), "Failed to validate params against schema")
156157

157-
if tk.ShouldOverrideIngest() {
158-
rte.WithCustomIngester(tk)
159-
}
158+
if tk.ShouldOverrideIngest() {
159+
rte.WithCustomIngester(tk)
160+
}
160161

161-
_, err = rte.Eval(ctx, tc.Entity.Entity, tc.Def, tc.Params, tkv1.NewVoidResultSink())
162-
if tc.Expect == ExpectPass {
163-
require.NoError(t, err)
164-
} else {
165-
require.Error(t, err)
166-
}
167-
})
162+
_, err = rte.Eval(ctx, tc.Entity.Entity, tc.Def, tc.Params, tkv1.NewVoidResultSink())
163+
if tc.Expect == ExpectPass {
164+
require.NoError(t, err)
165+
} else {
166+
require.Error(t, err)
167+
}
168+
})
168169

169-
if err != nil {
170-
t.Error(err)
170+
if err != nil {
171+
t.Error(err)
172+
}
171173
}
172174
}
173175

174-
func walkRuleTypesTests(t *testing.T, testfunc RuleTypeTestFunc) error {
176+
func walkRuleTypesTests(t *testing.T, folder string, testfunc RuleTypeTestFunc) error {
175177
t.Helper()
176178

177-
return filepath.Walk("rule-types", func(path string, info os.FileInfo, err error) error {
179+
return filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
178180
if err != nil {
179181
return err
180182
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data-sources/ghapi.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
tests:
2+
- name: "force push not allowed"
3+
def: {}
4+
params: {}
5+
entity:
6+
type: repository
7+
entity:
8+
owner: "mindersec"
9+
name: "minder"
10+
expect: "pass"
11+
http:
12+
status: 200
13+
body: '{"allow_force_pushes": {"enabled": false}}'
14+
- name: "force push allowed"
15+
def: {}
16+
params: {}
17+
entity:
18+
type: repository
19+
entity:
20+
owner: "mindersec"
21+
name: "minder"
22+
expect: "fail"
23+
http:
24+
status: 200
25+
body: '{"allow_force_pushes": {"enabled": true}}'
26+
- name: "not found"
27+
def: {}
28+
params: {}
29+
entity:
30+
type: repository
31+
entity:
32+
owner: "mindersec"
33+
name: "minder"
34+
expect: "fail"
35+
http:
36+
status: 404
37+
body: '{"woot": "woot"}'
38+
- name: "internal error"
39+
def: {}
40+
params: {}
41+
entity:
42+
type: repository
43+
entity:
44+
owner: "mindersec"
45+
name: "minder"
46+
expect: "fail"
47+
http:
48+
status: 502
49+
body: '{"woot": "woot"}'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
version: v1
2+
release_phase: alpha
3+
type: rule-type
4+
name: osps-ac-04
5+
display_name: Prevent overwriting git history
6+
short_failure_message: Force pushes are allowed
7+
severity:
8+
value: info
9+
context:
10+
provider: github
11+
description: Disallow force pushes to the branch
12+
guidance: |
13+
Ensure that the appropriate setting is disabled for the branch
14+
protection rule.
15+
16+
This setting prevents users with push access to force push to the
17+
branch.
18+
19+
For more information, see [GitHub's
20+
documentation](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule).
21+
def:
22+
in_entity: repository
23+
rule_schema: {}
24+
ingest:
25+
type: rest
26+
rest:
27+
endpoint: '/repos/{{.Entity.Owner}}/{{.Entity.Name}}/branches/{{ .Entity.DefaultBranch }}/protection'
28+
parse: json
29+
fallback:
30+
- http_code: 404
31+
body: |
32+
{"http_status": 404, "message": "Not Protected"}
33+
eval:
34+
type: jq
35+
jq:
36+
- ingested:
37+
def: ".allow_force_pushes.enabled"
38+
constant: false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
tests:
2+
- name: "force push not allowed"
3+
def: {}
4+
params: {}
5+
entity:
6+
type: repository
7+
entity:
8+
owner: "mindersec"
9+
name: "minder"
10+
expect: "pass"
11+
http:
12+
status: 200
13+
body: '{"allow_deletions": {"enabled": false}}'
14+
- name: "force push allowed"
15+
def: {}
16+
params: {}
17+
entity:
18+
type: repository
19+
entity:
20+
owner: "mindersec"
21+
name: "minder"
22+
expect: "fail"
23+
http:
24+
status: 200
25+
body: '{"allow_deletions": {"enabled": true}}'
26+
- name: "not found"
27+
def: {}
28+
params: {}
29+
entity:
30+
type: repository
31+
entity:
32+
owner: "mindersec"
33+
name: "minder"
34+
expect: "fail"
35+
http:
36+
status: 404
37+
body: '{"woot": "woot"}'
38+
- name: "internal error"
39+
def: {}
40+
params: {}
41+
entity:
42+
type: repository
43+
entity:
44+
owner: "mindersec"
45+
name: "minder"
46+
expect: "fail"
47+
http:
48+
status: 502
49+
body: '{"woot": "woot"}'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
version: v1
2+
release_phase: alpha
3+
type: rule-type
4+
name: osps-ac-04
5+
display_name: Prevent permanent branch deletion
6+
short_failure_message: Branch protection allows deletions
7+
severity:
8+
value: info
9+
context:
10+
provider: github
11+
description: Prevents the branch from being deleted
12+
guidance: |
13+
Ensure that the "Allow deletions" setting is disabled for the branch
14+
protection rule.
15+
16+
Prevent users from deleting matching branches.
17+
18+
For more information, see [GitHub's
19+
documentation](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule).
20+
def:
21+
in_entity: repository
22+
rule_schema: {}
23+
ingest:
24+
type: rest
25+
rest:
26+
endpoint: '/repos/{{.Entity.Owner}}/{{.Entity.Name}}/branches/{{ .Entity.DefaultBranch }}/protection'
27+
parse: json
28+
fallback:
29+
- http_code: 404
30+
body: |
31+
{"http_status": 404, "message": "Not Protected"}
32+
eval:
33+
type: jq
34+
jq:
35+
- ingested:
36+
def: ".allow_deletions.enabled"
37+
constant: false

0 commit comments

Comments
 (0)