Merge ubuntu-security-tools:iosifache/semgrep-rules-manager into ubuntu-security-tools:master

Proposed by George-Andrei Iosif
Status: Rejected
Rejected by: George-Andrei Iosif
Proposed branch: ubuntu-security-tools:iosifache/semgrep-rules-manager
Merge into: ubuntu-security-tools:master
Diff against target: 199 lines (+87/-7)
6 files modified
audits/.gitignore (+2/-0)
audits/CONTRIBUTING.md (+4/-0)
audits/README.md (+2/-0)
audits/custom-semgrep-rules/third-party/.gitkeep (+0/-0)
audits/uaudit (+78/-6)
audits/workflow.template (+1/-1)
Reviewer Review Type Date Requested Status
Spyros Seimenis Needs Fixing
Review via email: mp+448255@code.launchpad.net

Commit message

Integrates semgrep-rules-manager

Description of the change

This merge proposal targets the auditing capabilities of UST.

As a result of the Semgrep integration in MP #446963 [1], the commits in this merge proposal include a newly constructed Semgrep-related utility, semgrep-rules-manager.

The objective of semgrep-rules-manager [2] is to manage third-party Semgrep rule sources by enabling actions such as downloading, listing, synchronizing, and uninstalling. Beside the open source codebase, there are also a snap [4] and a Python package [5] available.

The merge proposal adds a new workflow:
1. When the first time uaudit is launched, the user is prompted if she wishes to install new Semgrep rules.
2. If yes, the semgrep-rules-manager snap is installed on the local host.
3. Once the installation is complete, all Semgrep rule sources are downloaded to $UST/audits/custom-semgrep-rules/third-party. This allows the user to avoid getting lost in a maze of files by writing her custom rules in the root of $UST/audits/custom-semgrep-rules and having the automatically downloaded ones on $UST/audits/custom-semgrep-rules/third-party.
4. uaudit will then launch Semgrep, which will detect and use the downloaded rules for scanning.

Regardless of the answer supplied in the first step, semgrep-rules-manager can be alternatively launched with the --download-semgrep-rules flag from uaudit.

The commits, in addition to the mentioned behaviour, target documentation files (README.md and CONTRIBUTING.md), which are updated with information about the changes made in this MP.

[1] https://code.launchpad.net/~ubuntu-security/ubuntu-security-tools/+git/ubuntu-security-tools/+merge/446963
[2] https://github.com/iosifache/semgrep-rules-manager
[3] https://snapcraft.io/semgrep-rules-manager
[4] https://pypi.org/project/semgrep-rules-manager

P.S.: The previously generated Semgrep snap is actively utilized by tens of users in our community! The download of semgrep-rules-manager has also begun. So happy about this!

To post a comment you must log in.
Revision history for this message
Spyros Seimenis (sespiros) wrote (last edit ):

I think we can reuse the logic and flow that is already there for tool installation instead of introducing extra helpers. The new requirement of semgrep-rules-manager for example can be handled in verify_requirements() or maybe even better in uaudit_install_dependencies() directly:

```python
def uaudit_install_dependencies():
    dependencies = {}
    for tool in static_analysis_tools:
        dependencies[tool.name] = tool.install_cmd()

+ dependencies["semgrep-rules-manager"] = ["snap", "install", "semgrep-rules-manager"]

    for tool, cmd_args in dependencies.items():
        if is_program_installed(tool):
            debug(f'{tool} is already installed in the system')
        else:
            install_tool(cmd_args, tool)

```

Then we would only need to prompt for the extra sources via ask_for_custom_semgrep_rules() -> download_custom_semgrep_rules() and remove the ensure_installed_semgrep_rules_manager() method.

review: Needs Fixing

Unmerged commits

78b19f8... by George-Andrei Iosif

Updates the documentation with info about semgrep-rules-manager

Signed-off-by: George-Andrei Iosif <email address hidden>

3827dde... by George-Andrei Iosif

Integrates semgrep-rules-manager in uaudit

Signed-off-by: George-Andrei Iosif <email address hidden>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/audits/.gitignore b/audits/.gitignore
0new file mode 1006440new file mode 100644
index 0000000..e01805a
--- /dev/null
+++ b/audits/.gitignore
@@ -0,0 +1,2 @@
1custom-semgrep-rules/third-party/*
2!custom-semgrep-rules/third-party/.gitkeep
0\ No newline at end of file3\ No newline at end of file
diff --git a/audits/CONTRIBUTING.md b/audits/CONTRIBUTING.md
index 8d59bfa..7c79d99 100644
--- a/audits/CONTRIBUTING.md
+++ b/audits/CONTRIBUTING.md
@@ -20,3 +20,7 @@
20 ```20 ```
2121
225. If the `summary` member of your `StaticAnalysisTool` object is initialized, its content can be used in reports (e.g. `bug.template` and `workflow.template`) by embedding the `$tool_id>` variable. A frequent usecase is to save the number of created errors and warnings and reference it in the "Static analysis results summary" section of `jira.template`.225. If the `summary` member of your `StaticAnalysisTool` object is initialized, its content can be used in reports (e.g. `bug.template` and `workflow.template`) by embedding the `$tool_id>` variable. A frequent usecase is to save the number of created errors and warnings and reference it in the "Static analysis results summary" section of `jira.template`.
23
24## Adding Third-party Semgrep Rules
25
26Please follow the [contribution guide from `semgrep-rules-manager`](https://github.com/iosifache/semgrep-rules-manager/blob/main/CONTRIBUTING.md#add-a-new-source-with-semgrep-rules).
diff --git a/audits/README.md b/audits/README.md
index b34440f..841b25a 100644
--- a/audits/README.md
+++ b/audits/README.md
@@ -18,6 +18,8 @@
18 $ uaudit --download-release=precise hello18 $ uaudit --download-release=precise hello
19 ```19 ```
2020
21If you run `uaudit` for the first time on your system, it will ask if you wish to download additional third-party Semgrep rules. If you intend to scan with Semgrep and opt to download the rules, they will be saved in `./custom-semgrep-rules/third-party`. If you decided not to download them but later changed your mind, execute `uadit --download-semgrep-rules`.
22
21Observe the output of `uaudit`. It uses `umt` to download and build source and binary packages. It also creates an `audits` directory that contains all the reports.23Observe the output of `uaudit`. It uses `umt` to download and build source and binary packages. It also creates an `audits` directory that contains all the reports.
2224
23`uaudit` will generate its reports in `<toplevel source>/audits`. You might want to copy these to somewhere safe (eg, `~/ubuntu/security/audits`). Ideas for starting points are in `WORKFLOW.md`. Sift through the various reports, be25`uaudit` will generate its reports in `<toplevel source>/audits`. You might want to copy these to somewhere safe (eg, `~/ubuntu/security/audits`). Ideas for starting points are in `WORKFLOW.md`. Sift through the various reports, be
diff --git a/audits/custom-semgrep-rules/third-party/.gitkeep b/audits/custom-semgrep-rules/third-party/.gitkeep
24new file mode 10064426new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audits/custom-semgrep-rules/third-party/.gitkeep
diff --git a/audits/uaudit b/audits/uaudit
index 96d03d2..f3b8aef 100755
--- a/audits/uaudit
+++ b/audits/uaudit
@@ -46,6 +46,9 @@ class StaticAnalysisToolSource(Enum):
4646
47OUTPUT_FILE="$OUTPUT"47OUTPUT_FILE="$OUTPUT"
4848
49def get_custom_semgrep_rules_location() -> str:
50 return os.path.join(os.path.dirname(__file__), "custom-semgrep-rules")
51
49class StaticAnalysisTool(object):52class StaticAnalysisTool(object):
50 """A class modeling a static analysis tool53 """A class modeling a static analysis tool
5154
@@ -265,7 +268,7 @@ static_analysis_tools = [
265 "--config",268 "--config",
266 "auto",269 "auto",
267 "--config",270 "--config",
268 os.path.join(os.path.dirname(__file__), "custom-semgrep-rules")271 get_custom_semgrep_rules_location()
269 ],272 ],
270 cmd_txt=["--vim"],273 cmd_txt=["--vim"],
271 cmd_json=["--json"],274 cmd_json=["--json"],
@@ -506,15 +509,21 @@ def uaudit_setup_env():
506509
507510
508def query_user_consent_to_install_tool(cmd_args, tool):511def query_user_consent_to_install_tool(cmd_args, tool):
509 valid_answers = {"yes": True, "y": True, "no": False, "n": False}
510 command = " ".join(cmd_args)512 command = " ".join(cmd_args)
511 question = f"{tool} is not present in the system.\n" \513 question = f"{tool} is not present in the system.\n" \
512 "The preferred version can be installed by running:\n" \514 "The preferred version can be installed by running:\n" \
513 f" {command}\n" \515 f" {command}\n" \
514 "Do you want to run this now to install it? [y/n] "516 "Do you want to run this now to install it? [y/n] "
515517
518 return ask_question_with_binary_response(question)
519
520
521def ask_question_with_binary_response(question) -> bool:
522 valid_answers = {"yes": True, "y": True, "no": False, "n": False}
523
516 while True:524 while True:
517 sys.stdout.write(question)525 sys.stdout.write(question)
526
518 choice = input().lower()527 choice = input().lower()
519 if choice in valid_answers:528 if choice in valid_answers:
520 return valid_answers[choice]529 return valid_answers[choice]
@@ -538,12 +547,15 @@ def uaudit_install_dependencies():
538 for tool in static_analysis_tools:547 for tool in static_analysis_tools:
539 dependencies[tool.name] = tool.install_cmd()548 dependencies[tool.name] = tool.install_cmd()
540 for tool, cmd_args in dependencies.items():549 for tool, cmd_args in dependencies.items():
541 rc, out = cmd(['which', tool])550 if is_program_installed(tool):
542 if rc != 0:
543 install_tool(cmd_args, tool)
544 else:
545 debug(f'{tool} is already installed in the system')551 debug(f'{tool} is already installed in the system')
552 else:
553 install_tool(cmd_args, tool)
546554
555def is_program_installed(software_name: str) -> bool:
556 rc, _ = cmd(['which', software_name])
557
558 return (rc == 0)
547559
548def verify_requirements():560def verify_requirements():
549 uaudit_setup_env()561 uaudit_setup_env()
@@ -1139,6 +1151,55 @@ def create_tags(audit_dir):
11391151
1140 msg("Tags file: %s" % (out_fn_rel))1152 msg("Tags file: %s" % (out_fn_rel))
11411153
1154def ask_for_custom_semgrep_rules() -> None:
1155 user_not_asked_before = check_create_semgrep_ask_file()
1156 if not user_not_asked_before:
1157 return
1158
1159 question = """\
1160Because Semgrep is built into uaudit for SAST, you can download extra rules to
1161your system to uncover more potential software flaws. Do you wish to install
1162semgrep-rules-manager automatically and download all Semgrep rule sources?
1163[y/n] """
1164
1165 response = ask_question_with_binary_response(question)
1166 if response:
1167 download_custom_semgrep_rules()
1168
1169
1170def check_create_semgrep_ask_file() -> bool:
1171 ask_fn = os.path.join(get_3rd_party_semgrep_rules_location(), ".ask")
1172
1173 if os.path.isfile(ask_fn):
1174 return False
1175
1176 os.mknod(ask_fn)
1177
1178 return True
1179
1180
1181def get_3rd_party_semgrep_rules_location() -> str:
1182 return os.path.join(get_custom_semgrep_rules_location(), "third-party")
1183
1184
1185def download_custom_semgrep_rules() -> None:
1186 ensure_installed_semgrep_rules_manager()
1187
1188 location = get_3rd_party_semgrep_rules_location()
1189
1190 rc, out = cmd(["semgrep-rules-manager", "--dir", location, "download"])
1191 if rc == 0:
1192 msg("The third-party Semgrep rules were downloaded!")
1193 else:
1194 error(f"An error occurred while running semgrep-rules-manager!")
1195
1196
1197def ensure_installed_semgrep_rules_manager() -> None:
1198 if not is_program_installed("semgrep-rules-manager"):
1199 rc, out = cmd(["snap", "install", "semgrep-rules-manager"])
1200 if rc != 0:
1201 error(f"An error occurred while installing semgrep-rules-manager!")
1202
11421203
1143def get_usage():1204def get_usage():
1144 '''Print usage statement'''1205 '''Print usage statement'''
@@ -1237,6 +1298,11 @@ if __name__ == "__main__":
1237 default=False,1298 default=False,
1238 help="Disable automatic coverity integration via cov-build",1299 help="Disable automatic coverity integration via cov-build",
1239 action="store_true")1300 action="store_true")
1301 parser.add_argument("--download-semgrep-rules",
1302 dest="download_semgrep_rules",
1303 default=False,
1304 help="Download additonal Semgrep rules and exit",
1305 action="store_true")
1240 parser.add_argument("--debug",1306 parser.add_argument("--debug",
1241 default=False,1307 default=False,
1242 help="Print debug output",1308 help="Print debug output",
@@ -1264,6 +1330,12 @@ if __name__ == "__main__":
12641330
1265 verify_requirements()1331 verify_requirements()
12661332
1333 if args.download_semgrep_rules:
1334 download_custom_semgrep_rules()
1335 exit()
1336 else:
1337 ask_for_custom_semgrep_rules()
1338
1267 if not os.path.exists(args.config):1339 if not os.path.exists(args.config):
1268 error("Could not find '%s'" % args.config)1340 error("Could not find '%s'" % args.config)
1269 ust = load_ust_config(args.config)1341 ust = load_ust_config(args.config)
diff --git a/audits/workflow.template b/audits/workflow.template
index 17735f3..c0b6c2a 100644
--- a/audits/workflow.template
+++ b/audits/workflow.template
@@ -74,7 +74,7 @@ the response within the Launchpad MIR bug.
74### CVE History74### CVE History
7575
76- Run $UCT/scripts/pkg_history $package.76- Run $UCT/scripts/pkg_history $package.
77- Run $UCT/scripts/pkg_status $package77- Run $UCT/scripts/pkg_status $package.
78- If there are old CVEs,78- If there are old CVEs,
79 - What were they?79 - What were they?
80 - Were they fixed in a timely fashion?80 - Were they fixed in a timely fashion?

Subscribers

People subscribed via source and target branches