Skip to content

Commit f68d3f0

Browse files
authored
Doug/add cli options (#8)
* Add options to disable dependency overview and security issues comments. * Added fix for if files is not specified * Added debug logging and moved to using a shared do_request * Fixed bug in the check of the GH variable name
1 parent 90d4ccc commit f68d3f0

File tree

8 files changed

+141
-184
lines changed

8 files changed

+141
-184
lines changed

README.md

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,34 @@ The Socket Security CLI was created to enable integrations with other tools like
55
## Usage
66

77
```` shell
8-
socketcli [-h] [--api_token API_TOKEN] [--repo REPO] [--branch BRANCH] [--committer COMMITTER] [--pr_number PR_NUMBER] [--commit_message COMMIT_MESSAGE] [--default_branch DEFAULT_BRANCH]
9-
[--target_path TARGET_PATH] [--mode {diff,new,license}] [--scm {api,github}] [--generate-license GENERATE_LICENSE]
8+
socketcli [-h] [--api_token API_TOKEN] [--repo REPO] [--branch BRANCH] [--committer COMMITTER] [--pr_number PR_NUMBER]
9+
[--commit_message COMMIT_MESSAGE] [--default_branch] [--target_path TARGET_PATH] [--scm {api,github,gitlab}] [--sbom-file SBOM_FILE]
10+
[--commit-sha COMMIT_SHA] [--generate-license GENERATE_LICENSE] [-v] [--enable-debug] [--enable-json] [--disable-overview]
11+
[--disable-security-issue] [--files FILES]
1012
````
1113

1214
If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
1315

1416

15-
| Parameter | Alternate Name | Required | Default | Description |
16-
|:-------------------|:---------------|:---------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------|
17-
| -h | --help | False | | Show the CLI help message |
18-
| --api_token | | False | | Provides the Socket API Token |
19-
| --repo | | True | | The string name in a git approved name for repositories. |
20-
| --branch | | False | | The string name in a git approved name for branches. |
21-
| --committer | | False | | The string name of the person doing the commit or running the CLI. Can be specified multiple times to have more than one committer |
22-
| --pr_number | | False | 0 | The integer for the PR or MR number |
23-
| --commit_message | | False | | The string for a commit message if there is one |
24-
| --default_branch | | False | False | If the flag is specified this will signal that this is the default branch. This needs to be enabled for a report to update Org Alerts and Org Dependencies |
25-
| --target_path | | False | ./ | This is the path to where the manifest files are location. The tool will recursively search for all supported manifest files |
26-
| --scm | | False | api | This is the mode that the tool is to run in. For local runs `api` would be the mode. Other options are `gitlab` and `github` |
27-
| --generate-license | | False | False | If this flag is specified it will generate a json file with the license per package and license text in the current working directory |
28-
| --version | -v | False | | Prints the version and exits |
29-
| --enable-debug | | False | False | Enables debug messaging for the CLI |
17+
| Parameter | Alternate Name | Required | Default | Description |
18+
|:-------------------------|:---------------|:---------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------|
19+
| -h | --help | False | | Show the CLI help message |
20+
| --api_token | | False | | Provides the Socket API Token |
21+
| --repo | | True | | The string name in a git approved name for repositories. |
22+
| --branch | | False | | The string name in a git approved name for branches. |
23+
| --committer | | False | | The string name of the person doing the commit or running the CLI. Can be specified multiple times to have more than one committer |
24+
| --pr_number | | False | 0 | The integer for the PR or MR number |
25+
| --commit_message | | False | | The string for a commit message if there is one |
26+
| --default_branch | | False | False | If the flag is specified this will signal that this is the default branch. This needs to be enabled for a report to update Org Alerts and Org Dependencies |
27+
| --target_path | | False | ./ | This is the path to where the manifest files are location. The tool will recursively search for all supported manifest files |
28+
| --scm | | False | api | This is the mode that the tool is to run in. For local runs `api` would be the mode. Other options are `gitlab` and `github` |
29+
| --generate-license | | False | False | If this flag is specified it will generate a json file with the license per package and license text in the current working directory |
30+
| --version | -v | False | | Prints the version and exits |
31+
| --enable-debug | | False | False | Enables debug messaging for the CLI |
32+
| --sbom-file | | False | False | Creates a JSON file with all dependencies and alerts |
33+
| --commit-sha | | False | | The commit hash for the commit |
34+
| --generate-license | | False | False | If enabled with `--sbom-file` will include license details |
35+
| --enable-json | | False | False | If enabled will change the console output format to JSON |
36+
| --disable-overview | | False | False | If enabled will disable Dependency Overview comments |
37+
| --disable-security-issue | | False | False | If enabled will disable Security Issue Comments |
38+
| --files | | False | | If provided in the format of `["file1", "file2"]` it will only look for those files and not glob the path |

scripts/build_container.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ echo $VERSION
66
if [ -z $BYPASS_PYPI_BUILD ] || [ $BYPASS_PYPI_BUILD -eq 0 ]; then
77
python -m build --wheel --sdist
88
twine upload dist/*$VERSION*
9-
sleep 180
9+
sleep 240
1010
fi
11+
1112
docker build --no-cache --build-arg CLI_VERSION=$VERSION --platform linux/amd64,linux/arm64 -t socketdev/cli:$VERSION . \
1213
&& docker build --no-cache --build-arg CLI_VERSION=$VERSION --platform linux/amd64,linux/arm64 -t socketdev/cli:latest . \
1314
&& docker push socketdev/cli:$VERSION \

socketsecurity/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
__author__ = 'socket.dev'
2-
__version__ = '0.0.86'
2+
__version__ = '0.0.95'

socketsecurity/core/__init__.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222
)
2323
import platform
2424
from glob import glob
25-
import fnmatch
2625
import time
2726

2827
__all__ = [
2928
"Core",
3029
"log",
31-
"__version__"
30+
"__version__",
31+
"do_request"
3232
]
3333

3434

@@ -63,27 +63,32 @@ def do_request(
6363
payload: [dict, str] = None,
6464
files: list = None,
6565
method: str = "GET",
66+
base_url: str = None,
6667
) -> requests.request:
6768
"""
6869
do_requests is the shared function for making HTTP calls
69-
70+
:param base_url:
7071
:param path: Required path for the request
7172
:param headers: Optional dictionary of headers. If not set will use a default set
7273
:param payload: Optional dictionary or string of the payload to pass
7374
:param files: Optional list of files to upload
7475
:param method: Optional method to use, defaults to GET
7576
:return:
7677
"""
77-
if encoded_key is None or encoded_key == "":
78-
raise APIKeyMissing
78+
79+
if base_url is not None:
80+
url = f"{base_url}/{path}"
81+
else:
82+
if encoded_key is None or encoded_key == "":
83+
raise APIKeyMissing
84+
url = f"{api_url}/{path}"
7985

8086
if headers is None:
8187
headers = {
8288
'Authorization': f"Basic {encoded_key}",
8389
'User-Agent': f'SocketPythonCLI/{__version__}',
8490
"accept": "application/json"
8591
}
86-
url = f"{api_url}/{path}"
8792
response = requests.request(
8893
method.upper(),
8994
url,
@@ -92,8 +97,8 @@ def do_request(
9297
files=files,
9398
timeout=timeout
9499
)
95-
output_headers = headers
96-
output_headers['Authorization'] = "Basic API_KEY_REDACTED"
100+
output_headers = headers.copy()
101+
output_headers['Authorization'] = "API_KEY_REDACTED"
97102
output = {
98103
"url": url,
99104
"headers": output_headers,
@@ -107,14 +112,7 @@ def do_request(
107112
if response.status_code <= 399:
108113
return response
109114
elif response.status_code == 400:
110-
print(f"url={url}")
111-
print(f"payload={payload}")
112-
print(f"files={files}")
113-
error = {
114-
"msg": "bad request",
115-
"error": response.text
116-
}
117-
raise APIFailure(error)
115+
raise APIFailure(output)
118116
elif response.status_code == 401:
119117
raise APIAccessDenied("Unauthorized")
120118
elif response.status_code == 403:
@@ -128,8 +126,10 @@ def do_request(
128126
else:
129127
msg = {
130128
"status_code": response.status_code,
129+
"UnexpectedError": "There was an unexpected error using the API",
131130
"error": response.text,
132-
"UnexpectedError": "There was an unexpected error using the API"
131+
"payload": payload,
132+
"url": url
133133
}
134134
raise APIFailure(msg)
135135

@@ -155,6 +155,11 @@ def __init__(self, token: str, base_api_url=None, request_timeout=None, enable_a
155155
all_new_alerts = True
156156
Core.set_org_vars()
157157

158+
@staticmethod
159+
def enable_debug_log(level: int):
160+
global log
161+
log.setLevel(level)
162+
158163
@staticmethod
159164
def set_org_vars() -> None:
160165
"""
@@ -394,7 +399,7 @@ def find_files(path: str, new_files: list = None) -> list:
394399
_, base_name = file.rsplit("/", 1)
395400
else:
396401
base_name = file
397-
if new_files is not None and base_name not in new_files:
402+
if new_files is not None and len(new_files) > 0 and base_name not in new_files:
398403
continue
399404
if platform.system() == "Windows":
400405
file = file.replace("\\", "/")

socketsecurity/core/github.py

Lines changed: 18 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import json
22
import os
3-
from socketsecurity.core import log
3+
from socketsecurity.core import log, do_request
44
import requests
5-
from socketsecurity.core.exceptions import *
65
from socketsecurity.core.classes import Comment
76
from socketsecurity.core.scm_comments import Comments
87
import sys
@@ -53,58 +52,15 @@
5352
is_default_branch = False
5453
else:
5554
is_default_branch = True
55+
if var_name != "gh_api_token":
56+
value = globals()[var_name] = os.getenv(env) or None
57+
log.debug(f"{env}={value}")
5658

57-
58-
def do_request(
59-
path: str,
60-
headers: dict = None,
61-
payload: [dict, str] = None,
62-
files: list = None,
63-
method: str = "GET",
64-
) -> dict:
65-
"""
66-
do_requests is the shared function for making HTTP calls
67-
68-
:param path: Required path for the request
69-
:param headers: Optional dictionary of headers. If not set will use a default set
70-
:param payload: Optional dictionary or string of the payload to pass
71-
:param files: Optional list of files to upload
72-
:param method: Optional method to use, defaults to GET
73-
:return:
74-
"""
75-
if gh_api_token is None or gh_api_token == "":
76-
raise APIKeyMissing
77-
78-
if headers is None:
79-
headers = {
80-
'Authorization': f"Bearer {gh_api_token}",
81-
'User-Agent': 'SocketPythonScript/0.0.1',
82-
"accept": "application/json"
83-
}
84-
url = f"{github_api_url}/{path}"
85-
response = requests.request(
86-
method.upper(),
87-
url,
88-
headers=headers,
89-
data=payload,
90-
files=files
91-
)
92-
if response.status_code <= 399:
93-
try:
94-
return response.json()
95-
except Exception as error:
96-
response = {
97-
"error": error,
98-
"response": response.text
99-
}
100-
return response
101-
else:
102-
msg = {
103-
"status_code": response.status_code,
104-
"UnexpectedError": "There was an unexpected error using the API",
105-
"error": response.text
106-
}
107-
raise APIFailure(msg)
59+
headers = {
60+
'Authorization': f"Bearer {gh_api_token}",
61+
'User-Agent': 'SocketPythonScript/0.0.1',
62+
"accept": "application/json"
63+
}
10864

10965

11066
class Github:
@@ -174,16 +130,22 @@ def add_socket_comments(
174130
existing_overview_comment = comments.get("overview")
175131
existing_security_comment = comments.get("security")
176132
if new_overview_comment:
133+
log.debug("New Dependency Overview comment")
177134
if existing_overview_comment is not None:
135+
log.debug("Previous version of Dependency Overview, updating")
178136
existing_overview_comment: Comment
179137
Github.update_comment(overview_comment, str(existing_overview_comment.id))
180138
else:
139+
log.debug("No previous version of Dependency Overview, posting")
181140
Github.post_comment(overview_comment)
182141
if new_security_comment:
142+
log.debug("New Security Issue Comment")
183143
if existing_security_comment is not None:
144+
log.debug("Previous version of Security Issue comment, updating")
184145
existing_security_comment: Comment
185146
Github.update_comment(security_comment, str(existing_security_comment.id))
186147
else:
148+
log.debug("No Previous version of Security Issue comment, posting")
187149
Github.post_comment(security_comment)
188150

189151
@staticmethod
@@ -194,7 +156,7 @@ def post_comment(body: str) -> None:
194156
"body": body
195157
}
196158
payload = json.dumps(payload)
197-
do_request(path, payload=payload, method="POST")
159+
do_request(path, payload=payload, method="POST", headers=headers, base_url=github_api_url)
198160

199161
@staticmethod
200162
def update_comment(body: str, comment_id: str) -> None:
@@ -204,7 +166,7 @@ def update_comment(body: str, comment_id: str) -> None:
204166
"body": body
205167
}
206168
payload = json.dumps(payload)
207-
do_request(path, payload=payload, method="PATCH")
169+
do_request(path, payload=payload, method="PATCH", headers=headers, base_url=github_api_url)
208170

209171
@staticmethod
210172
def write_new_env(name: str, content: str) -> None:
@@ -216,7 +178,7 @@ def write_new_env(name: str, content: str) -> None:
216178
@staticmethod
217179
def get_comments_for_pr(repo: str, pr: str) -> dict:
218180
path = f"repos/{github_repository_owner}/{repo}/issues/{pr}/comments"
219-
raw_comments = do_request(path)
181+
raw_comments = Comments.process_response(do_request(path, headers=headers, base_url=github_api_url))
220182
comments = {}
221183
if "error" not in raw_comments:
222184
for item in raw_comments:

0 commit comments

Comments
 (0)