Skip to content

Commit be86980

Browse files
committed
about to big refactor socketcli
1 parent 5e6c6bc commit be86980

File tree

6 files changed

+356
-54
lines changed

6 files changed

+356
-54
lines changed

socketsecurity/config.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
from dataclasses import dataclass
2+
from typing import List, Optional
3+
import argparse
4+
import os
5+
6+
@dataclass
7+
class CliConfig:
8+
api_token: str
9+
repo: Optional[str]
10+
branch: str = ""
11+
committer: Optional[List[str]] = None
12+
pr_number: str = "0"
13+
commit_message: Optional[str] = None
14+
default_branch: bool = False
15+
target_path: str = "./"
16+
scm: str = "api"
17+
sbom_file: Optional[str] = None
18+
commit_sha: str = ""
19+
generate_license: bool = False
20+
enable_debug: bool = False
21+
allow_unverified: bool = False
22+
enable_json: bool = False
23+
disable_overview: bool = False
24+
disable_security_issue: bool = False
25+
files: str = "[]"
26+
ignore_commit_files: bool = False
27+
disable_blocking: bool = False
28+
29+
@classmethod
30+
def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
31+
parser = create_argument_parser()
32+
args = parser.parse_args(args_list)
33+
34+
# Get API token from env or args
35+
api_token = os.getenv("SOCKET_SECURITY_API_KEY") or args.api_token
36+
37+
return cls(
38+
api_token=api_token,
39+
repo=args.repo,
40+
branch=args.branch,
41+
committer=args.committer,
42+
pr_number=args.pr_number,
43+
commit_message=args.commit_message,
44+
default_branch=args.default_branch,
45+
target_path=args.target_path,
46+
scm=args.scm,
47+
sbom_file=args.sbom_file,
48+
commit_sha=args.commit_sha,
49+
generate_license=args.generate_license,
50+
enable_debug=args.enable_debug,
51+
allow_unverified=args.allow_unverified,
52+
enable_json=args.enable_json,
53+
disable_overview=args.disable_overview,
54+
disable_security_issue=args.disable_security_issue,
55+
files=args.files,
56+
ignore_commit_files=args.ignore_commit_files,
57+
disable_blocking=args.disable_blocking
58+
)
59+
60+
def create_argument_parser() -> argparse.ArgumentParser:
61+
parser = argparse.ArgumentParser(
62+
prog="socketcli",
63+
description="Socket Security CLI"
64+
)
65+
66+
parser.add_argument(
67+
"--api-token",
68+
help="Socket Security API token (can also be set via SOCKET_SECURITY_API_KEY env var)",
69+
required=False
70+
)
71+
72+
parser.add_argument(
73+
"--repo",
74+
help="Repository name in owner/repo format",
75+
required=False
76+
)
77+
78+
parser.add_argument(
79+
"--branch",
80+
help="Branch name",
81+
default=""
82+
)
83+
84+
parser.add_argument(
85+
"--committer",
86+
help="Committer(s) to filter by",
87+
nargs="*"
88+
)
89+
90+
parser.add_argument(
91+
"--pr-number",
92+
help="Pull request number",
93+
default="0"
94+
)
95+
96+
parser.add_argument(
97+
"--commit-message",
98+
help="Commit message"
99+
)
100+
101+
# Boolean flags
102+
parser.add_argument(
103+
"--default-branch",
104+
action="store_true",
105+
help="Use default branch"
106+
)
107+
108+
parser.add_argument(
109+
"--generate-license",
110+
action="store_true",
111+
help="Generate license information"
112+
)
113+
114+
parser.add_argument(
115+
"--enable-debug",
116+
action="store_true",
117+
help="Enable debug logging"
118+
)
119+
120+
parser.add_argument(
121+
"--allow-unverified",
122+
action="store_true",
123+
help="Allow unverified packages"
124+
)
125+
126+
parser.add_argument(
127+
"--enable-json",
128+
action="store_true",
129+
help="Output in JSON format"
130+
)
131+
132+
parser.add_argument(
133+
"--disable-overview",
134+
action="store_true",
135+
help="Disable overview output"
136+
)
137+
138+
parser.add_argument(
139+
"--disable-security-issue",
140+
action="store_true",
141+
help="Disable security issue checks"
142+
)
143+
144+
parser.add_argument(
145+
"--ignore-commit-files",
146+
action="store_true",
147+
help="Ignore commit files"
148+
)
149+
150+
parser.add_argument(
151+
"--disable-blocking",
152+
action="store_true",
153+
help="Disable blocking mode"
154+
)
155+
156+
# Path and file related arguments
157+
parser.add_argument(
158+
"--target-path",
159+
default="./",
160+
help="Target path for analysis"
161+
)
162+
163+
parser.add_argument(
164+
"--scm",
165+
default="api",
166+
help="Source control management type"
167+
)
168+
169+
parser.add_argument(
170+
"--sbom-file",
171+
help="SBOM file path"
172+
)
173+
174+
parser.add_argument(
175+
"--commit-sha",
176+
default="",
177+
help="Commit SHA"
178+
)
179+
180+
parser.add_argument(
181+
"--files",
182+
default="[]",
183+
help="Files to analyze (JSON array string)"
184+
)
185+
186+
return parser

socketsecurity/core/__init__.py

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,6 @@ def do_request(
140140

141141

142142
class Core:
143-
# token: str
144-
# base_api_url: str
145-
# request_timeout: int
146-
# reports: list
147143

148144
client: CliClient
149145
config: SocketConfig
@@ -153,30 +149,6 @@ def __init__(self, config: SocketConfig, client: CliClient):
153149
self.client = client
154150
self.set_org_vars()
155151

156-
# def __init__(
157-
# self,
158-
# token: str,
159-
# base_api_url: str = None,
160-
# request_timeout: int = None,
161-
# enable_all_alerts: bool = False,
162-
# allow_unverified: bool = False
163-
# ):
164-
# global allow_unverified_ssl
165-
# allow_unverified_ssl = allow_unverified
166-
# self.token = token + ":"
167-
# encode_key(self.token)
168-
# self.socket_date_format = "%Y-%m-%dT%H:%M:%S.%fZ"
169-
# self.base_api_url = base_api_url
170-
# if self.base_api_url is not None:
171-
# Core.set_api_url(self.base_api_url)
172-
# self.request_timeout = request_timeout
173-
# if self.request_timeout is not None:
174-
# Core.set_timeout(self.request_timeout)
175-
# if enable_all_alerts:
176-
# global all_new_alerts
177-
# all_new_alerts = True
178-
# Core.set_org_vars()
179-
180152

181153
def set_org_vars(self) -> None:
182154
"""Sets the main shared configuration variables"""
@@ -231,26 +203,6 @@ def get_sbom_data(self, full_scan_id: str) -> list:
231203

232204
return results
233205

234-
# ORIGINAL - remove after verification
235-
# def get_sbom_data(self, full_scan_id: str) -> list:
236-
# path = f"orgs/{self.config.org_slug}/full-scans/{full_scan_id}"
237-
# response = self.client.request(path)
238-
# results = []
239-
# try:
240-
# data = response.json()
241-
# results = data.get("sbom_artifacts") or []
242-
# except Exception as error:
243-
# log.debug("Failed with old style full-scan API using new format")
244-
# log.debug(error)
245-
# data = response.text
246-
# data.strip('"')
247-
# data.strip()
248-
# for line in data.split("\n"):
249-
# if line != '"' and line != "" and line is not None:
250-
# item = json.loads(line)
251-
# results.append(item)
252-
# return results
253-
254206
def get_security_policy(self) -> dict:
255207
"""Get the Security policy and determine the effective Org security policy"""
256208
payload = [{"organization": self.config.org_id}]

socketsecurity/output.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from typing import Optional, Dict, Any
2+
import json
3+
import sys
4+
import logging
5+
from pathlib import Path
6+
from .core.classes import Diff, Issue
7+
8+
9+
class OutputHandler:
10+
blocking_disabled: bool
11+
logger: logging.Logger
12+
13+
def __init__(self, blocking_disabled: bool):
14+
self.blocking_disabled = blocking_disabled
15+
self.logger = logging.getLogger("socketcli")
16+
17+
def handle_output(self, diff_report: Diff, sbom_file_name: Optional[str] = None, json_output: bool = False) -> int:
18+
"""Main output handler that determines output format and returns exit code"""
19+
if json_output:
20+
self.output_console_json(diff_report, sbom_file_name)
21+
else:
22+
self.output_console_comments(diff_report, sbom_file_name)
23+
24+
self.save_sbom_file(diff_report, sbom_file_name)
25+
return 0 if self.report_pass(diff_report) else 1
26+
27+
def output_console_comments(self, diff_report: Diff, sbom_file_name: Optional[str] = None) -> None:
28+
"""Outputs formatted console comments"""
29+
if not diff_report.issues:
30+
self.logger.info("No issues found")
31+
return
32+
33+
for issue in diff_report.issues:
34+
self._output_issue(issue)
35+
36+
def output_console_json(self, diff_report: Diff, sbom_file_name: Optional[str] = None) -> None:
37+
"""Outputs JSON formatted results"""
38+
output = {
39+
"issues": [self._format_issue(issue) for issue in diff_report.issues],
40+
"pass": self.report_pass(diff_report)
41+
}
42+
if sbom_file_name:
43+
output["sbom_file"] = sbom_file_name
44+
45+
json.dump(output, sys.stdout, indent=2)
46+
sys.stdout.write("\n")
47+
48+
def report_pass(self, diff_report: Diff) -> bool:
49+
"""Determines if the report passes security checks"""
50+
if not diff_report.issues:
51+
return True
52+
53+
if self.blocking_disabled:
54+
return True
55+
56+
return not any(issue.blocking for issue in diff_report.issues)
57+
58+
def save_sbom_file(self, diff_report: Diff, sbom_file_name: Optional[str] = None) -> None:
59+
"""Saves SBOM file if filename is provided"""
60+
if not sbom_file_name or not diff_report.sbom:
61+
return
62+
63+
sbom_path = Path(sbom_file_name)
64+
sbom_path.parent.mkdir(parents=True, exist_ok=True)
65+
66+
with open(sbom_path, "w") as f:
67+
json.dump(diff_report.sbom, f, indent=2)
68+
69+
def _output_issue(self, issue: Issue) -> None:
70+
"""Helper method to format and output a single issue"""
71+
severity = issue.severity.upper() if issue.severity else "UNKNOWN"
72+
status = "🚫 Blocking" if issue.blocking else "⚠️ Warning"
73+
74+
self.logger.warning(f"\n{status} - Severity: {severity}")
75+
self.logger.warning(f"Title: {issue.title}")
76+
if issue.description:
77+
self.logger.warning(f"Description: {issue.description}")
78+
if issue.recommendation:
79+
self.logger.warning(f"Recommendation: {issue.recommendation}")
80+
81+
def _format_issue(self, issue: Issue) -> Dict[str, Any]:
82+
"""Helper method to format an issue for JSON output"""
83+
return {
84+
"title": issue.title,
85+
"description": issue.description,
86+
"severity": issue.severity,
87+
"blocking": issue.blocking,
88+
"recommendation": issue.recommendation
89+
}

socketsecurity/socketcli.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import argparse
22
import json
33

4-
import socketsecurity.core
54
from socketsecurity.core import Core, __version__
65
from socketsecurity.logging import initialize_logging, set_debug_mode
76
from socketsecurity.core.classes import FullScanParams, Diff, Package, Issue
@@ -11,13 +10,8 @@
1110
from git import InvalidGitRepositoryError, NoSuchPathError
1211
import os
1312
import sys
14-
import logging
1513

1614
socket_logger, cli_logger = initialize_logging()
17-
18-
log_format = "%(asctime)s: %(message)s"
19-
logging.basicConfig(level=logging.INFO, format=log_format)
20-
socketsecurity.core.log.setLevel(level=logging.INFO)
2115
log = cli_logger
2216
blocking_disabled = False
2317

0 commit comments

Comments
 (0)