Skip to content

Commit 8a15ad9

Browse files
Merge branch 'master' into iduffy/circleci
2 parents df15ca1 + 2a30884 commit 8a15ad9

7 files changed

Lines changed: 60 additions & 23 deletions

File tree

Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,9 @@ RUN mkdir -p /opt/cloudsmith \
1616
&& curl -1sLf -o /opt/cloudsmith/cloudsmith "https://dl.cloudsmith.io/public/${CLOUDSMITH_NAMESPACE}/${CLOUDSMITH_REPO}/raw/names/cloudsmith-cli/versions/${CLOUDSMITH_CLI_VERSION}/cloudsmith.pyz" \
1717
&& chmod +x /opt/cloudsmith/cloudsmith
1818

19+
# Run as a non-root user
20+
RUN adduser -D -u 1000 cloudsmith
21+
USER cloudsmith
22+
1923
# Default command
2024
ENTRYPOINT [ "cloudsmith" ]

cloudsmith_cli/core/credentials/oidc/cache.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,16 @@ def _cache_key(api_host: str, org: str, service_slug: str) -> str:
4141

4242

4343
def _decode_jwt_exp(token: str) -> float | None:
44-
"""Decode the exp claim from a JWT without verification."""
44+
"""Read the exp claim from a JWT payload.
45+
46+
The token is only inspected to determine a cache TTL; it is never used to
47+
make an authorization decision, so the signature is deliberately not
48+
verified (the API rejects tampered tokens regardless).
49+
"""
4550
try:
4651
import jwt
4752

48-
payload = jwt.decode(
49-
token,
50-
options={"verify_signature": False},
51-
algorithms=["RS256", "ES256", "HS256"],
52-
)
53+
payload = jwt.decode(token, options={"verify_signature": False})
5354
exp = payload.get("exp")
5455
if exp is not None:
5556
return float(exp)

cloudsmith_cli/core/download.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ def _verify_checksum(filepath: str, expected: str) -> bool:
583583

584584
# Try SHA1
585585
if len(expected) == 40:
586-
sha1_hash = hashlib.sha1()
586+
sha1_hash = hashlib.sha1(usedforsecurity=False)
587587
with open(filepath, "rb") as f:
588588
for chunk in iter(lambda: f.read(4096), b""):
589589
sha1_hash.update(chunk)

cloudsmith_cli/core/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def read_file(*path):
3535

3636
def calculate_file_md5(filepath, blocksize=2**20):
3737
"""Calculate an MD5 hash for a file."""
38-
checksum = hashlib.md5()
38+
checksum = hashlib.md5(usedforsecurity=False)
3939

4040
with click.open_file(filepath, "rb") as f:
4141

requirements.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ pre-commit
88
pylint
99
pytest-cov
1010
python-toon
11-
mcp==1.9.1
11+
mcp==1.27.2

requirements.txt

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with Python 3.10
33
# by the following command:
44
#
5-
# pip-compile --output-file=requirements.txt requirements.in setup.py
5+
# pip-compile --no-emit-index-url --output-file=requirements.txt requirements.in setup.py
66
#
77
annotated-types==0.7.0
88
# via pydantic
@@ -14,6 +14,10 @@ anyio==4.12.1
1414
# starlette
1515
astroid==4.0.3
1616
# via pylint
17+
attrs==26.1.0
18+
# via
19+
# jsonschema
20+
# referencing
1721
backports-tarfile==1.2.0
1822
# via jaraco-context
1923
build==1.4.0
@@ -28,6 +32,8 @@ certifi==2026.1.4
2832
# httpcore
2933
# httpx
3034
# requests
35+
cffi==2.0.0
36+
# via cryptography
3137
cfgv==3.5.0
3238
# via pre-commit
3339
charset-normalizer==3.4.4
@@ -51,6 +57,8 @@ configparser==7.2.0
5157
# via click-configfile
5258
coverage[toml]==7.13.1
5359
# via pytest-cov
60+
cryptography==48.0.0
61+
# via pyjwt
5462
dill==0.4.1
5563
# via pylint
5664
distlib==0.4.0
@@ -77,7 +85,7 @@ httpx-sse==0.4.3
7785
# via mcp
7886
identify==2.6.16
7987
# via pre-commit
80-
idna==3.11
88+
idna==3.18
8189
# via
8290
# anyio
8391
# httpx
@@ -96,13 +104,17 @@ jaraco-functools==4.4.0
96104
# via keyring
97105
json5==0.13.0
98106
# via cloudsmith-cli (setup.py)
107+
jsonschema==4.26.0
108+
# via mcp
109+
jsonschema-specifications==2025.9.1
110+
# via jsonschema
99111
keyring==25.7.0
100112
# via cloudsmith-cli (setup.py)
101113
markdown-it-py==4.0.0
102114
# via rich
103115
mccabe==0.7.0
104116
# via pylint
105-
mcp==1.9.1
117+
mcp==1.27.2
106118
# via
107119
# -r requirements.in
108120
# cloudsmith-cli (setup.py)
@@ -131,6 +143,8 @@ pluggy==1.6.0
131143
# pytest-cov
132144
pre-commit==4.5.1
133145
# via -r requirements.in
146+
pycparser==3.0
147+
# via cffi
134148
pydantic==2.12.5
135149
# via
136150
# mcp
@@ -139,44 +153,55 @@ pydantic-core==2.41.5
139153
# via pydantic
140154
pydantic-settings==2.12.0
141155
# via mcp
142-
pygments==2.19.2
156+
pygments==2.20.0
143157
# via
144158
# pytest
145159
# rich
146-
pyjwt==2.12.1
147-
# via cloudsmith-cli (setup.py)
160+
pyjwt[crypto]==2.12.1
161+
# via
162+
# cloudsmith-cli (setup.py)
163+
# mcp
164+
# pyjwt
148165
pylint==4.0.4
149166
# via -r requirements.in
150167
pyproject-hooks==1.2.0
151168
# via
152169
# build
153170
# pip-tools
154-
pytest==9.0.2
171+
pytest==9.0.3
155172
# via pytest-cov
156173
pytest-cov==7.0.0
157174
# via -r requirements.in
158175
python-dateutil==2.9.0.post0
159176
# via
160177
# cloudsmith-api
161178
# freezegun
162-
python-dotenv==1.2.1
179+
python-dotenv==1.2.2
163180
# via pydantic-settings
164-
python-multipart==0.0.21
181+
python-multipart==0.0.32
165182
# via mcp
166183
python-toon==0.1.2
167184
# via
168185
# -r requirements.in
169186
# cloudsmith-cli (setup.py)
170187
pyyaml==6.0.3
171188
# via pre-commit
172-
requests==2.32.5
189+
referencing==0.37.0
190+
# via
191+
# jsonschema
192+
# jsonschema-specifications
193+
requests==2.34.2
173194
# via
174195
# cloudsmith-cli (setup.py)
175196
# requests-toolbelt
176197
requests-toolbelt==1.0.0
177198
# via cloudsmith-cli (setup.py)
178199
rich==14.3.3
179200
# via cloudsmith-cli (setup.py)
201+
rpds-py==0.30.0
202+
# via
203+
# jsonschema
204+
# referencing
180205
semver==3.0.4
181206
# via cloudsmith-cli (setup.py)
182207
six==1.17.0
@@ -186,7 +211,7 @@ six==1.17.0
186211
# python-dateutil
187212
sse-starlette==3.2.0
188213
# via mcp
189-
starlette==0.52.1
214+
starlette==1.2.1
190215
# via
191216
# mcp
192217
# sse-starlette
@@ -203,19 +228,23 @@ typing-extensions==4.15.0
203228
# via
204229
# anyio
205230
# astroid
231+
# cryptography
206232
# exceptiongroup
233+
# mcp
207234
# pydantic
208235
# pydantic-core
209236
# pyjwt
237+
# referencing
210238
# starlette
211239
# typing-inspection
212240
# uvicorn
213241
# virtualenv
214242
typing-inspection==0.4.2
215243
# via
244+
# mcp
216245
# pydantic
217246
# pydantic-settings
218-
urllib3==2.6.3
247+
urllib3==2.7.0
219248
# via
220249
# cloudsmith-api
221250
# cloudsmith-cli (setup.py)

setup.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ def get_long_description():
5656
"json5>=0.9.0", # For parsing JSONC (JSON with comments) in VS Code settings
5757
"cloudsmith-api>=2.0.25,<3.0", # Compatible upto (but excluding) 3.0+
5858
"keyring>=25.4.1",
59-
"mcp==1.9.1",
60-
"PyJWT>=2.0.0",
59+
"mcp==1.27.2",
60+
# The crypto extra must be declared here: mcp requires pyjwt[crypto],
61+
# and a bare PyJWT requirement makes the PEX zipapp resolver drop the
62+
# extra (and with it the cryptography wheels).
63+
"PyJWT[crypto]>=2.0.0",
6164
"python-toon==0.1.2",
6265
"requests>=2.18.4",
6366
"requests_toolbelt>=1.0.0",

0 commit comments

Comments
 (0)