Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Socket Security CLI

The Socket Security CLI was created to enable integrations with other tools like GitHub Actions, GitLab, BitBucket, local use cases and more. The tool will get the head scan for the provided repo from Socket, create a new one, and then report any new alerts detected. If there are new alerts against the Socket security policy it'll exit with a non-Zero exit code.
The Socket Security CLI was created to enable integrations with other tools like GitHub Actions, GitLab, BitBucket, local use cases and more. The tool will get the head scan for the provided repo from Socket, create a new one, and then report any new alerts detected. If there are new alerts with blocking actions it'll exit with a non-Zero exit code.

## Quick Start

Expand Down
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"

[project]
name = "socketsecurity"
version = "2.2.40"
version = "2.2.43"
requires-python = ">= 3.10"
license = {"file" = "LICENSE"}
dependencies = [
Expand Down Expand Up @@ -160,3 +160,8 @@ docstring-code-line-length = "dynamic"

[tool.hatch.build.targets.wheel]
include = ["socketsecurity", "LICENSE"]

[dependency-groups]
dev = [
"pre-commit>=4.3.0",
]
2 changes: 1 addition & 1 deletion socketsecurity/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__author__ = 'socket.dev'
__version__ = '2.2.40'
__version__ = '2.2.43'
USER_AGENT = f'SocketPythonCLI/{__version__}'
17 changes: 3 additions & 14 deletions socketsecurity/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from socketdev.fullscans import FullScanParams, SocketArtifact
from socketdev.org import Organization
from socketdev.repos import RepositoryInfo
from socketdev.settings import SecurityPolicyRule
import copy
from socketsecurity import __version__, USER_AGENT
from socketsecurity.core.classes import (
Expand Down Expand Up @@ -82,8 +81,6 @@ def set_org_vars(self) -> None:
self.config.full_scan_path = f"{base_path}/full-scans"
self.config.repository_path = f"{base_path}/repos"

self.config.security_policy = self.get_security_policy()

def get_org_id_slug(self) -> Tuple[str, str]:
"""Gets the Org ID and Org Slug for the API Token."""
response = self.sdk.org.get(use_types=True)
Expand Down Expand Up @@ -112,16 +109,7 @@ def get_sbom_data_list(self, artifacts_dict: Dict[str, SocketArtifact]) -> list[
"""Converts artifacts dictionary to a list."""
return list(artifacts_dict.values())

def get_security_policy(self) -> Dict[str, SecurityPolicyRule]:
"""Gets the organization's security policy."""
response = self.sdk.settings.get(self.config.org_slug, use_types=True)

if not response.success:
log.error(f"Failed to get security policy: {response.status}")
log.error(response.message)
raise Exception(f"Failed to get security policy: {response.status}, message: {response.message}")

return response.securityPolicyRules

def create_sbom_output(self, diff: Diff) -> dict:
"""Creates CycloneDX output for a given diff."""
Expand Down Expand Up @@ -1317,8 +1305,9 @@ def add_package_alerts_to_collection(self, package: Package, alerts_collection:
url=package.url
)

if alert.type in self.config.security_policy:
action = self.config.security_policy[alert.type]['action']
# Use action from API (from security policy, label policy, triage, etc.)
if 'action' in alert_item and alert_item['action']:
action = alert_item['action']
setattr(issue_alert, action, True)

if issue_alert.key not in alerts_collection:
Expand Down
6 changes: 3 additions & 3 deletions socketsecurity/core/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def security_comment_template(diff: Diff, config=None) -> str:
> **❗️ Caution**
> **Review the following alerts detected in dependencies.**
>
> According to your organization's Security Policy, you **must** resolve all **"Block"** alerts before proceeding. It's recommended to resolve **"Warn"** alerts too.
> According to your organization's policies, you **must** resolve all **"Block"** alerts before proceeding. It's recommended to resolve **"Warn"** alerts too.
> Learn more about [Socket for GitHub](https://socket.dev?utm_medium=gh).

<!-- start-socket-updated-alerts-table -->
Expand Down Expand Up @@ -622,7 +622,7 @@ def create_acceptable_risk(md: MdUtils, ignore_commands: list) -> MdUtils:
@staticmethod
def create_security_alert_table(diff: Diff, md: MdUtils) -> tuple[MdUtils, list, dict]:
"""
Creates the detected issues table based on the Security Policy
Creates the detected issues table based on alert actions from the API
:param diff: Diff - Diff report with the detected issues
:param md: MdUtils - Main markdown variable
:return:
Expand Down Expand Up @@ -794,7 +794,7 @@ def create_purl_link(details: Purl) -> str:
@staticmethod
def create_console_security_alert_table(diff: Diff) -> PrettyTable:
"""
Creates the detected issues table based on the Security Policy
Creates the detected issues table based on alert actions from the API
:param diff: Diff - Diff report with the detected issues
:return:
"""
Expand Down
8 changes: 0 additions & 8 deletions socketsecurity/core/socket_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class SocketConfig:
org_slug: Optional[str] = None
full_scan_path: Optional[str] = None
repository_path: Optional[str] = None
security_policy: Dict = None
repo_visibility: Optional[str] = 'private'
all_issues: Optional['AllIssues'] = None
excluded_dirs: Set[str] = field(default_factory=lambda: default_exclude_dirs)
Expand All @@ -42,10 +41,6 @@ def __post_init__(self):

self._validate_api_url(self.api_url)

# Initialize empty dict for security policy if None
if self.security_policy is None:
self.security_policy = {}

# Initialize AllIssues if None
if self.all_issues is None:
self.all_issues = AllIssues()
Expand All @@ -70,6 +65,3 @@ def update_org_details(self, org_id: str, org_slug: str) -> None:
self.full_scan_path = f"{base_path}/full-scans"
self.repository_path = f"{base_path}/repos"

def update_security_policy(self, policy: Dict) -> None:
"""Update security policy"""
self.security_policy = policy
12 changes: 1 addition & 11 deletions tests/core/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
StreamDiffResponse,
)
from socketdev.repos import GetRepoResponse
from socketdev.settings import OrgSecurityPolicyResponse


@pytest.fixture
Expand Down Expand Up @@ -88,14 +87,7 @@ def stream_diff_response(data_dir, load_json):
})


@pytest.fixture
def security_policy(data_dir, load_json):
json_data = load_json(data_dir / "settings" / "security-policy.json")
return OrgSecurityPolicyResponse.from_dict({
"success": json_data["success"],
"status": json_data["status"],
"securityPolicyRules": json_data["securityPolicyRules"]
})



@pytest.fixture
Expand Down Expand Up @@ -146,13 +138,11 @@ def mock_sdk_with_responses(
new_scan_metadata,
new_scan_stream,
stream_diff_response,
security_policy,
create_full_scan_response,
):
sdk = mock_socket_sdk.return_value

# Simple returns
sdk.settings.get.return_value = security_policy
sdk.fullscans.post.return_value = create_full_scan_response

# Argument-based returns
Expand Down
33 changes: 2 additions & 31 deletions tests/core/test_package_and_alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ def mock_sdk(self):
}
})

# Set up settings.get() to return empty security policy
# Set up settings.get() to return empty response
mock.settings = Mock()
settings_response = Mock()
settings_response.success = True
settings_response.security_policy = {}
mock.settings.get = Mock(return_value=settings_response)

return mock
Expand All @@ -48,7 +47,6 @@ def config(self):
api_key="test-key",
allow_unverified_ssl=False
)
config.security_policy = {} # Initialize with empty dict
return config

@pytest.fixture
Expand Down Expand Up @@ -135,34 +133,7 @@ def test_add_package_alerts_basic(self, core):
assert alert.type == "networkAccess"
assert alert.severity == "high"

def test_add_package_alerts_with_security_policy(self, core):
"""Test alerts are properly tagged based on security policy"""
# Mock security policy in config
core.config.security_policy = {
"networkAccess": {"action": "error"}
}

package = Package(
id="pkg:npm/test@1.0.0",
name="test",
version="1.0.0",
type="npm",
alerts=[{
"type": "networkAccess",
"key": "test-alert",
"severity": "high"
}],
topLevelAncestors=[]
)

alerts_collection = {}
packages = {package.id: package}

result = core.add_package_alerts_to_collection(package, alerts_collection, packages)

assert len(result) == 1
alert = result["test-alert"][0]
assert alert.error is True


def test_get_capabilities_for_added_packages(self, core):
"""Test capability extraction from package alerts"""
Expand Down
13 changes: 1 addition & 12 deletions tests/unit/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ def test_config_default_values():

assert config.api_key == "test_key"
assert config.api_url == "https://api.socket.dev/v0"
assert config.timeout == 30
assert config.timeout == 1200
assert config.allow_unverified_ssl is False
assert config.org_id is None
assert config.org_slug is None
assert config.full_scan_path is None
assert config.repository_path is None
assert config.security_policy == {}

def test_config_custom_values():
"""Test that config accepts custom values"""
Expand Down Expand Up @@ -67,14 +66,4 @@ def test_config_update_org_details():
assert config.full_scan_path == "orgs/test-org/full-scans"
assert config.repository_path == "orgs/test-org/repos"

def test_config_update_security_policy():
"""Test updating security policy"""
config = SocketConfig(api_key="test_key")

test_policy = {
"rule1": {"action": "block"},
"rule2": {"action": "warn"}
}

config.security_policy = test_policy
assert config.security_policy == test_policy
22 changes: 13 additions & 9 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading