Skip to content

Commit 5abca11

Browse files
committed
sdk integrated and tested, some pre-sdk tests need removal
1 parent aefa447 commit 5abca11

File tree

12 files changed

+487
-315
lines changed

12 files changed

+487
-315
lines changed

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ dependencies = [
1313
'argparse',
1414
'GitPython',
1515
'packaging'
16+
'python-dotenv', # Add this
17+
'socket-sdk-python @ file:///${PROJECT_ROOT}/../socket-sdk-python'
1618
]
1719
readme = "README.md"
1820
description = "Socket Security CLI for CI/CD"

socketsecurity/config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from dataclasses import dataclass
2-
from typing import List, Optional
31
import argparse
42
import os
3+
from dataclasses import dataclass
4+
from typing import List, Optional
5+
56

67
@dataclass
78
class CliConfig:

socketsecurity/core/__init__.py

Lines changed: 48 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from glob import glob
77
from pathlib import PurePath
88
from urllib.parse import urlencode
9+
from socketdev import socketdev
10+
from typing import Tuple, Dict
911

1012
import requests
1113

@@ -23,8 +25,9 @@
2325
from socketsecurity.core.licenses import Licenses
2426

2527
from .cli_client import CliClient
26-
from .config import SocketConfig
28+
from .socket_config import SocketConfig
2729
from .utils import socket_globs
30+
from socketdev.org import Orgs, Organization
2831

2932
__all__ = [
3033
"Core",
@@ -139,12 +142,11 @@ def do_request(
139142

140143
class Core:
141144

142-
client: CliClient
143145
config: SocketConfig
144-
145-
def __init__(self, config: SocketConfig, client: CliClient):
146+
sdk: socketdev
147+
def __init__(self, config: SocketConfig, sdk: socketdev):
146148
self.config = config
147-
self.client = client
149+
self.sdk = sdk
148150
self.set_org_vars()
149151

150152

@@ -165,73 +167,38 @@ def set_org_vars(self) -> None:
165167
# Get security policy AFTER org_id is updated
166168
self.config.security_policy = self.get_security_policy()
167169

168-
def get_org_id_slug(self) -> tuple[str, str]:
170+
def get_org_id_slug(self) -> Tuple[str, str]:
169171
"""Gets the Org ID and Org Slug for the API Token"""
170-
path = "organizations"
171-
response = self.client.request(path)
172-
data = response.json()
173-
organizations = data.get("organizations")
174-
new_org_id = None
175-
new_org_slug = None
172+
response = self.sdk.org.get()
173+
organizations: Dict[str, Organization] = response.get("organizations", {})
174+
176175
if len(organizations) == 1:
177-
for key in organizations:
178-
new_org_id = key
179-
new_org_slug = organizations[key].get('slug')
180-
return new_org_id, new_org_slug
176+
org_id = next(iter(organizations)) # More Pythonic way to get first key
177+
return org_id, organizations[org_id]['slug']
178+
return None, None
181179

182180
def get_sbom_data(self, full_scan_id: str) -> list:
183181
"""
184182
Return the list of SBOM artifacts for a full scan
185183
"""
186-
path = f"orgs/{self.config.org_slug}/full-scans/{full_scan_id}"
187-
response = self.client.request(path)
188-
results = []
189184

190-
if response.status_code != 200:
185+
response = self.sdk.fullscans.stream(self.config.org_slug, full_scan_id)
186+
if(response.get("success", False) == False):
191187
log.debug(f"Failed to get SBOM data for full-scan {full_scan_id}")
192-
log.debug(response.text)
188+
log.debug(response.get("message", "No message"))
193189
return []
194-
data = response.text
195-
data.strip('"')
196-
data.strip()
197-
for line in data.split("\n"):
198-
if line != '"' and line != "" and line is not None:
199-
item = json.loads(line)
200-
results.append(item)
201190

202-
return results
191+
response.pop("success", None)
192+
response.pop("status", None)
193+
return response
203194

204195
def get_security_policy(self) -> dict:
205-
"""Get the Security policy and determine the effective Org security policy"""
206-
payload = [{"organization": self.config.org_id}]
207-
208-
response = self.client.request(
209-
path="settings",
210-
method="POST",
211-
payload=json.dumps(payload)
212-
)
196+
"""Get the Security policy"""
213197

214-
data = response.json()
215-
defaults = data.get("defaults", {})
216-
default_rules = defaults.get("issueRules", {})
217-
entries = data.get("entries", [])
198+
response = self.sdk.settings.get(self.config.org_slug)
218199

219-
org_rules = {}
220-
221-
# Get organization-specific rules
222-
for org_set in entries:
223-
settings = org_set.get("settings")
224-
if settings:
225-
org_details = settings.get("organization", {})
226-
org_rules.update(org_details.get("issueRules", {}))
227-
228-
# Apply default rules where no org-specific rule exists
229-
for default in default_rules:
230-
if default not in org_rules:
231-
action = default_rules[default]["action"]
232-
org_rules[default] = {"action": action}
233-
234-
return org_rules
200+
data = response.get("securityPolicyRules", {})
201+
return data
235202

236203
@staticmethod
237204
def get_manifest_files(package: Package, packages: dict) -> str:
@@ -254,11 +221,15 @@ def get_manifest_files(package: Package, packages: dict) -> str:
254221
return manifest_files
255222

256223
def create_sbom_output(self, diff: Diff) -> dict:
257-
base_path = f"orgs/{self.config.org_slug}/export/cdx"
258-
path = f"{base_path}/{diff.id}"
259-
result = self.client.request(path=path)
260224
try:
261-
sbom = result.json()
225+
result = self.sdk.export.cdx_bom(self.config.org_slug, diff.id)
226+
if(result.get("success", False) == False):
227+
log.error(f"Failed to get CycloneDX Output for full-scan {diff.id}")
228+
log.error(result.get("message", "No message"))
229+
return {}
230+
231+
result.pop("success", None)
232+
return result
262233
except Exception as error:
263234
log.error(f"Unable to get CycloneDX Output for {diff.id}")
264235
log.error(error)
@@ -330,37 +301,18 @@ def create_full_scan(self, files: list, params: FullScanParams, workspace: str)
330301
:param workspace: str - Path of workspace
331302
:return:
332303
"""
333-
send_files = []
304+
334305
create_full_start = time.time()
335306
log.debug("Creating new full scan")
336-
for file in files:
337-
if platform.system() == "Windows":
338-
file = file.replace("\\", "/")
339-
if "/" in file:
340-
path, name = file.rsplit("/", 1)
341-
else:
342-
path = "."
343-
name = file
344-
full_path = f"{path}/{name}"
345-
if full_path.startswith(workspace):
346-
key = full_path[len(workspace):]
347-
else:
348-
key = full_path
349-
key = key.lstrip("/")
350-
key = key.lstrip("./")
351-
payload = (
352-
key,
353-
(
354-
name,
355-
open(full_path, 'rb')
356-
)
357-
)
358-
send_files.append(payload)
359-
query_params = urlencode(params.__dict__)
360-
full_uri = f"{self.config.full_scan_path}?{query_params}"
361-
response = self.client.request(full_uri, method="POST", files=send_files)
362-
results = response.json()
363-
full_scan = FullScan(**results)
307+
params.org_slug = self.config.org_slug
308+
res = self.sdk.fullscans.post(files, params)
309+
310+
# If the response is a string, it's an error message
311+
if isinstance(res, str):
312+
log.error(f"Error creating full scan: {res}")
313+
return FullScan()
314+
315+
full_scan = FullScan(**res)
364316
full_scan.sbom_artifacts = self.get_sbom_data(full_scan.id)
365317
create_full_end = time.time()
366318
total_time = create_full_end - create_full_start
@@ -380,35 +332,29 @@ def get_license_details(package: Package) -> Package:
380332
def get_head_scan_for_repo(self, repo_slug: str) -> str:
381333
"""Get the head scan ID for a repository"""
382334
print(f"\nGetting head scan for repo: {repo_slug}")
383-
repo_path = f"{self.config.repository_path}/{repo_slug}"
384-
print(f"Repository path: {repo_path}")
385335

386-
response = self.client.request(repo_path)
336+
response = self.sdk.repos.repo(self.config.org_slug, repo_slug)
387337
response_data = response.json()
388338
print(f"Raw API Response: {response_data}") # Debug raw response
389-
print(f"Response type: {type(response_data)}") # Debug response type
390339

391-
if "repository" in response_data:
392-
print(f"Repository data: {response_data['repository']}") # Debug repository data
393-
else:
394-
print("No 'repository' key in response data!")
340+
if not response_data or "repository" not in response_data:
341+
log.error("Failed to get repository data from API")
342+
return ""
395343

396344
repository = Repository(**response_data["repository"])
397345
print(f"Created repository object: {repository.__dict__}") # Debug final object
398346

399347
return repository.head_full_scan_id
400348

349+
# TODO: this is the same as get_sbom_data. AND IT CALLS GET_SBOM_DATA. huh?
401350
def get_full_scan(self, full_scan_id: str) -> FullScan:
402351
"""
403352
Get the specified full scan and return a FullScan object
404353
:param full_scan_id: str - ID of the full scan to pull
405354
:return:
406355
"""
407-
full_scan_url = f"{self.config.full_scan_path}/{full_scan_id}"
408-
response = self.client.request(full_scan_url)
409-
results = response.json()
356+
results = self.get_sbom_data(full_scan_id)
410357
full_scan = FullScan(**results)
411-
full_scan.sbom_artifacts = self.get_sbom_data(full_scan.id)
412358
return full_scan
413359

414360
def create_new_diff(self, path: str, params: FullScanParams, workspace: str, no_change: bool = False) -> Diff:

socketsecurity/core/cli_client.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import base64
2-
import requests
3-
from typing import Optional, Dict, Union, List
42
import logging
5-
from .config import SocketConfig
3+
from typing import Dict, List, Optional, Union
4+
5+
import requests
6+
7+
from .socket_config import SocketConfig
68
from .exceptions import APIFailure
79

810
logger = logging.getLogger("socketdev")

socketsecurity/core/config.py renamed to socketsecurity/core/socket_config.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from dataclasses import dataclass
2-
from typing import Optional, Dict
2+
from typing import Dict, Optional
33
from urllib.parse import urlparse
4+
45
from socketsecurity.core.issues import AllIssues
56

7+
68
@dataclass
79
class SocketConfig:
810
api_key: str

socketsecurity/socketcli.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import json
22
import sys
33

4+
from dotenv import load_dotenv
45
from git import InvalidGitRepositoryError, NoSuchPathError
6+
from socketdev import socketdev
57

68
from socketsecurity.config import CliConfig
79
from socketsecurity.core import Core
810
from socketsecurity.core.classes import Diff, FullScanParams
911
from socketsecurity.core.cli_client import CliClient
10-
from socketsecurity.core.config import SocketConfig
12+
from socketsecurity.core.socket_config import SocketConfig
1113
from socketsecurity.core.git_interface import Git
1214
from socketsecurity.core.logging import initialize_logging, set_debug_mode
1315
from socketsecurity.core.messages import Messages
@@ -16,6 +18,9 @@
1618

1719
socket_logger, log = initialize_logging()
1820

21+
load_dotenv()
22+
23+
1924
def cli():
2025
try:
2126
main_code()
@@ -40,6 +45,8 @@ def main_code():
4045
config = CliConfig.from_args()
4146
output_handler = OutputHandler(blocking_disabled=config.disable_blocking)
4247

48+
sdk = socketdev(token=config.api_token)
49+
4350
if config.enable_debug:
4451
set_debug_mode(True)
4552
log.debug("Debug logging enabled")
@@ -55,7 +62,7 @@ def main_code():
5562
allow_unverified_ssl=config.allow_unverified
5663
)
5764
client = CliClient(socket_config)
58-
core = Core(socket_config, client)
65+
core = Core(socket_config, client, sdk)
5966

6067
# Load files - files defaults to "[]" in CliConfig
6168
try:

tests/unit/test_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from unittest.mock import Mock, patch
33
import requests
44
from socketsecurity.core.cli_client import CliClient
5-
from socketsecurity.core.config import SocketConfig
5+
from socketsecurity.core.socket_config import SocketConfig
66
from socketsecurity.core.exceptions import APIFailure
77

88
@pytest.fixture

tests/unit/test_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import pytest
2-
from socketsecurity.core.config import SocketConfig
2+
from socketsecurity.core.socket_config import SocketConfig
33

44
def test_config_default_values():
55
"""Test that config initializes with correct default values"""

tests/unit/test_core.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
from unittest.mock import MagicMock, mock_open, patch
2+
13
import pytest
2-
from unittest.mock import mock_open, patch, MagicMock
4+
35
from socketsecurity.core import Core
4-
from socketsecurity.core.classes import Package
5-
from socketsecurity.core.classes import Purl
6-
from socketsecurity.core.classes import Diff
7-
from socketsecurity.core.classes import Issue
6+
from socketsecurity.core.classes import Diff, Issue, Package, Purl
7+
88

99
@pytest.fixture
1010
def sample_package():

0 commit comments

Comments
 (0)