suite-py 1.42.1__py3-none-any.whl → 1.43.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- suite_py/__version__.py +1 -1
- suite_py/cli.py +9 -3
- suite_py/lib/handler/captainhook_handler.py +1 -1
- suite_py/lib/handler/git_handler.py +39 -0
- suite_py/lib/handler/okta_handler.py +13 -9
- suite_py/lib/handler/pre_commit_handler.py +95 -0
- suite_py/lib/metrics.py +1 -1
- suite_py/lib/oauth.py +1 -1
- {suite_py-1.42.1.dist-info → suite_py-1.43.0.dist-info}/METADATA +5 -5
- {suite_py-1.42.1.dist-info → suite_py-1.43.0.dist-info}/RECORD +12 -11
- {suite_py-1.42.1.dist-info → suite_py-1.43.0.dist-info}/WHEEL +0 -0
- {suite_py-1.42.1.dist-info → suite_py-1.43.0.dist-info}/entry_points.txt +0 -0
suite_py/__version__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
__version__ = "1.
|
|
2
|
+
__version__ = "1.43.0"
|
suite_py/cli.py
CHANGED
|
@@ -49,6 +49,7 @@ from suite_py.lib.handler import git_handler as git
|
|
|
49
49
|
from suite_py.lib.handler import prompt_utils
|
|
50
50
|
from suite_py.lib.handler.captainhook_handler import CaptainHook
|
|
51
51
|
from suite_py.lib.handler.okta_handler import Okta
|
|
52
|
+
from suite_py.lib.handler.pre_commit_handler import PreCommit
|
|
52
53
|
from suite_py.lib.tokens import Tokens
|
|
53
54
|
|
|
54
55
|
# pylint: enable=wrong-import-position
|
|
@@ -107,9 +108,11 @@ def catch_exceptions(func):
|
|
|
107
108
|
def wrapper(*args, **kwargs):
|
|
108
109
|
try:
|
|
109
110
|
return func(*args, **kwargs)
|
|
110
|
-
except ClickException as e:
|
|
111
|
-
raise e
|
|
112
111
|
except Exception as e:
|
|
112
|
+
# Ignore all exception classes from the click module
|
|
113
|
+
if type(e).__module__.startswith("click."):
|
|
114
|
+
raise e
|
|
115
|
+
|
|
113
116
|
logger.debug("An error occured:", exc_info=True)
|
|
114
117
|
raise ClickException(f"{str(e)}. rerun with -v for more details") from e
|
|
115
118
|
|
|
@@ -168,7 +171,7 @@ def main(ctx, project, timeout, verbose):
|
|
|
168
171
|
if not skip_confirmation and not prompt_utils.ask_confirm(
|
|
169
172
|
f"Do you want to continue on project {os.path.basename(project)}?"
|
|
170
173
|
):
|
|
171
|
-
|
|
174
|
+
ctx.exit()
|
|
172
175
|
if timeout:
|
|
173
176
|
config.user["captainhook_timeout"] = timeout
|
|
174
177
|
|
|
@@ -193,6 +196,9 @@ def main(ctx, project, timeout, verbose):
|
|
|
193
196
|
or ctx.invoked_subcommand not in ALLOW_NO_HOME_SUBCOMMAND
|
|
194
197
|
):
|
|
195
198
|
os.chdir(os.path.join(config.user["projects_home"], ctx.obj.project))
|
|
199
|
+
# Warn on missing pre_commit hook
|
|
200
|
+
if ctx.invoked_subcommand not in ALLOW_NO_GIT_SUBCOMMAND:
|
|
201
|
+
ctx.obj.call(PreCommit).check_and_warn()
|
|
196
202
|
|
|
197
203
|
|
|
198
204
|
@main.result_callback()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
2
|
import requests
|
|
3
3
|
|
|
4
|
+
from suite_py.__version__ import __version__
|
|
4
5
|
from suite_py.lib.handler.github_handler import GithubHandler
|
|
5
6
|
from suite_py.lib.handler.okta_handler import Okta
|
|
6
|
-
from suite_py.__version__ import __version__
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class UnauthorizedError(Exception):
|
|
@@ -269,6 +269,45 @@ class GitHandler:
|
|
|
269
269
|
logger.error(f"Error during git reset on {self._repo}: {e}")
|
|
270
270
|
sys.exit(-1)
|
|
271
271
|
|
|
272
|
+
def get_git_config(self, option):
|
|
273
|
+
"""
|
|
274
|
+
Get git config value.
|
|
275
|
+
Git configs are very versitile and allow arbitrary string KV pairs to be stored,
|
|
276
|
+
support per-repo, or more complex conditional and global configurations,
|
|
277
|
+
making it the perfect place for us to store a lot of our configs.
|
|
278
|
+
"""
|
|
279
|
+
proc = subprocess.run(
|
|
280
|
+
["git", "config", "get", option],
|
|
281
|
+
cwd=self._path,
|
|
282
|
+
check=False,
|
|
283
|
+
capture_output=True,
|
|
284
|
+
)
|
|
285
|
+
if proc.returncode == 0:
|
|
286
|
+
return proc.stdout.decode().strip()
|
|
287
|
+
return None
|
|
288
|
+
|
|
289
|
+
def hooks_path(self):
|
|
290
|
+
"""
|
|
291
|
+
Get path to git-hooks
|
|
292
|
+
See: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks for more details
|
|
293
|
+
"""
|
|
294
|
+
try:
|
|
295
|
+
proc = subprocess.run(
|
|
296
|
+
["git", "rev-parse", "--git-path", "hooks"],
|
|
297
|
+
cwd=self._path,
|
|
298
|
+
check=True,
|
|
299
|
+
capture_output=True,
|
|
300
|
+
)
|
|
301
|
+
hooks = proc.stdout.decode().strip()
|
|
302
|
+
|
|
303
|
+
# Return absolute path to the hooks dir,
|
|
304
|
+
# since we overwrite the subprocesses cwd.
|
|
305
|
+
abs_path = os.path.join(self._path, hooks)
|
|
306
|
+
return abs_path
|
|
307
|
+
except CalledProcessError as e:
|
|
308
|
+
logger.error(f"Error getting hooks path {self._repo}: {e}")
|
|
309
|
+
sys.exit(-1)
|
|
310
|
+
|
|
272
311
|
|
|
273
312
|
def get_root_folder(directory):
|
|
274
313
|
return (
|
|
@@ -9,7 +9,9 @@ _SCOPE = "openid offline_access"
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class OktaError(Exception):
|
|
12
|
-
|
|
12
|
+
def __init__(self, message) -> None:
|
|
13
|
+
message = f"{message}\nTry relogging with 'suite-py login'"
|
|
14
|
+
super().__init__(message)
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
class Okta:
|
|
@@ -38,15 +40,17 @@ class Okta:
|
|
|
38
40
|
|
|
39
41
|
refresh_token = self._get_refresh_token()
|
|
40
42
|
if not isinstance(refresh_token, str):
|
|
41
|
-
raise OktaError(
|
|
42
|
-
|
|
43
|
+
raise OktaError("Invalid okta refresh token")
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
res = oauth.do_refresh_token(
|
|
47
|
+
self._config.okta["client_id"],
|
|
48
|
+
self._config.okta["base_url"],
|
|
49
|
+
_SCOPE,
|
|
50
|
+
refresh_token,
|
|
43
51
|
)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
self._config.okta["base_url"],
|
|
47
|
-
_SCOPE,
|
|
48
|
-
refresh_token,
|
|
49
|
-
)
|
|
52
|
+
except oauth.OAuthError as e:
|
|
53
|
+
raise OktaError(f"Error refreshing a token with okta: {e}") from e
|
|
50
54
|
|
|
51
55
|
return self._update_tokens(res)
|
|
52
56
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import yaml
|
|
3
|
+
|
|
4
|
+
from suite_py.lib import logger
|
|
5
|
+
from suite_py.lib.config import Config
|
|
6
|
+
from suite_py.lib.handler.git_handler import GitHandler
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PreCommit:
|
|
10
|
+
"""
|
|
11
|
+
Handler checking whether the user has the prima pre-commit hooks setup and print a warning if they are missing
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, project: str, config: Config):
|
|
15
|
+
self._git = GitHandler(project, config)
|
|
16
|
+
|
|
17
|
+
def check_and_warn(self):
|
|
18
|
+
if self.is_enabled() and not self.is_pre_commit_hooks_installed():
|
|
19
|
+
self.warn_missing_pre_commit_hook()
|
|
20
|
+
|
|
21
|
+
def is_pre_commit_hooks_installed(self):
|
|
22
|
+
"""
|
|
23
|
+
Apply some heuteristics to check whether the gitleaks pre-commit hook is installed.
|
|
24
|
+
This is extremely imperfect, and only supports direct calls in shell scripts.
|
|
25
|
+
More hooks, like husky should be added later
|
|
26
|
+
"""
|
|
27
|
+
return self.is_vanilla_hook_setup() or self.is_pre_commit_py_hook_setup()
|
|
28
|
+
|
|
29
|
+
def warn_missing_pre_commit_hook(self):
|
|
30
|
+
logger.warning(
|
|
31
|
+
"""
|
|
32
|
+
Looks like the current repo is missing the gitleaks pre-commit hook!
|
|
33
|
+
Please install it per the security guide:
|
|
34
|
+
https://www.notion.so/helloprima/Install-Gitleaks-pre-commit-hook-aaaa6beafafa4c298b537afcb52bb25a
|
|
35
|
+
|
|
36
|
+
If you have installed them already you can report the false positive to team-platform-shared-services (on Slack) and run:
|
|
37
|
+
git config suite-py.disable-pre-commit-warning true
|
|
38
|
+
to disable the check for this repo, or
|
|
39
|
+
git config --global suite-py.disable-pre-commit-warning true
|
|
40
|
+
to disable it globally
|
|
41
|
+
"""
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def is_vanilla_hook_setup(self):
|
|
45
|
+
"""
|
|
46
|
+
Check whether the gitleaks hook is setup as a regular bash script
|
|
47
|
+
"""
|
|
48
|
+
pre_commit_file = self.read_pre_commit_hook()
|
|
49
|
+
|
|
50
|
+
# Assume everything is a shell script.
|
|
51
|
+
# Technically you could use a binary, or even python code,
|
|
52
|
+
# But those are out of scope for us, and the user should just disable the warning themselves
|
|
53
|
+
lines = pre_commit_file.splitlines()
|
|
54
|
+
|
|
55
|
+
# Filter out lines that start with '#' since those are probably just comments.
|
|
56
|
+
without_comments = filter(lambda l: not l.strip().startswith("#"), lines)
|
|
57
|
+
|
|
58
|
+
return any("gitleaks" in line for line in without_comments)
|
|
59
|
+
|
|
60
|
+
def is_pre_commit_py_hook_setup(self):
|
|
61
|
+
"""
|
|
62
|
+
Check whether the gitleaks hook is setup with the pre-commit python framework
|
|
63
|
+
"""
|
|
64
|
+
# If the framework is not setup skip
|
|
65
|
+
if "pre-commit" not in self.read_pre_commit_hook():
|
|
66
|
+
logger.debug("pre-commit.com not installed, skipping config check")
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
config_path = os.path.join(self._git.get_path(), ".pre-commit-config.yaml")
|
|
70
|
+
try:
|
|
71
|
+
with open(config_path, encoding="utf-8") as f:
|
|
72
|
+
config = yaml.safe_load(f)
|
|
73
|
+
except FileNotFoundError:
|
|
74
|
+
logger.debug("pre-commit config file(%s) not found", config_path)
|
|
75
|
+
return False
|
|
76
|
+
except yaml.YAMLError:
|
|
77
|
+
logger.warning(".pre-commit-config.yaml file is invalid!", exc_info=True)
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
return any(
|
|
81
|
+
repo.get("repo", "") == "git@github.com:primait/security-hooks.git"
|
|
82
|
+
for repo in config.get("repos", [])
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def read_pre_commit_hook(self):
|
|
86
|
+
pre_commit_file_path = os.path.join(self._git.hooks_path(), "pre-commit")
|
|
87
|
+
logger.debug("Reading pre-commit script from %s", pre_commit_file_path)
|
|
88
|
+
try:
|
|
89
|
+
with open(pre_commit_file_path, encoding="utf-8") as f:
|
|
90
|
+
return f.read()
|
|
91
|
+
except FileNotFoundError:
|
|
92
|
+
return ""
|
|
93
|
+
|
|
94
|
+
def is_enabled(self):
|
|
95
|
+
return self._git.get_git_config("suite-py.disable-pre-commit-warning") != "true"
|
suite_py/lib/metrics.py
CHANGED
suite_py/lib/oauth.py
CHANGED
|
@@ -37,7 +37,7 @@ def retrieve_token(base_url, params) -> OAuthTokenResponse:
|
|
|
37
37
|
data = requests.post(url, headers=headers, data=params, timeout=30).json()
|
|
38
38
|
logger.debug(data)
|
|
39
39
|
|
|
40
|
-
if error := data.get("error_description", None):
|
|
40
|
+
if error := data.get("error_description", data.get("errorSummary", None)):
|
|
41
41
|
raise OAuthError(f"OAuth error: {error}")
|
|
42
42
|
|
|
43
43
|
return OAuthTokenResponse(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: suite-py
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.43.0
|
|
4
4
|
Summary:
|
|
5
5
|
Author: larrywax, EugenioLaghi, michelangelomo
|
|
6
6
|
Author-email: devops@prima.it
|
|
@@ -21,12 +21,12 @@ Requires-Dist: black (>=22.6,<25.0)
|
|
|
21
21
|
Requires-Dist: boto3 (>=1.17.84)
|
|
22
22
|
Requires-Dist: cement (>=3.0)
|
|
23
23
|
Requires-Dist: colorama (>=0.4.3)
|
|
24
|
-
Requires-Dist: cryptography (==43.0.
|
|
24
|
+
Requires-Dist: cryptography (==43.0.1)
|
|
25
25
|
Requires-Dist: halo (>=0.0.28)
|
|
26
26
|
Requires-Dist: inquirer (==3.1.4)
|
|
27
27
|
Requires-Dist: itsdangerous (==2.2.0)
|
|
28
28
|
Requires-Dist: keyring (>=23.9.1,<26.0.0)
|
|
29
|
-
Requires-Dist: kubernetes (==
|
|
29
|
+
Requires-Dist: kubernetes (==31.0.0)
|
|
30
30
|
Requires-Dist: logzero (==1.7.0)
|
|
31
31
|
Requires-Dist: markupsafe (==2.0.1)
|
|
32
32
|
Requires-Dist: pptree (==3.1)
|
|
@@ -36,7 +36,7 @@ Requires-Dist: pytest (>=7.0.0)
|
|
|
36
36
|
Requires-Dist: python-dateutil (>=2.8.2)
|
|
37
37
|
Requires-Dist: requests (>=2.26.0)
|
|
38
38
|
Requires-Dist: requests-toolbelt (>=0.9.1)
|
|
39
|
-
Requires-Dist: rich (==13.
|
|
39
|
+
Requires-Dist: rich (==13.9.2)
|
|
40
40
|
Requires-Dist: semver (>=2.13.0,<3.0.0)
|
|
41
41
|
Requires-Dist: termcolor (>=1.1.0)
|
|
42
|
-
Requires-Dist: truststore (>=0.7,<0.
|
|
42
|
+
Requires-Dist: truststore (>=0.7,<0.11) ; python_version >= "3.10"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
suite_py/__init__.py,sha256=REmi3D0X2G1ZWnYpKs8Ffm3NIj-Hw6dMuvz2b9NW344,142
|
|
2
|
-
suite_py/__version__.py,sha256=
|
|
3
|
-
suite_py/cli.py,sha256=
|
|
2
|
+
suite_py/__version__.py,sha256=ieZXcKFUSr3HB9yG_7H6w0LtkWcCWwTjzJFoXitR7tQ,49
|
|
3
|
+
suite_py/cli.py,sha256=sgJAT5ofSw4dCSVPtiatWaPrrMJdLSstsDiVcyl2IAE,10258
|
|
4
4
|
suite_py/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
suite_py/commands/ask_review.py,sha256=yN__Ac-fiZBPShjRDhyCCQZGfVlQE16KozoJk4UtiNw,3788
|
|
6
6
|
suite_py/commands/bump.py,sha256=oFZU1hPfD11ujFC5G7wFyQOf2alY3xp2SO1h1ldjf3s,5406
|
|
@@ -19,26 +19,27 @@ suite_py/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
19
19
|
suite_py/lib/config.py,sha256=52YV0K0GK1WRbeM70IDXkpG8oZD1Zvxipn1b-XekwNA,3907
|
|
20
20
|
suite_py/lib/handler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
21
|
suite_py/lib/handler/aws_handler.py,sha256=dRvRDicikfRbuFtCLPbevaX-yC-fO4LwXFdyqLPJ8OI,8815
|
|
22
|
-
suite_py/lib/handler/captainhook_handler.py,sha256=
|
|
22
|
+
suite_py/lib/handler/captainhook_handler.py,sha256=R30_Vvh2ck7fM5fwbpm3UV_FtlQr2xnx6RJpkG1Gn14,2983
|
|
23
23
|
suite_py/lib/handler/changelog_handler.py,sha256=-ppnRl3smBA_ys8tPqXmytS4eyntlwfawC2fiXFcwlw,4818
|
|
24
24
|
suite_py/lib/handler/frequent_reviewers_handler.py,sha256=EIJX5FEMWzrxuXS9A17hu1vfxgJSOHSBX_ahCEZ2FVA,2185
|
|
25
|
-
suite_py/lib/handler/git_handler.py,sha256=
|
|
25
|
+
suite_py/lib/handler/git_handler.py,sha256=Y2hKR5sUKBhfRfQrMNjyCScJpdyPJ7XWK9f3ykx7Lf0,12710
|
|
26
26
|
suite_py/lib/handler/github_handler.py,sha256=AnFL54yOZ5GDIU91wQat4s-d1WTcmg_B_5M7-Rop3wA,2900
|
|
27
27
|
suite_py/lib/handler/metrics_handler.py,sha256=-Tp62pFIiYsBkDga0nQG3lWU-gxH68wEjIIIJeU1jHk,3159
|
|
28
|
-
suite_py/lib/handler/okta_handler.py,sha256=
|
|
28
|
+
suite_py/lib/handler/okta_handler.py,sha256=UiRcBDmFkMFi9H7Me1QaruC8yPI5fFbnLGzOf3kfxG0,2805
|
|
29
|
+
suite_py/lib/handler/pre_commit_handler.py,sha256=2-G67eS5LNYUK3P9JLJmhz_UbMIQr7RffsIaVZ34vy4,3739
|
|
29
30
|
suite_py/lib/handler/prompt_utils.py,sha256=vgk1O7h-iYEAZv1sXtMh8xIgH1djI398rzxRIgZWZcg,2474
|
|
30
31
|
suite_py/lib/handler/version_handler.py,sha256=DXTx4yCAbFVC6CdMqPJ-LiN5YM-dT2zklG8POyKTP5A,6774
|
|
31
32
|
suite_py/lib/handler/youtrack_handler.py,sha256=eTGBBXjlN_ay1cawtnZ2IG6l78dDyKdMN1x6PxcvtA0,7499
|
|
32
33
|
suite_py/lib/logger.py,sha256=q_qRtpg0Eh7r5tB-Rwz87dnWBwP-a2dIvggkiQikH8M,782
|
|
33
|
-
suite_py/lib/metrics.py,sha256=
|
|
34
|
-
suite_py/lib/oauth.py,sha256=
|
|
34
|
+
suite_py/lib/metrics.py,sha256=urTBVzIc1Ys6OHPOO32fLPPRcQU45tzM3XMJ7mUl5dc,1629
|
|
35
|
+
suite_py/lib/oauth.py,sha256=DhXimUu7MDscQsMyt3L04_kw0ZmuqmhYG6KZTPlKqNQ,5083
|
|
35
36
|
suite_py/lib/requests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
37
|
suite_py/lib/requests/auth.py,sha256=wN_WtGFmDUWRFilWzOmUaRBvP2n3EPpPMqex9Zjddko,228
|
|
37
38
|
suite_py/lib/requests/session.py,sha256=P32H3cWnCWunu91WIj2iDM5U3HzaBglg60VN_C9JBL4,267
|
|
38
39
|
suite_py/lib/symbol.py,sha256=z3QYBuNIwD3qQ3zF-cLOomIr_-C3bO_u5UIDAHMiyTo,60
|
|
39
40
|
suite_py/lib/tokens.py,sha256=4DbsHDFLIxs40t3mRw_ZyhmejZQ0Bht7iAL8dTCTQd4,5458
|
|
40
41
|
suite_py/templates/login.html,sha256=fJLls2SB84oZTSrxTdA5q1PqfvIHcCD4fhVWfyco7Ig,861
|
|
41
|
-
suite_py-1.
|
|
42
|
-
suite_py-1.
|
|
43
|
-
suite_py-1.
|
|
44
|
-
suite_py-1.
|
|
42
|
+
suite_py-1.43.0.dist-info/METADATA,sha256=F4M9UIEhOXN7cbAYMSYRI3lV5bVA3GWKtTEghpHQwg4,1533
|
|
43
|
+
suite_py-1.43.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
44
|
+
suite_py-1.43.0.dist-info/entry_points.txt,sha256=dVKLC-9Infy-dHJT_MkK6LcDjOgBCJ8lfPkURJhBjxE,46
|
|
45
|
+
suite_py-1.43.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|