Skip to content

Commit cb9540a

Browse files
committed
Fix SecretsManager
For some reason we coded up the SecretsManager so that it held only one secret per session. Let's store a dict instead.
1 parent 30e56e3 commit cb9540a

File tree

5 files changed

+30
-19
lines changed

5 files changed

+30
-19
lines changed

src/codegate/pipeline/secrets/manager.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class SecretsManager:
2121

2222
def __init__(self):
2323
self.crypto = CodeGateCrypto()
24-
self._session_store: dict[str, SecretEntry] = {}
24+
self._session_store: dict[str, dict[str, SecretEntry]] = {}
2525
self._encrypted_to_session: dict[str, str] = {} # Reverse lookup index
2626

2727
def store_secret(self, value: str, service: str, secret_type: str, session_id: str) -> str:
@@ -41,12 +41,14 @@ def store_secret(self, value: str, service: str, secret_type: str, session_id: s
4141
encrypted_value = self.crypto.encrypt_token(value, session_id)
4242

4343
# Store mappings
44-
self._session_store[session_id] = SecretEntry(
44+
session_secrets = self._session_store.get(session_id, {})
45+
session_secrets[encrypted_value] = SecretEntry(
4546
original=value,
4647
encrypted=encrypted_value,
4748
service=service,
4849
secret_type=secret_type,
4950
)
51+
self._session_store[session_id] = session_secrets
5052
self._encrypted_to_session[encrypted_value] = session_id
5153

5254
logger.debug("Stored secret", service=service, type=secret_type, encrypted=encrypted_value)
@@ -58,7 +60,9 @@ def get_original_value(self, encrypted_value: str, session_id: str) -> Optional[
5860
try:
5961
stored_session_id = self._encrypted_to_session.get(encrypted_value)
6062
if stored_session_id == session_id:
61-
return self._session_store[session_id].original
63+
session_secrets = self._session_store[session_id].get(encrypted_value)
64+
if session_secrets:
65+
return session_secrets.original
6266
except Exception as e:
6367
logger.error("Error retrieving secret", error=str(e))
6468
return None
@@ -71,9 +75,10 @@ def cleanup(self):
7175
"""Securely wipe sensitive data"""
7276
try:
7377
# Convert and wipe original values
74-
for entry in self._session_store.values():
75-
original_bytes = bytearray(entry.original.encode())
76-
self.crypto.wipe_bytearray(original_bytes)
78+
for secrets in self._session_store.values():
79+
for entry in secrets.values():
80+
original_bytes = bytearray(entry.original.encode())
81+
self.crypto.wipe_bytearray(original_bytes)
7782

7883
# Clear the dictionaries
7984
self._session_store.clear()
@@ -92,9 +97,9 @@ def cleanup_session(self, session_id: str):
9297
"""
9398
try:
9499
# Get the secret entry for the session
95-
entry = self._session_store.get(session_id)
100+
secrets = self._session_store.get(session_id, {})
96101

97-
if entry:
102+
for entry in secrets.values():
98103
# Securely wipe the original value
99104
original_bytes = bytearray(entry.original.encode())
100105
self.crypto.wipe_bytearray(original_bytes)

src/codegate/pipeline/secrets/secrets.py

+3
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ async def process_chunk(
362362
if match:
363363
# Found a complete marker, process it
364364
encrypted_value = match.group(1)
365+
print("----> encrypted_value: ", encrypted_value)
365366
original_value = input_context.sensitive.manager.get_original_value(
366367
encrypted_value,
367368
input_context.sensitive.session_id,
@@ -370,6 +371,8 @@ async def process_chunk(
370371
if original_value is None:
371372
# If value not found, leave as is
372373
original_value = match.group(0) # Keep the REDACTED marker
374+
else:
375+
print("----> original_value: ", original_value)
373376

374377
# Post an alert with the redacted content
375378
input_context.add_alert(self.name, trigger_string=encrypted_value)

src/codegate/providers/ollama/completion_handler.py

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ async def ollama_stream_generator(
1616
"""OpenAI-style SSE format"""
1717
try:
1818
async for chunk in stream:
19+
print(chunk)
1920
try:
2021
yield f"{chunk.model_dump_json()}\n\n"
2122
except Exception as e:

src/codegate/providers/ollama/provider.py

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def _setup_routes(self):
3838
"""
3939
Sets up Ollama API routes.
4040
"""
41+
4142
@self.router.get(f"/{self.provider_route_name}/api/tags")
4243
async def get_tags(request: Request):
4344
"""

tests/pipeline/secrets/test_manager.py

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from codegate.pipeline.secrets.manager import SecretEntry, SecretsManager
3+
from codegate.pipeline.secrets.manager import SecretsManager
44

55

66
class TestSecretsManager:
@@ -21,11 +21,8 @@ def test_store_secret(self):
2121

2222
# Verify the secret was stored
2323
stored = self.manager.get_by_session_id(self.test_session)
24-
assert isinstance(stored, SecretEntry)
25-
assert stored.original == self.test_value
26-
assert stored.encrypted == encrypted
27-
assert stored.service == self.test_service
28-
assert stored.secret_type == self.test_type
24+
assert isinstance(stored, dict)
25+
assert stored[encrypted].original == self.test_value
2926

3027
# Verify encrypted value can be retrieved
3128
retrieved = self.manager.get_original_value(encrypted, self.test_session)
@@ -86,10 +83,15 @@ def test_multiple_secrets_same_session(self):
8683
encrypted1 = self.manager.store_secret("secret1", "service1", "type1", self.test_session)
8784
encrypted2 = self.manager.store_secret("secret2", "service2", "type2", self.test_session)
8885

89-
# Latest secret should be retrievable
86+
# Latest secret should be retrievable in the session
9087
stored = self.manager.get_by_session_id(self.test_session)
91-
assert stored.original == "secret2"
92-
assert stored.encrypted == encrypted2
88+
assert isinstance(stored, dict)
89+
assert stored[encrypted1].original == "secret1"
90+
assert stored[encrypted2].original == "secret2"
91+
92+
# Both secrets should be retrievable directly
93+
assert self.manager.get_original_value(encrypted1, self.test_session) == "secret1"
94+
assert self.manager.get_original_value(encrypted2, self.test_session) == "secret2"
9395

9496
# Both encrypted values should map to the session
9597
assert self.manager._encrypted_to_session[encrypted1] == self.test_session
@@ -119,15 +121,14 @@ def test_secure_cleanup(self):
119121

120122
# Get reference to stored data before cleanup
121123
stored = self.manager.get_by_session_id(self.test_session)
122-
original_value = stored.original
124+
assert len(stored) == 1
123125

124126
# Perform cleanup
125127
self.manager.cleanup()
126128

127129
# Verify the original string was overwritten, not just removed
128130
# This test is a bit tricky since Python strings are immutable,
129131
# but we can at least verify the data is no longer accessible
130-
assert original_value not in str(self.manager._session_store)
131132
assert self.test_value not in str(self.manager._session_store)
132133

133134
def test_session_isolation(self):

0 commit comments

Comments
 (0)