Skip to content

Commit 9a9c1ff

Browse files
authored
Added cli feature (#6)
* Updated path to osspoi datastore
1 parent 8093937 commit 9a9c1ff

22 files changed

Lines changed: 925 additions & 570 deletions

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
ossp_data.json
1+
__pycache__/
2+
.vscode/
3+
.pytest_cache/
4+
dist/
5+
besecure_developer_toolkit/__pycache__/
6+
besecure_developer_toolkit/src/__pycache__/

README.md

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,60 @@
1-
# besecure-developer-toolkit
1+
# Be-Secure Developer Toolkit (bes-dev-kit)
22

3-
The toolkit helps you to quickly generate meta data for BeSLighthouse visualisation.
3+
bes-dev-kit is a cli tool for generating metadata and assessment report for [BeSLighthouse](https://github.com/Be-Secure/BeSLighthouse).
44

5-
It can generate the following data -
6-
- ossp-master
7-
- version details
8-
- scorecard
9-
- criticality score
5+
# Installation
106

11-
## Pre-requisites
7+
`$ python3 -m pip install besecure-developer-toolkit`
128

13-
1. Python 3.x
14-
2. GitHub personal access token (classic).
15-
3. Set all the variables under [config](acc-config.cfg) file.
9+
# Pre-requisites
1610

17-
## Keep in mind
11+
1. [Poetry](https://python-poetry.org/)
12+
2. Python 3.x
13+
3. pip
14+
4. Github personal access token
1815

19-
1. Make sure the format of the version is correct under [Be-Secure/issues](https://github.com/Be-Secure/Be-Secure/issues).
20-
2. Name of the project is case-sensitive. Please provide the name of the project exactly as is given in their repository.
16+
# Setting env variables
17+
18+
`Note: Should be done before testing/running`
19+
20+
1. Creating a json file in your user home dir under the name `bes-dev-kit.json`.
21+
2. Copy the below contents and paste it inside the file.
2122

22-
` Note:- Make sure you give the complete path to the directories`
23+
{
24+
"GITHUB_ORG": "Be-Secure",
25+
"OSSPOI_DIR": "<complete_path_to>/besecure-osspoi-datastore",
26+
"ASSESSMENT_DIR": "<complete_path_to>/besecure-assessment-datastore",
27+
"GITHUB_AUTH_TOKEN": "<token>"
28+
}
29+
3. Update `OSSPOI_DIR` and `ASSESSMENT_DIR` with complete path to your `besecure-assessment-datastore` and `besecure-osspoi-datastore` dirs.
30+
4. Add your github personal access token
31+
32+
33+
# Setting up locally
34+
35+
1. Install [poetry](https://python-poetry.org/). Use the [link](https://python-poetry.org/docs/) to install Poetry.
36+
2. Clone the repo.
37+
3. Move into the cloned directory.
38+
4. Create a new virtual env using Poetry - `$ poetry shell`
39+
5. Run the command to install the tool- `$ poetry install`
40+
6. Check installation - `$ bes-dev-kit --help`
41+
42+
# Usage
43+
44+
### Generate Metadata
45+
46+
Command helps to generate metadata such as OSSP-master file data and version details file.
47+
48+
`$ bes-dev-kit generate metadata`
49+
50+
For more options use `--help` at end.
51+
52+
### Generate Reports
53+
54+
`$ bes-dev-kit generate report <report name>`
55+
56+
`<report name> - scorecard, codeql, criticality_score`
57+
58+
For more options use `--help` at end.
2359

24-
## Usage
25-
1. Open terminal
26-
2. Using the below command, run [osspoi-meta-data-generator.sh](scripts/osspoi-meta-data-generator.sh) file.
27-
28-
`$ ./osspoi-meta-data-generator.sh`
60+
`Note: All three reports can be generated at once by passing all report names - $ bes-dev-kit generate report scorecard criticality_score codeql`

acc-config.cfg

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Top-level package for Be-Secure Developer toolkit."""
2+
# src/__init__.py
3+
4+
__app_name__ = "bes-dev-kit"
5+
__version__ = "0.0.1"
6+
7+
(
8+
SUCCESS,
9+
DIR_ERROR,
10+
FILE_ERROR,
11+
JSON_ERROR,
12+
ID_ERROR,
13+
) = range(5)
14+
15+
ERRORS = {
16+
DIR_ERROR: "config directory error",
17+
FILE_ERROR: "config file error",
18+
ID_ERROR: "to-do id error",
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Be-Secure Developer Toolkit entry point script."""
2+
from besecure_developer_toolkit import cli, __app_name__
3+
4+
def main():
5+
6+
cli.app(prog_name=__app_name__)
7+
8+
if __name__ == "__main__":
9+
main()

besecure_developer_toolkit/cli.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""This module provides the Be-Secure Developer Toolkit CLI."""
2+
# src/cli.py
3+
import sys, os, json
4+
from typing import Optional
5+
from typing import List
6+
from rich import print
7+
import typer
8+
from besecure_developer_toolkit import __app_name__, __version__
9+
from besecure_developer_toolkit.src.CreateOsspMaster import OSSPMaster
10+
from besecure_developer_toolkit.src.CreateVersionData import Version
11+
from besecure_developer_toolkit.src.GenerateReport import Report
12+
13+
def set_env_vars():
14+
user_home = os.path.expanduser('~')
15+
with open(user_home+'/bes_dev_kit.json', 'r') as f:
16+
vars = json.load(f)
17+
for key, value in vars.items():
18+
os.environ[key] = str(value)
19+
20+
set_env_vars()
21+
22+
app = typer.Typer()
23+
24+
generate_app = typer.Typer()
25+
26+
app.add_typer(generate_app, name="generate")
27+
28+
def _version_callback(value: bool) -> None:
29+
if value:
30+
typer.echo(f"{__app_name__} v{__version__}")
31+
raise typer.Exit()
32+
33+
34+
35+
@generate_app.command("metadata")
36+
def ossp(overwrite: bool = typer.Option(False, help="Overwrite the existing entries inside OSSP-master.json and version file")):
37+
""" Update OSSP-master.json file and add/update version file to osspoi datastore """
38+
try:
39+
id = int(input("Enter OSSP id:"))
40+
except ValueError:
41+
sys.exit("Input should be of type int")
42+
name = str(input("Enter OSSP name:"))
43+
ossp_data = OSSPMaster(id, name)
44+
ossp_data.GenerateOsspMaster(overwrite)
45+
version_data = Version(id, name)
46+
version_data.generate_version_data(overwrite)
47+
48+
@generate_app.command("report")
49+
def report(reports: List[str], update_version_file: bool = typer.Option(True, help="Update version file with scorecard/criticality score")):
50+
""" Following reports can be generated - scorecard, criticality_score, codeql"""
51+
if len(reports) > 3:
52+
print("[bold red]Alert! [green]Too many arguments")
53+
raise typer.Exit()
54+
else:
55+
try:
56+
id = int(input("Enter OSSP id:"))
57+
except ValueError:
58+
print("[bold red]Alert! [green]Expected type int")
59+
raise typer.Exit()
60+
61+
name = str(input("Enter OSSP name:"))
62+
version = str(input("Enter version of "+ name +":"))
63+
for i in reports:
64+
if i == "scorecard":
65+
scorecard_obj = Report(id, name, version, i)
66+
scorecard_obj.main()
67+
if update_version_file:
68+
scorecard_obj.update_version_data()
69+
elif i == "criticality_score":
70+
criticality_obj = Report(id, name, version, i)
71+
criticality_obj.main()
72+
if update_version_file:
73+
criticality_obj.update_version_data()
74+
elif i == "codeql":
75+
codeql_obj = Report(id, name, version, i)
76+
codeql_obj.main()
77+
78+
79+
80+
@app.callback()
81+
def main(
82+
version: Optional[bool] = typer.Option(
83+
None,
84+
"--version",
85+
"-v",
86+
help="Show the application's version and exit.",
87+
callback=_version_callback,
88+
is_eager=True,
89+
)
90+
):
91+
92+
return

besecure_developer_toolkit/config.py

Whitespace-only changes.
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import sys, os, json, subprocess
2+
from urllib.request import urlopen
3+
from rich import print
4+
5+
class OSSPMaster():
6+
7+
def __init__(self, id: int, name: str) -> None:
8+
self.id = id
9+
self.name = name
10+
11+
def check_issue_exists(self,id) -> None:
12+
try:
13+
urlopen('https://github.com/Be-Secure/Be-Secure/issues/'+str(id))
14+
except Exception as e:
15+
exc_type, exc_obj, exc_tb = sys.exc_info()
16+
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
17+
print(exc_type, fname, exc_tb.tb_lineno)
18+
print("Could not find issue with id : "+str(id))
19+
sys.exit()
20+
21+
def check_issue_related_to_project(self):
22+
23+
json_data = json.loads(urlopen(f'https://api.github.com/repos/Be-Secure/Be-Secure/issues/{self.id}').read())
24+
issue_title = json_data["title"]
25+
project_name = str(str(issue_title).split(":")[1]).replace(" ","")
26+
if project_name != self.name:
27+
print(f"[bold red]Alert! [yellow]Mismatch issue_id-project : [green] Issue id {self.id} does not match the project {self.name}")
28+
sys.exit()
29+
else:
30+
pass
31+
32+
33+
34+
def check_repo_exists(self,name) -> None:
35+
try:
36+
urlopen('https://api.github.com/repos/Be-Secure/'+name)
37+
except Exception as e:
38+
exc_type, exc_obj, exc_tb = sys.exc_info()
39+
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
40+
print(exc_type, fname, exc_tb.tb_lineno)
41+
print("Could not find "+ name +" under Be-Secure")
42+
sys.exit()
43+
44+
def write_tech_stack(self,bes_id):
45+
raw_data = urlopen("https://api.github.com/repos/Be-Secure/Be-Secure/issues/"+str(bes_id))
46+
47+
data = json.loads(raw_data.read())
48+
49+
body_data = iter(data["body"].splitlines())
50+
found = "false"
51+
for i in body_data:
52+
if i == "### Tech Stack":
53+
found = "true"
54+
continue
55+
if len(i.strip()) == 0:
56+
continue
57+
if len(i.strip()) != 0 and found == "true":
58+
s = str(i.split(" [")[1])
59+
s = str(s.split("]")[0])
60+
break
61+
return s
62+
def write_project_repos_data(self,project_data):
63+
project_repos = {
64+
"main_github_url": "",
65+
"main_bes_url": "",
66+
"all_projects": [
67+
{
68+
"id": 0,
69+
"name": "",
70+
"url": ""
71+
}
72+
],
73+
"all_bes_repos": [
74+
{
75+
"id": 0,
76+
"name": "",
77+
"url": ""
78+
}
79+
80+
]
81+
}
82+
project_repos.update({"main_github_url": project_data["parent"]["html_url"]})
83+
project_repos.update({"main_bes_url": project_data["html_url"]})
84+
project_repos["all_projects"][0]["id"] = project_data["parent"]["id"]
85+
project_repos["all_projects"][0]["name"] = project_data["parent"]["full_name"]
86+
project_repos["all_projects"][0]["url"] = project_data["parent"]["html_url"]
87+
project_repos["all_bes_repos"][0]["id"] = project_data["id"]
88+
project_repos["all_bes_repos"][0]["name"] = project_data["full_name"]
89+
project_repos["all_bes_repos"][0]["url"] = project_data["html_url"]
90+
return project_repos
91+
92+
def write_tags(self, bes_id):
93+
url = 'https://api.github.com/repos/Be-Secure/Be-Secure/issues/'+str(bes_id)+'/labels'
94+
tags_json_data = urlopen(url)
95+
tags_dict = json.loads(tags_json_data.read())
96+
tags = []
97+
for i in range(len(tags_dict)):
98+
tags.append(tags_dict[i]["name"])
99+
return tags
100+
101+
def write_languages(self,name):
102+
raw_data = urlopen("https://api.github.com/repos/Be-Secure/"+name+"/languages")
103+
data = json.loads(raw_data.read())
104+
return data
105+
106+
def write_to_ossp_master(self, f, ossp_master_json, data, overwrite: bool):
107+
if overwrite:
108+
for i in range(len(ossp_master_json["items"])):
109+
if ossp_master_json["items"][i]["id"] == self.id:
110+
ossp_master_json["items"][i] = data
111+
break
112+
else:
113+
ossp_master_json["items"].append(data)
114+
f.seek(0)
115+
f.write(json.dumps(ossp_master_json, indent=4))
116+
f.truncate()
117+
118+
119+
120+
def GenerateOsspMaster(self, overwrite: bool):
121+
self.check_issue_exists(self.id)
122+
self.check_repo_exists(self.name)
123+
self.check_issue_related_to_project()
124+
osspoi_dir = os.environ['OSSPOI_DIR']
125+
namespace = os.environ['GITHUB_ORG']
126+
token = os.environ['GITHUB_AUTH_TOKEN']
127+
write_flag = True
128+
f = open(osspoi_dir+"/OSSP-Master.json", "r+")
129+
ossp_master_json = json.load(f)
130+
if not overwrite:
131+
for i in range(len(ossp_master_json["items"])):
132+
if ossp_master_json["items"][i]["id"] == self.id:
133+
print("[bold red]Alert! [green]Entry for "+str(self.id)+"-"+self.name+" already present under OSSP-Master.json")
134+
write_flag = False
135+
break
136+
else:
137+
write_flag = True
138+
if write_flag:
139+
# proc = subprocess.Popen([f'curl -L -H "Accept: application/vnd.github+json" -H "Authorization: Bearer <YOUR-TOKEN>"-H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com//{namespace}/{self.name}'], stdout=subprocess.PIPE, shell=True)
140+
# (out, err) = proc.communicate()
141+
url_data = urlopen('https://api.github.com/repos/Be-Secure/'+self.name)
142+
project_data = json.loads(url_data.read())
143+
ossp_data = json.loads('{}')
144+
repo_keys = [ "id", "bes_tracking_id", "issue_url", "name", "full_name", "description", "bes_technology_stack", "watchers_count", "forks_count", "stargazers_count", "size", "open_issues", "created_at", "updated_at", "pushed_at", "git_url", "clone_url", "html_url", "homepage", "owner", "project_repos", "license", "language", "tags" ]
145+
for i in repo_keys:
146+
if i == "id" or i == "bes_tracking_id":
147+
ossp_data[i] = self.id
148+
elif i == "issue_url":
149+
ossp_data[i] = 'https://github.com/Be-Secure/Be-Secure/issues/'+str(self.id)
150+
elif i == "bes_technology_stack":
151+
ossp_data[i] = self.write_tech_stack(self.id)
152+
elif i == "project_repos":
153+
ossp_data[i] = self.write_project_repos_data(project_data)
154+
elif i == "tags":
155+
ossp_data[i] = self.write_tags(self.id)
156+
elif i == "language":
157+
ossp_data[i] = self.write_languages(self.name)
158+
else:
159+
ossp_data[i] = project_data[i]
160+
self.write_to_ossp_master(f, ossp_master_json, ossp_data, overwrite)
161+
f.close()
162+
163+
164+
165+
166+

0 commit comments

Comments
 (0)