You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

sym-cli

Package Overview
Dependencies
Maintainers
1
Versions
176
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sym-cli - pypi Package Compare versions

Comparing version
0.5.0
to
0.5.1
+1
-1
PKG-INFO
Metadata-Version: 2.1
Name: sym-cli
Version: 0.5.0
Version: 0.5.1
Summary: Sym's Official CLI for Users

@@ -5,0 +5,0 @@ Home-page: https://symops.com/

[tool.poetry]
name = "sym-cli"
version = "0.5.0"
version = "0.5.1"
description = "Sym's Official CLI for Users"

@@ -5,0 +5,0 @@ authors = ["SymOps, Inc. <pypi@symops.io>"]

@@ -34,13 +34,15 @@ import json

def boto_client(saml_client, service):
# For the AwsConfig SAML Client, we want to continue to use
# the boto session that has the aws profile name configured in it
# there could be more better ways to do this if necessary in the future
if hasattr(saml_client, "boto_session"):
return saml_client.boto_session.client(service)
creds = saml_client.get_creds()
if access_key_id := creds.get("AWS_ACCESS_KEY_ID"):
return boto3.client(
service,
config=BotoConfig(region_name=get_region(saml_client, creds)),
aws_access_key_id=access_key_id,
aws_secret_access_key=creds["AWS_SECRET_ACCESS_KEY"],
aws_session_token=creds.get("AWS_SESSION_TOKEN"),
)
# If there is no access key id, then assume that the boto3 default session is set up
return boto3.client(service)
return boto3.client(
service,
region_name=get_region(saml_client, creds),
aws_access_key_id=creds["AWS_ACCESS_KEY_ID"],
aws_secret_access_key=creds["AWS_SECRET_ACCESS_KEY"],
aws_session_token=creds.get("AWS_SESSION_TOKEN"),
)

@@ -47,0 +49,0 @@

@@ -7,3 +7,3 @@ import os

from boto3 import setup_default_session
from boto3.session import Session
from sym.shared.cli.helpers.contexts import push_env

@@ -32,8 +32,8 @@ from sym.shared.cli.helpers.keywords_to_options import Argument

options: "GlobalOptions"
boto_session: Session
def __init__(self, resource: str, *, options: "GlobalOptions") -> None:
super().__init__(resource, options=options)
# Make the default session use our AWS profile so we don't need to manage sessions in
# whatever other call chains there are to get AWS creds
setup_default_session(profile_name=resource)
self.raise_if_invalid()
self.boto_session = Session(profile_name=self.resource)

@@ -71,3 +71,8 @@ @classmethod

def get_creds(self):
return {}
creds = self.boto_session.get_credentials().get_frozen_credentials()
return {
"AWS_ACCESS_KEY_ID": creds.access_key,
"AWS_SECRET_ACCESS_KEY": creds.secret_key,
"AWS_SESSION_TOKEN": creds.token,
}

@@ -74,0 +79,0 @@ @intercept_errors()

@@ -1,1 +0,1 @@

__version__ = '0.5.0'
__version__ = '0.5.1'
import json
import os
from contextlib import ExitStack
from pathlib import Path
from typing import Iterator
from unittest.mock import MagicMock, patch
import pytest
import responses
from freezegun import freeze_time
from semver import VersionInfo
from sym.shared.cli.helpers.updater import SymUpdater
CURRENT_ISH_VERSION = VersionInfo.parse("0.2.7")
@pytest.fixture
def time_travel() -> Iterator:
with patch("yaml.safe_dump"): # YAML can't serialize FakeDatetimes
with freeze_time() as time:
yield time
@pytest.fixture
def pypi_response():
def responder(name) -> dict:
return json.load((Path(__file__).parent / "responses" / f"{name}.json").open())
return responder
@pytest.fixture
def http_mock(pypi_response) -> Iterator:
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
if os.getenv("CI"):
rsps.add_passthru("http") # make real requests on CI
else:
rsps.add(
responses.GET,
"https://pypi.org/pypi/sym-cli/json",
json=pypi_response("sym-cli"),
)
rsps.add(
responses.GET,
f"https://pypi.org/pypi/sym-cli/{CURRENT_ISH_VERSION}/json",
json=pypi_response("sym-cli-0.2.7"),
)
yield rsps
@pytest.fixture
def updater(sandbox, http_mock) -> Iterator[SymUpdater]:
with ExitStack() as stack:
stack.enter_context(sandbox.push_home())
stack.enter_context(sandbox.push_xdg_config_home())
stack.enter_context(sandbox.push_exec_path())
updater = MagicMock(wraps=SymUpdater)()
updater._env_is_local = lambda: False
yield updater
@pytest.fixture
def other_updater(sandbox, updater) -> SymUpdater:
updater.dir = sandbox.create_dir("my-sym-cli")
return updater
@pytest.fixture
def sitepackage_updater(sandbox, updater) -> SymUpdater:
root = Path() / "foo"
sandbox.create_binary(root / "bin" / "pip")
updater.dir = sandbox.create_dir(root / "lib" / "python3.8" / "site-packages")
return updater
@pytest.fixture
def pipx_updater(sandbox, updater) -> SymUpdater:
sandbox.create_binary("bin/pipx")
updater.is_local = MagicMock(return_value=False)
updater.dir = (
sandbox.path
/ "home"
/ ".local"
/ "pipx"
/ "venvs"
/ "sym-cli"
/ "lib"
/ "python3.8"
/ "site-packages"
)
return updater
@pytest.fixture
def brew_updater(sandbox, updater) -> SymUpdater:
sandbox.create_binary("bin/brew")
sandbox.create_binary("bin/git")
updater.is_local = MagicMock(return_value=False)
updater.dir = (
Path("/")
/ "usr"
/ "local"
/ "Cellar"
/ "sym-cli"
/ "0.0.0"
/ "libexec"
/ "lib"
/ "python3.8"
/ "site-packages"
)
return updater

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

import datetime
import os
import re
from pathlib import Path
from unittest.mock import MagicMock
import pytest
from semver import VersionInfo
from sym.shared.cli.helpers.updater import FAIL_LOG_PATH
from sym.cli.helpers.config import Config, SymConfigFile
V1 = VersionInfo.parse("0.0.1")
def test_pipx_path(pipx_updater):
assert pipx_updater.is_pipx() == True
def test_sitepackage_path(sitepackage_updater):
assert sitepackage_updater.is_sitepackage() == True
def test_brew_path(brew_updater):
assert brew_updater.is_brew() == True
def test_local_if_v0(updater):
updater.dir = Path("/foo/bar")
assert updater.is_local() == True
updater.get_current_version = MagicMock(return_value=V1)
assert updater.is_local() == False
def test_default_path(updater):
assert (updater.dir / "sym" / "cli").exists() == True
def test_noop_if_local(updater):
assert updater.is_local() == True
assert updater.should_check() == False
def test_no_manual_if_local(updater):
updater.update = MagicMock()
updater.manual_update()
updater.update.assert_not_called()
def test_checks_first_time(pipx_updater):
assert pipx_updater.should_check() == True
def test_checks_first_time_no_autoupdate(pipx_updater):
Config.instance()["autoupdate"] = "false"
assert pipx_updater.should_check() == False
def test_no_check_second_time(pipx_updater):
assert pipx_updater.should_check() == True
assert pipx_updater.should_check() == False
def test_check_after_a_day(pipx_updater, time_travel):
assert pipx_updater.should_check() == True
time_travel.tick(delta=datetime.timedelta(days=1))
assert pipx_updater.should_check() == True
def test_get_version(updater):
assert updater.get_latest_version() is not None
assert updater.get_latest_version().major == 0
assert updater.get_latest_version().minor >= 2
def test_needs_update(pipx_updater):
pipx_updater.get_current_version = MagicMock(return_value=V1)
assert pipx_updater.needs_update() is True
def test_needs_no_update(pipx_updater):
pipx_updater.get_current_version = MagicMock(return_value=V1)
pipx_updater.get_latest_version = MagicMock(return_value=V1)
assert pipx_updater.needs_update() is False
def test_failed_fetch(pipx_updater):
pipx_updater.get_latest_version = MagicMock(return_value=None)
assert pipx_updater.needs_update() is False
def test_update_sitepackage(sitepackage_updater, capture_command):
with capture_command():
assert sitepackage_updater._update() == True
capture_command.assert_command(re.compile(r"pip install -U sym-cli"))
def test_update_sitepackage_failed(sitepackage_updater, capture_command):
capture_command.register_output("pip", "", exit_code=1)
with capture_command():
assert sitepackage_updater._update() == False
def test_update_pipx(pipx_updater, capture_command):
with capture_command():
assert pipx_updater._update() == True
capture_command.assert_command(["pipx", "upgrade", "sym-cli"])
def test_update_pipx_failed(pipx_updater, capture_command):
capture_command.register_output("pipx", "", exit_code=1)
with capture_command():
assert pipx_updater._update() == False
def test_update_brew(brew_updater, capture_command):
capture_command.register_output(r"brew --repo", "/foo/bar")
with capture_command():
brew_updater.latest_version = V1
assert brew_updater._update() == True
capture_command.assert_command(
["brew", "--repo", "symopsio/tap"],
["git", "pull", "origin", "master"],
["brew", "install", "sym@0.0.1"],
["brew", "link", "sym@0.0.1"],
)
def test_update_brew_failed(brew_updater, capture_command):
capture_command.register_output("brew", "", exit_code=1)
with capture_command():
assert brew_updater._update() == False
def test_update_brew_failed_debug(brew_updater, capture_command, capsys):
capture_command.register_output("brew", "an error!", exit_code=1)
with capture_command():
brew_updater.debug = True
assert brew_updater._update() == False
assert "an error!" in capsys.readouterr().err
def test_update_brew_timeout(brew_updater, capture_command, capsys):
capture_command.register_output(r"brew --repo", "/foo/bar")
capture_command.register_output(r"brew install", "something slow...", timeout=True)
with capture_command():
brew_updater.latest_version = V1
brew_updater.debug = True
assert brew_updater._update() == False
capture_command.assert_command(
["brew", "--repo", "symopsio/tap"],
["git", "pull", "origin", "master"],
["brew", "install", "sym@0.0.1"],
["brew", "link", "sym"],
)
config_file = SymConfigFile(file_name=FAIL_LOG_PATH, uid_scope=False)
assert str(config_file.path) in capsys.readouterr().err
assert "something slow..." in config_file.read()
@pytest.mark.skipif(not os.getenv("CI"), reason="skipping real requests locally")
def test_update_other(other_updater):
version = other_updater.get_latest_version()
assert other_updater._update() == True
assert (other_updater.dir / "sym").exists() == True
assert str(version) in (other_updater.dir / "sym" / "cli" / "version.py").read_text()