Skip to content

Commit e8e0298

Browse files
committed
rekor: Make create_entry() conservative WRT session use
* Session thread safety is ambiguous: it may now be safe but situation is unclear * Use a single Session per create_entry() call: This may have a little more overhead but seems like the safest option * Note that RekorLog (v1) other methods may not be thread safe: I only reviewed the create_entry() flow Signed-off-by: Jussi Kukkonen <[email protected]>
1 parent ea890a0 commit e8e0298

File tree

2 files changed

+26
-24
lines changed

2 files changed

+26
-24
lines changed

sigstore/_internal/rekor/client.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ def from_response(cls, dict_: dict[str, Any]) -> RekorLogInfo:
7474

7575
class _Endpoint(ABC):
7676
def __init__(self, url: str, session: requests.Session) -> None:
77+
# Note that _Endpoint may not be thread be safe if the same Session is provided
78+
# to an _Endpoint in multiple threads
7779
self.url = url
7880
self.session = session
7981

@@ -210,20 +212,19 @@ def __init__(self, url: str) -> None:
210212
Create a new `RekorClient` from the given URL.
211213
"""
212214
self.url = f"{url}/api/v1"
213-
self.session = requests.Session()
214-
self.session.headers.update(
215+
216+
def _session(self) -> requests.Session:
217+
# We do not use a long living session to avoid potential thread safety issues:
218+
# submitting entries via create_entry() should be thread safe.
219+
session = requests.Session()
220+
session.headers.update(
215221
{
216222
"Content-Type": "application/json",
217223
"Accept": "application/json",
218224
"User-Agent": USER_AGENT,
219225
}
220226
)
221-
222-
def __del__(self) -> None:
223-
"""
224-
Terminates the underlying network session.
225-
"""
226-
self.session.close()
227+
return session
227228

228229
@classmethod
229230
def production(cls) -> RekorClient:
@@ -246,7 +247,10 @@ def log(self) -> RekorLog:
246247
"""
247248
Returns a `RekorLog` adapter for making requests to a Rekor log.
248249
"""
249-
return RekorLog(f"{self.url}/log", session=self.session)
250+
251+
# Each RekorLog gets their own session
252+
with self._session() as s:
253+
return RekorLog(f"{self.url}/log", session=s)
250254

251255
def create_entry(self, request: EntryRequestBody) -> LogEntry:
252256
"""

sigstore/_internal/rekor/client_v2.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,6 @@ def __init__(self, base_url: str) -> None:
5555
Create a new `RekorV2Client` from the given URL.
5656
"""
5757
self.url = f"{base_url}/api/v2"
58-
self.session = requests.Session()
59-
self.session.headers.update(
60-
{
61-
"Content-Type": "application/json",
62-
"Accept": "application/json",
63-
"User-Agent": USER_AGENT,
64-
}
65-
)
66-
67-
def __del__(self) -> None:
68-
"""
69-
Terminates the underlying network session.
70-
"""
71-
self.session.close()
7258

7359
def create_entry(self, payload: EntryRequestBody) -> LogEntry:
7460
"""
@@ -79,7 +65,19 @@ def create_entry(self, payload: EntryRequestBody) -> LogEntry:
7965
https://github.com/sigstore/rekor-tiles/blob/main/CLIENTS.md#handling-longer-requests
8066
"""
8167
_logger.debug(f"proposed: {json.dumps(payload)}")
82-
resp = self.session.post(
68+
69+
# Use a short lived session to avoid potential issues with multi-threading:
70+
# Session thread-safety is ambiguous
71+
session = requests.Session()
72+
session.headers.update(
73+
{
74+
"Content-Type": "application/json",
75+
"Accept": "application/json",
76+
"User-Agent": USER_AGENT,
77+
}
78+
)
79+
80+
resp = session.post(
8381
f"{self.url}/log/entries",
8482
json=payload,
8583
)

0 commit comments

Comments
 (0)