Skip to content

Commit 90cf5e1

Browse files
blktevankanderson
andauthored
Add OSPS Baseline Level 1 rules. (#265)
* 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 * Update security-baseline/rule-types/github/osps-do-01.yaml * Update security-baseline/rule-types/github/osps-do-01.yaml * Update security-baseline/rule-types/github/osps-do-01.yaml * Update security-baseline/rule-types/github/osps-qa-01.yaml --------- Co-authored-by: Evan Anderson <[email protected]>
1 parent f4e479c commit 90cf5e1

File tree

27 files changed

+715
-74
lines changed

27 files changed

+715
-74
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_config:
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

profiles/github/security_baseline_1.yaml

-41
This file was deleted.
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,37 @@
1+
version: v1
2+
type: profile
3+
name: security-baseline-level-1
4+
display_name: OSPS Security Baseline - Level 1
5+
context:
6+
provider: github
7+
alert: "off"
8+
remediate: "off"
9+
repository:
10+
# OSPS-AC-03: Prevent overwriting git history
11+
- name: osps-ac-03
12+
type: osps-ac-03
13+
def: {}
14+
# OSPS-AC-04: Prevent permanent branch deletion
15+
- name: osps-ac-04
16+
type: osps-ac-04
17+
def: {}
18+
# OSPS-DO-01: Projects has public discussion mechanisms
19+
- name: osps-do-01
20+
type: osps-do-01
21+
def: {}
22+
# OSPS-DO-02: Enforce CONTRIBUTING file presence
23+
- name: osps-do-02
24+
type: osps-do-02
25+
def: {}
26+
# OSPS-LE-02: Ensure OSI/FSF approved license
27+
- name: osps-le-02
28+
type: osps-le-02
29+
def: {}
30+
# OSPS-LE-03: LICENSE or COPYING files are available available
31+
- name: osps-le-03
32+
type: osps-le-03
33+
def: {}
34+
# OSPS-QA-01: Repository visibility check
35+
- name: osps-qa-01
36+
type: osps-qa-01
37+
def: {}
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-03
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

0 commit comments

Comments
 (0)