1
+ ---
2
+ version : v1
3
+ release_phase : alpha
4
+ type : rule-type
5
+ name : osps-do-03
6
+ display_name : OSPS-DO-03 The project documentation MUST provide user guides for all basic functionality
7
+ short_failure_message : No user guides or project documentation found
8
+ severity :
9
+ value : low
10
+ context :
11
+ provider : github
12
+ description : |
13
+ Verifies that the project documentation provides a user guide.
14
+
15
+ This rule attempts to locate user guides from several project documentation sources.
16
+
17
+ Currently, this rule checks the following:
18
+
19
+ * The GitHub repository's public link
20
+ * A `docs` directory in the default branch of the repository with .md, .rst, .html or .txt files
21
+ * A `documentation` entry in SECURITY-INSIGHTS.yaml
22
+ * A `README.md` file containing preformatted text (triple-backtick) or the headings
23
+ "usage" or "getting started"
24
+
25
+ For more information, see [OpenSSF Security Baseline](https://baseline.openssf.org/#osps-do-03).
26
+ guidance : |
27
+ Publish documentation in one of the following well-known locations:
28
+
29
+ * Set the repository homepage to a documentation URL.
30
+ * Add a SECURITY-INSIGHTS.yaml file with a `documentation` entry
31
+ * Create a `docs` directory in the default branch of the repository
32
+ * Add a "usage" or "getting started" section to `README.md`
33
+ def :
34
+ in_entity : repository
35
+ rule_schema : {}
36
+ ingest :
37
+ type : git
38
+ eval :
39
+ type : rego
40
+ data_sources :
41
+ - name : ghapi
42
+ rego :
43
+ type : deny-by-default
44
+ def : |
45
+ package minder
46
+
47
+ import rego.v1
48
+
49
+ default allow := false
50
+
51
+ repo := sprintf("%s/%s", [])
52
+
53
+ allow if {
54
+ # Check the SECURITY-INSIGHTS.yaml file
55
+ file.exists("SECURITY-INSIGHTS.yaml")
56
+ si_data := yaml.unmarshal(file.read("SECURITY-INSIGHTS.yaml"))
57
+ count(si_data.documentation) > 0
58
+ }
59
+
60
+ # TODO: these should trigger a remediation to put them in
61
+ # SECURITY-INSIGHTS.yaml, but also still pass the check(?)
62
+
63
+ allow if {
64
+ # Check the GitHub homepage link
65
+ out = minder.datasource.ghapi.repo_config({
66
+ "owner": input.properties["github/repo_owner"],
67
+ "repo": input.properties["github/repo_name"]
68
+ })
69
+ out.body.homepage != ""
70
+ }
71
+
72
+ allow if {
73
+ # Check the docs directory
74
+ mdDocs := file.ls_glob("docs/*.md")
75
+ rstDocs := file.ls_glob("docs/*.rst")
76
+ htmlDocs := file.ls_glob("docs/*.html")
77
+ txtDocs := file.ls_glob("docs/*.txt")
78
+ count(mdDocs) + count(rstDocs) + count(htmlDocs) + count(txtDocs) > 0
79
+ }
80
+
81
+ readme := file.read("README.md")
82
+ allow if {
83
+ # Check the README.md file for preformatted text after the first line
84
+ regex.match("\n *```", readme)
85
+ }
86
+ allow if {
87
+ regex.match("\n#+ (?i:Usage|Getting Started)", readme)
88
+ }
89
+
90
+ # Remediation is a work in progress -- ideally, we could read which location(s)
91
+ # contained the documentation, and automatically update SECURITY-INSIGHTS.yaml
92
+ # with any missing documentation locations.
93
+ # remediate:
94
+ # type: pull_request
95
+ # pull_request:
96
+ # title: "Add documentation to security-insights.yaml"
97
+ # body: |
98
+ # This is a Minder automated pull request.
99
+
100
+ # This pull request links the discovered documentation in the security-insights.yaml file.
101
+ # method: minder.yq.evaluate
102
+ # params:
103
+ # # TODO: need to be able to feed output from eval into remediate
104
+ # expression: |
105
+ # .documentation = [ "./README.md" ]
106
+ # patterns:
107
+ # # TODO: need to be able to create files as well as match existing files
108
+ # - pattern: "SECURITY-INSIGHTS.yaml"
109
+ # type: glob
0 commit comments