Skip to content

Commit dcd3fd4

Browse files
author
Paweł Kędzia
committed
Merge branch 'features/fa_optim'
2 parents fec086a + b280aa5 commit dcd3fd4

File tree

9 files changed

+62
-21
lines changed

9 files changed

+62
-21
lines changed

.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.4.0
1+
0.4.1

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
| 0.2.4 | Anonymizer module, integration anonymization with any endpoint (using dynamic payload analysis and full payload anonymisation), dedicated `/api/anonymize_text` endpoint as memory only anonymization. Whole router may be run in `FORCE_ANONYMISATION` mode. |
1616
| 0.3.0 | Anonymization available with three strategies: `fast_masker`, `genai`, `prov_masker`. |
1717
| 0.3.1 | Refactoring `lb.strategies` to be more flexible modular. Introduced `MaskerPipeline` and `GuardrailPipeline` both configured via env. Removed genai-based masking endpoint. |
18-
| 0.4.0 | The main repository is divided into dedicated ones: plugins, services, web — separate repositories. Clean up the whole repository. Examples of integration with llamaindex, langchain, openai, litellm and haystack. |
18+
| 0.4.0 | The main repository is divided into dedicated ones: plugins, services, web — separate repositories. Clean up the whole repository. Examples of integration with llamaindex, langchain, openai, litellm and haystack. |
19+
| 0.4.1 | Audit log is stored using GPG. Add bash script (`scripts/gen_and_export_gpg.sh` to prepare GPG keys and simple `scripts/decrypt_auditor_logs.sh` to decrypt encrypted audit logs. |

llm_router_api/base/constants.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,6 @@ def __verify_balancing_strategy():
217217

218218
@staticmethod
219219
def __verify_default_masking_strategy():
220-
if MASKING_WITH_AUDIT:
221-
if not FORCE_MASKING:
222-
raise Exception(
223-
f"`export LLM_ROUTER_FORCE_MASKING=1` environment is "
224-
f"required when `LLM_ROUTER_MASKING_WITH_AUDIT=1`\n\n"
225-
)
226-
227220
if FORCE_MASKING and not len(MASKING_STRATEGY_PIPELINE):
228221
raise Exception(
229222
"When FORCE_MASKING is set to `True`, you must specify the "
File renamed without changes.

llm_router_api/base/model_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from typing import Dict, Optional, Any
1212

1313
from llm_router_api.base.model_config import ApiModelConfig
14-
from llm_router_api.base.lb.provider_strategy_facase import ProviderStrategyFacade
14+
from llm_router_api.base.lb.provider_strategy_facade import ProviderStrategyFacade
1515

1616

1717
@dataclass(frozen=True)

llm_router_api/core/auditor/log_storage/gpg.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
``logs/auditor/<audit_type>__<timestamp>.audit``.
1919
"""
2020

21+
import uuid
2122
import json
2223
import gnupg
2324

@@ -28,8 +29,16 @@
2829
AuditorLogStorageInterface,
2930
)
3031

32+
# Base output directory for the auditor
33+
DEFAULT_AUDITOR_OUT_DIR = Path("logs/auditor")
34+
DEFAULT_AUDITOR_OUT_DIR.mkdir(parents=True, exist_ok=True)
35+
3136

3237
class GPGAuditorLogStorage(AuditorLogStorageInterface):
38+
# Default gpg auditor public key
39+
AUDITOR_PUB_KEY_DIR = Path("resources/keys")
40+
AUDITOR_PUB_KEY_FILE = AUDITOR_PUB_KEY_DIR / Path("llm-router-auditor-pub.asc")
41+
3342
"""
3443
GPG‑backed storage for audit logs.
3544
@@ -46,13 +55,6 @@ class GPGAuditorLogStorage(AuditorLogStorageInterface):
4655
for encryption.
4756
"""
4857

49-
# Base output directory for the auditor
50-
DEFAULT_AUDITOR_OUT_DIR = Path("logs/auditor")
51-
DEFAULT_AUDITOR_OUT_DIR.mkdir(parents=True, exist_ok=True)
52-
53-
AUDITOR_PUB_KEY_DIR = Path("resources/keys")
54-
AUDITOR_PUB_KEY_FILE = AUDITOR_PUB_KEY_DIR / Path("llm-router-auditor-pub.asc")
55-
5658
def __init__(self):
5759
"""
5860
Create a new GPG‑based audit log storage instance.
@@ -70,6 +72,8 @@ def __init__(self):
7072
self._gpg = gnupg.GPG(gnupghome=str(self.AUDITOR_PUB_KEY_DIR))
7173
self._gpg.encoding = "utf-8"
7274

75+
self.__verify()
76+
7377
with self.AUDITOR_PUB_KEY_FILE.open("r", encoding="utf-8") as f:
7478
self._import_result = self._gpg.import_keys(f.read())
7579
if not self._import_result.count:
@@ -103,7 +107,7 @@ def store_log(self, audit_log, audit_type: str):
103107
"""
104108
date_str = datetime.now().strftime("%Y%m%d_%H%M%S.%f")
105109
out_file_name = f"{audit_type}__{date_str}.audit"
106-
out_file_path = self.DEFAULT_AUDITOR_OUT_DIR / out_file_name
110+
out_file_path = DEFAULT_AUDITOR_OUT_DIR / out_file_name
107111
with open(out_file_path, "wt") as f:
108112
audit_str = json.dumps(audit_log, indent=2, ensure_ascii=False)
109113
encrypted_data = self._gpg.encrypt(
@@ -113,3 +117,46 @@ def store_log(self, audit_log, audit_type: str):
113117
armor=True,
114118
)
115119
f.write(str(encrypted_data))
120+
121+
def __verify(self):
122+
"""
123+
Perform internal sanity checks during initialisation.
124+
125+
This method verifies that the required GPG public key file exists
126+
and that the process has write access to ``DEFAULT_AUDITOR_OUT_DIR``.
127+
It raises an exception if either check fails.
128+
"""
129+
self.__check_key_exists()
130+
self.__check_write_permission()
131+
132+
def __check_key_exists(self):
133+
"""
134+
Ensure that the GPG public key file specified by
135+
``AUDITOR_PUB_KEY_FILE`` is present on the filesystem.
136+
137+
Raises
138+
------
139+
Exception
140+
If the public key file does not exist.
141+
"""
142+
if not self.AUDITOR_PUB_KEY_FILE.exists():
143+
raise Exception(
144+
f"GPG public key {self.AUDITOR_PUB_KEY_FILE} does not exists!"
145+
)
146+
147+
def __check_write_permission(self):
148+
"""
149+
Verify that the process can write to ``DEFAULT_AUDITOR_OUT_DIR``.
150+
Writes a temporary file containing the string ``"llm-router"``,
151+
then removes it. Raises ``PermissionError`` if any step fails.
152+
"""
153+
try:
154+
temp_name = f"perm_check_{uuid.uuid4().hex}.audit"
155+
temp_path = DEFAULT_AUDITOR_OUT_DIR / temp_name
156+
with open(temp_path, "wt") as f:
157+
f.write("llm-router")
158+
temp_path.unlink()
159+
except Exception as exc:
160+
raise PermissionError(
161+
f"Unable to write to {DEFAULT_AUDITOR_OUT_DIR}: {exc}"
162+
)

llm_router_api/core/engine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
USE_PROMETHEUS,
3434
SERVER_BALANCE_STRATEGY,
3535
)
36-
from llm_router_api.base.lb.provider_strategy_facase import ProviderStrategyFacade
36+
from llm_router_api.base.lb.provider_strategy_facade import ProviderStrategyFacade
3737

3838
if USE_PROMETHEUS:
3939
from llm_router_api.core.metrics import PrometheusMetrics

llm_router_api/register/auto_loader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from llm_router_api.base.model_handler import ModelHandler
1212
from llm_router_api.base.constants import REST_API_LOG_LEVEL
13-
from llm_router_api.base.lb.provider_strategy_facase import ProviderStrategyFacade
13+
from llm_router_api.base.lb.provider_strategy_facade import ProviderStrategyFacade
1414

1515
from llm_router_api.endpoints.passthrough import PassthroughI
1616
from llm_router_api.endpoints.builtin.openai import OpenAIResponseHandler

run-rest-api-gunicorn.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export LLM_ROUTER_REDIS_PORT=${LLM_ROUTER_REDIS_PORT:-6379}
5050
# Data protection (additional endpoints will be available)
5151
# ------------ Masker section
5252
export LLM_ROUTER_FORCE_MASKING=${LLM_ROUTER_FORCE_MASKING:-0}
53-
export LLM_ROUTER_MASKING_WITH_AUDIT=${LLM_ROUTER_MASKING_WITH_AUDIT:-0}
53+
export LLM_ROUTER_MASKING_WITH_AUDIT=${LLM_ROUTER_MASKING_WITH_AUDIT:-1}
5454
export LLM_ROUTER_MASKING_STRATEGY_PIPELINE=${LLM_ROUTER_MASKING_STRATEGY_PIPELINE:-"fast_masker"}
5555
# ------------ Guardrails section (request)
5656
export LLM_ROUTER_FORCE_GUARDRAIL_REQUEST=${LLM_ROUTER_FORCE_GUARDRAIL_REQUEST:-0}

0 commit comments

Comments
 (0)