litellm-lint 0.1.0__tar.gz
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.
- litellm_lint-0.1.0/.gitignore +38 -0
- litellm_lint-0.1.0/.pre-commit-hooks.yaml +7 -0
- litellm_lint-0.1.0/CHANGELOG.md +26 -0
- litellm_lint-0.1.0/LICENSE +21 -0
- litellm_lint-0.1.0/PKG-INFO +271 -0
- litellm_lint-0.1.0/README.md +246 -0
- litellm_lint-0.1.0/docs/images/01-hero.png +0 -0
- litellm_lint-0.1.0/docs/images/02-good.png +0 -0
- litellm_lint-0.1.0/docs/rules.md +28 -0
- litellm_lint-0.1.0/examples/.env.example +4 -0
- litellm_lint-0.1.0/examples/bad_config.yaml +29 -0
- litellm_lint-0.1.0/examples/good_config.yaml +31 -0
- litellm_lint-0.1.0/pyproject.toml +48 -0
- litellm_lint-0.1.0/scripts/gen_snapshot.py +370 -0
- litellm_lint-0.1.0/src/litellm_lint/__init__.py +18 -0
- litellm_lint-0.1.0/src/litellm_lint/__main__.py +3 -0
- litellm_lint-0.1.0/src/litellm_lint/cli.py +96 -0
- litellm_lint-0.1.0/src/litellm_lint/context.py +33 -0
- litellm_lint-0.1.0/src/litellm_lint/core.py +66 -0
- litellm_lint-0.1.0/src/litellm_lint/diagnostics.py +108 -0
- litellm_lint-0.1.0/src/litellm_lint/includes.py +82 -0
- litellm_lint-0.1.0/src/litellm_lint/loader.py +215 -0
- litellm_lint-0.1.0/src/litellm_lint/py.typed +0 -0
- litellm_lint-0.1.0/src/litellm_lint/report.py +68 -0
- litellm_lint-0.1.0/src/litellm_lint/rules/__init__.py +1 -0
- litellm_lint-0.1.0/src/litellm_lint/rules/deployments.py +75 -0
- litellm_lint-0.1.0/src/litellm_lint/rules/env.py +95 -0
- litellm_lint-0.1.0/src/litellm_lint/rules/keys.py +223 -0
- litellm_lint-0.1.0/src/litellm_lint/rules/refs.py +226 -0
- litellm_lint-0.1.0/src/litellm_lint/rules/safety.py +67 -0
- litellm_lint-0.1.0/src/litellm_lint/schema_export.py +74 -0
- litellm_lint-0.1.0/src/litellm_lint/snapshot.py +35 -0
- litellm_lint-0.1.0/src/litellm_lint/snapshots/litellm-1.108.4.json +8050 -0
- litellm_lint-0.1.0/src/litellm_lint/suggest.py +12 -0
- litellm_lint-0.1.0/tests/conftest.py +70 -0
- litellm_lint-0.1.0/tests/test_cli.py +65 -0
- litellm_lint-0.1.0/tests/test_env.py +61 -0
- litellm_lint-0.1.0/tests/test_examples.py +84 -0
- litellm_lint-0.1.0/tests/test_gen_snapshot.py +92 -0
- litellm_lint-0.1.0/tests/test_hardening.py +175 -0
- litellm_lint-0.1.0/tests/test_keys.py +98 -0
- litellm_lint-0.1.0/tests/test_redaction.py +68 -0
- litellm_lint-0.1.0/tests/test_refs.py +85 -0
- litellm_lint-0.1.0/tests/test_rules_misc.py +45 -0
- litellm_lint-0.1.0/tests/test_schema_export.py +49 -0
- litellm_lint-0.1.0/tests/test_snapshot.py +42 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.venv/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.mypy_cache/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
|
|
10
|
+
# Node
|
|
11
|
+
node_modules/
|
|
12
|
+
dist/
|
|
13
|
+
.next/
|
|
14
|
+
|
|
15
|
+
# 실행 산출물·모델·데이터 캐시
|
|
16
|
+
runs/
|
|
17
|
+
outputs/
|
|
18
|
+
.cache/
|
|
19
|
+
*.safetensors
|
|
20
|
+
*.gguf
|
|
21
|
+
*.bin
|
|
22
|
+
|
|
23
|
+
# 환경·비밀
|
|
24
|
+
.env
|
|
25
|
+
.env.*
|
|
26
|
+
!.env.example
|
|
27
|
+
|
|
28
|
+
# OS·에디터
|
|
29
|
+
.DS_Store
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
|
|
33
|
+
# Flutter·Dart
|
|
34
|
+
.dart_tool/
|
|
35
|
+
build/
|
|
36
|
+
.flutter-plugins
|
|
37
|
+
.flutter-plugins-dependencies
|
|
38
|
+
coverage/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
- id: litellm-lint
|
|
2
|
+
name: litellm-lint (LiteLLM proxy config)
|
|
3
|
+
description: Static check of a LiteLLM proxy config.yaml (typos, missing env vars, dangling fallbacks).
|
|
4
|
+
entry: litellm-lint check
|
|
5
|
+
language: python
|
|
6
|
+
files: (^|/)config[^/]*\.ya?ml$
|
|
7
|
+
pass_filenames: true
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-11-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `litellm-lint check` with rules LL000-LL402 and LL900 (unknown keys, types, misplaced keys, fallback and alias reference integrity, `os.environ/` resolution, literal secrets, weak `master_key`, repeated deployments, unknown provider prefixes).
|
|
12
|
+
- `--env-file` (repeatable), `--no-os-env`, `--strict`, `--ignore`, `--format text|json`; exit codes 0 / 1 / 2.
|
|
13
|
+
- `litellm-lint schema`: JSON Schema (Draft 2020-12) export for editors.
|
|
14
|
+
- Built-in schema snapshot extracted from litellm 1.108.4 and `scripts/gen_snapshot.py` to regenerate it.
|
|
15
|
+
- Python API: `check_file`, `export_schema`, `Diagnostic`, `Report`, `Severity`, `LintUsageError`.
|
|
16
|
+
- `.pre-commit-hooks.yaml`, example configs, CI.
|
|
17
|
+
|
|
18
|
+
### Known limitations
|
|
19
|
+
- In text mode, a problem found in an `include`d file is shown with the main config's file name plus the included file's line and column (JSON output has the right file).
|
|
20
|
+
- An `include` loop made of links, or a list used as a top-level mapping key, ends with "internal error" (exit 2) instead of an LL900 diagnostic.
|
|
21
|
+
- When anchors/aliases reuse the same `litellm_params` across many deployments, the same diagnostic is repeated once per deployment.
|
|
22
|
+
- Summary lines are always plural ("1 errors", "1 warnings").
|
|
23
|
+
- `Report.diagnostics` from the Python API is not sorted by line; sort it yourself.
|
|
24
|
+
|
|
25
|
+
[Unreleased]: https://github.com/LeeGyeongPil/litellm-lint/compare/v0.1.0...HEAD
|
|
26
|
+
[0.1.0]: https://github.com/LeeGyeongPil/litellm-lint/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LeeGyeongPil
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: litellm-lint
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Static linter for LiteLLM proxy config.yaml: typo'd keys, missing env vars, dangling fallbacks and aliases. Unofficial.
|
|
5
|
+
Project-URL: Homepage, https://github.com/LeeGyeongPil/litellm-lint
|
|
6
|
+
Project-URL: Issues, https://github.com/LeeGyeongPil/litellm-lint/issues
|
|
7
|
+
Author: LeeGyeongPil
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: config,linter,litellm,llm-gateway,proxy,yaml
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: ruamel-yaml<0.20,>=0.18
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# litellm-lint
|
|
27
|
+
|
|
28
|
+
> **English summary** — A static linter for LiteLLM proxy `config.yaml` files (unofficial, not affiliated with LiteLLM). It catches typo'd keys, missing `os.environ/` variables and fallbacks or aliases that point at a model that does not exist, before you deploy. Install: `uv tool install git+https://github.com/LeeGyeongPil/litellm-lint`, run: `litellm-lint check config.yaml`.
|
|
29
|
+
|
|
30
|
+
LiteLLM 프록시는 설정 파일의 오타를 조용히 넘기는 경우가 많습니다. 이 도구는 프록시를 띄우기 전에 `config.yaml` 을 읽어 그런 실수를 줄 번호와 함께 알려 줍니다. 프록시를 실행하지 않고, 네트워크도 쓰지 않고, 키 값도 읽어 출력하지 않습니다.
|
|
31
|
+
|
|
32
|
+
> 비공식 도구입니다. 검사 기준은 **litellm 1.108.4** 에서 뽑아 둔 스냅숏입니다(아래 "지원 버전과 한계").
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
*오타·없는 환경 변수 5건과 끊어진 폴백 2건을 줄 번호와 함께 보여 주는 `litellm-lint check` 출력*
|
|
36
|
+
|
|
37
|
+
## 이런 분께
|
|
38
|
+
- 배포 전에 `config.yaml` 을 CI 나 pre-commit 에서 자동으로 확인하고 싶을 때
|
|
39
|
+
- `num_retires` 같은 오타가 에러 없이 무시된 경험이 있을 때
|
|
40
|
+
- `fallbacks` 에 적은 모델 이름이 `model_list` 에 실제로 있는지 확인하고 싶을 때
|
|
41
|
+
- `os.environ/NAME` 으로 적은 환경 변수가 배포 환경에 정의돼 있는지 미리 보고 싶을 때
|
|
42
|
+
|
|
43
|
+
## 설치
|
|
44
|
+
```bash
|
|
45
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # uv 가 없다면 (Python 3.10 이상 필요)
|
|
46
|
+
uv tool install git+https://github.com/LeeGyeongPil/litellm-lint
|
|
47
|
+
litellm-lint --version
|
|
48
|
+
```
|
|
49
|
+
```
|
|
50
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4)
|
|
51
|
+
```
|
|
52
|
+
설치 없이 한 번만 돌려 보려면 `uvx --from git+https://github.com/LeeGyeongPil/litellm-lint litellm-lint check config.yaml`. 레포를 받아 직접 쓰려면 `git clone` 후 `uv run litellm-lint ...`. 최소 리눅스 이미지에는 `git` 과 `curl` 이 필요합니다.
|
|
53
|
+
|
|
54
|
+
## 빠르게 시작하기
|
|
55
|
+
레포의 예제로 바로 해 볼 수 있습니다.
|
|
56
|
+
```bash
|
|
57
|
+
git clone https://github.com/LeeGyeongPil/litellm-lint && cd litellm-lint
|
|
58
|
+
uv run litellm-lint check examples/bad_config.yaml --env-file examples/.env.example
|
|
59
|
+
```
|
|
60
|
+
```
|
|
61
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
62
|
+
examples/bad_config.yaml:7:16: error LL201 environment variable 'OPENAI_API_KEYY' not found in: examples/.env.example, process environment (did you mean 'OPENAI_API_KEY'?)
|
|
63
|
+
examples/bad_config.yaml:17:7: warning LL001 unknown key 'api_bse' in litellm_params (did you mean 'api_base'?)
|
|
64
|
+
examples/bad_config.yaml:20:3: error LL001 unknown key 'num_retires' in router_settings (did you mean 'num_retries'?)
|
|
65
|
+
examples/bad_config.yaml:22:18: error LL101 fallback target 'gpt-backup' in router_settings.fallbacks is not a model_name in model_list
|
|
66
|
+
examples/bad_config.yaml:24:3: error LL001 unknown key 'drop_parms' in litellm_settings (did you mean 'drop_params'?)
|
|
67
|
+
examples/bad_config.yaml:26:21: error LL101 fallback target 'nope-model' in litellm_settings.context_window_fallbacks is not a model_name in model_list
|
|
68
|
+
examples/bad_config.yaml:29:3: warning LL001 unknown key 'maser_key_typo' in general_settings: not in the litellm 1.108.4 snapshot (may be a newer setting, or a typo)
|
|
69
|
+
5 errors, 2 warnings
|
|
70
|
+
```
|
|
71
|
+
각 줄은 `파일:줄:열: 심각도 규칙코드 메시지` 입니다. 종료 코드는 오류가 있으면 1 입니다. 문제없는 설정은 이렇게 끝납니다.
|
|
72
|
+
```bash
|
|
73
|
+
uv run litellm-lint check examples/good_config.yaml --env-file examples/.env.example
|
|
74
|
+
```
|
|
75
|
+
```
|
|
76
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
77
|
+
0 errors, 0 warnings
|
|
78
|
+
```
|
|
79
|
+

|
|
80
|
+
*오류도 경고도 없으면 종료 코드 0*
|
|
81
|
+
|
|
82
|
+
## 사용법
|
|
83
|
+
```
|
|
84
|
+
litellm-lint check [--env-file PATH] [--no-os-env] [--strict] [--ignore CODES] [--format {text,json}] config [config ...]
|
|
85
|
+
litellm-lint schema [-o PATH]
|
|
86
|
+
litellm-lint --version
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
| 명령·옵션 | 하는 일 | 예 |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `check <config> [more ...]` | 설정을 검사하고 지적을 출력. 파일 여러 개 가능 | `litellm-lint check a.yaml b.yaml` |
|
|
92
|
+
| `--env-file PATH` | dotenv 파일에 적힌 **이름**을 "정의됨"으로 침(여러 번 가능) | `--env-file .env.prod` |
|
|
93
|
+
| `--no-os-env` | 지금 셸의 환경 변수는 정의된 것으로 치지 않음 | CI 에서 `.env` 만 기준으로 볼 때 |
|
|
94
|
+
| `--strict` | 경고에도 종료 코드 1 | `--strict` |
|
|
95
|
+
| `--ignore CODES` | 쉼표로 구분한 규칙 코드를 건너뜀 | `--ignore LL001,LL402` |
|
|
96
|
+
| `--format json` | 기계가 읽는 JSON 출력(파일이 여러 개면 파일별 객체의 배열) | `--format json` |
|
|
97
|
+
| `schema -o PATH` | 편집기용 JSON Schema(Draft 2020-12) 내보내기 | `schema -o litellm.schema.json` |
|
|
98
|
+
|
|
99
|
+
종료 코드: `0` 문제 없음(또는 경고만), `1` 오류 있음(`--strict` 면 경고 포함), `2` 사용법 오류 또는 입력을 읽을 수 없음(YAML 구문 오류, 없거나 깨진 `include` 파일, 너무 깊거나 큰 입력 = LL900). 파일이 여러 개면 가장 나쁜 값(2 > 1 > 0)이 종료 코드입니다.
|
|
100
|
+
|
|
101
|
+
파일을 여러 개 주면 헤더는 한 번만 나오고, 파일마다 지적과 요약 줄, 마지막에 `total` 줄이 붙습니다.
|
|
102
|
+
```bash
|
|
103
|
+
uv run litellm-lint check examples/good_config.yaml examples/bad_config.yaml --env-file examples/.env.example
|
|
104
|
+
```
|
|
105
|
+
```
|
|
106
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
107
|
+
examples/good_config.yaml: 0 errors, 0 warnings
|
|
108
|
+
examples/bad_config.yaml:7:16: error LL201 environment variable 'OPENAI_API_KEYY' not found in: examples/.env.example, process environment (did you mean 'OPENAI_API_KEY'?)
|
|
109
|
+
examples/bad_config.yaml:17:7: warning LL001 unknown key 'api_bse' in litellm_params (did you mean 'api_base'?)
|
|
110
|
+
examples/bad_config.yaml:20:3: error LL001 unknown key 'num_retires' in router_settings (did you mean 'num_retries'?)
|
|
111
|
+
examples/bad_config.yaml:22:18: error LL101 fallback target 'gpt-backup' in router_settings.fallbacks is not a model_name in model_list
|
|
112
|
+
examples/bad_config.yaml:24:3: error LL001 unknown key 'drop_parms' in litellm_settings (did you mean 'drop_params'?)
|
|
113
|
+
examples/bad_config.yaml:26:21: error LL101 fallback target 'nope-model' in litellm_settings.context_window_fallbacks is not a model_name in model_list
|
|
114
|
+
examples/bad_config.yaml:29:3: warning LL001 unknown key 'maser_key_typo' in general_settings: not in the litellm 1.108.4 snapshot (may be a newer setting, or a typo)
|
|
115
|
+
examples/bad_config.yaml: 5 errors, 2 warnings
|
|
116
|
+
total: 2 files, 5 errors, 2 warnings
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**시나리오 1 — 배포 파이프라인에서 막기.** `.env` 가 없는 CI 에서는 `--no-os-env --env-file deploy.env.example` 처럼 "배포 환경에 있어야 할 변수 이름 목록"을 기준으로 삼습니다. 아래는 `--ignore LL001` 로 오타 규칙을 끄고 환경 변수를 하나도 주지 않은 경우입니다.
|
|
120
|
+
```bash
|
|
121
|
+
uv run litellm-lint check examples/bad_config.yaml --no-os-env --ignore LL001
|
|
122
|
+
```
|
|
123
|
+
```
|
|
124
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
125
|
+
examples/bad_config.yaml:7:16: error LL201 environment variable 'OPENAI_API_KEYY' not found in: no sources
|
|
126
|
+
examples/bad_config.yaml:12:16: error LL201 environment variable 'OPENAI_API_KEY' not found in: no sources
|
|
127
|
+
examples/bad_config.yaml:22:18: error LL101 fallback target 'gpt-backup' in router_settings.fallbacks is not a model_name in model_list
|
|
128
|
+
examples/bad_config.yaml:26:21: error LL101 fallback target 'nope-model' in litellm_settings.context_window_fallbacks is not a model_name in model_list
|
|
129
|
+
examples/bad_config.yaml:28:15: error LL201 environment variable 'LITELLM_MASTER_KEY' not found in: no sources
|
|
130
|
+
5 errors, 0 warnings
|
|
131
|
+
```
|
|
132
|
+
정의된 환경 변수가 하나도 없으니 `os.environ/` 로 참조한 이름 3곳이 모두 LL201 로 잡힙니다.
|
|
133
|
+
|
|
134
|
+
**시나리오 2 — JSON 으로 다른 도구에 넘기기.** `--format json` 은 (파일 하나면 객체 하나, 여러 개면 객체의 배열로) `tool`, `version`, `snapshot`, `file`, `summary`, `diagnostics[]`(code, severity, message, file, line, column, key, suggestion)를 냅니다.
|
|
135
|
+
```bash
|
|
136
|
+
uv run litellm-lint check examples/good_config.yaml --env-file examples/.env.example --format json
|
|
137
|
+
```
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"tool": "litellm-lint",
|
|
141
|
+
"version": "0.1.0",
|
|
142
|
+
"snapshot": {
|
|
143
|
+
"litellm_version": "1.108.4",
|
|
144
|
+
"generated_at": "2026-11-10"
|
|
145
|
+
},
|
|
146
|
+
"file": "examples/good_config.yaml",
|
|
147
|
+
"summary": {
|
|
148
|
+
"errors": 0,
|
|
149
|
+
"warnings": 0,
|
|
150
|
+
"info": 0
|
|
151
|
+
},
|
|
152
|
+
"diagnostics": []
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**시나리오 3 — 편집기에서 바로 보기.** `litellm-lint schema -o litellm.schema.json` 으로 JSON Schema 를 만들어 YAML 편집기(예: VS Code 의 YAML 확장)에 연결하면 키 이름과 타입 오류를 저장 전에 볼 수 있습니다. 폴백·별칭·환경 변수 같은 **참조 검사는 스키마로 표현할 수 없어** `check` 에서만 됩니다.
|
|
157
|
+
|
|
158
|
+
**시나리오 4 — pre-commit.** 이 레포는 `.pre-commit-hooks.yaml` 을 제공합니다. 파일 이름이 `config*.yaml` 인 것만 검사하고, 한 번에 바뀐 파일을 모두 받습니다. 개발자 셸에는 API 키가 없는 경우가 많으므로, 아래처럼 `--no-os-env --env-file` 로 "배포 환경에 있어야 할 변수 이름 목록"(`deploy.env.example`, 이름만 적은 dotenv 파일)을 기준으로 삼으면 `os.environ/` 참조가 LL201 로 커밋을 막지 않습니다.
|
|
159
|
+
```yaml
|
|
160
|
+
repos:
|
|
161
|
+
- repo: https://github.com/LeeGyeongPil/litellm-lint
|
|
162
|
+
rev: v0.1.0
|
|
163
|
+
hooks:
|
|
164
|
+
- id: litellm-lint
|
|
165
|
+
args: [--no-os-env, --env-file, deploy.env.example]
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Python 에서.** 공개 API 는 `check_file`, `export_schema`, `Diagnostic`, `Report`, `Severity`, `LintUsageError` 입니다.
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from litellm_lint import check_file
|
|
172
|
+
|
|
173
|
+
report = check_file("examples/bad_config.yaml", env_files=["examples/.env.example"], use_os_env=False)
|
|
174
|
+
for d in sorted(report.diagnostics, key=lambda d: (d.line or 0, d.code)):
|
|
175
|
+
print(d.line, d.code, d.message)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`report.diagnostics` 는 줄 번호 순으로 정렬되어 있지 않아서 위처럼 직접 정렬합니다. 출력은 7건이며 첫 줄은 다음과 같습니다(위 `check` 결과와 같은 지적).
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
7 LL201 environment variable 'OPENAI_API_KEYY' not found in: examples/.env.example (did you mean 'OPENAI_API_KEY'?)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 설정
|
|
185
|
+
설정 파일은 따로 없습니다. 동작은 위 옵션으로만 정합니다.
|
|
186
|
+
- 환경 변수 **값은 읽어도 출력하지 않습니다.** 이름만 확인합니다. `examples/.env.example` 은 가짜 값이 든 예시이고, 도구는 그 안의 이름만 봅니다.
|
|
187
|
+
- LL201 은 `--env-file` 들, 설정 안의 `environment_variables`, (`--no-os-env` 를 주지 않았다면) 현재 프로세스 환경 순으로 이름을 찾습니다.
|
|
188
|
+
- API 키가 필요 없습니다. litellm 도 설치할 필요가 없습니다.
|
|
189
|
+
|
|
190
|
+
## 규칙 코드
|
|
191
|
+
| 코드 | 기본 심각도 | 무엇을 잡나 |
|
|
192
|
+
|---|---|---|
|
|
193
|
+
| LL000 | info | 설치된 litellm 버전이 스냅숏(1.108.4)과 다름. 패키지 메타데이터만 읽고 litellm 을 import 하지 않음 |
|
|
194
|
+
| LL001 | error / warning / info | 모르는 키. 같은 섹션의 비슷한 키가 있거나 다른 섹션에 있는 키면 error + 제안, 비슷한 게 없으면 warning(새 버전 키일 수 있음). `litellm_params` 안에서는 제안이 있으면 warning, 없으면 info |
|
|
195
|
+
| LL002 | error | 타입·구조 오류(`num_retries: three`, `default_fallbacks: "gpt-main"`, 매핑이 아닌 섹션, 폴백 리스트 원소가 `{출발: [대상, ...]}` 모양이 아님, `include` 가 경로 리스트가 아님, 문자열이 아닌 최상위 키, `model_name`·`litellm_params`·`model` 이 없는 `model_list` 항목). `os.environ/NAME`·숫자 문자열·빈 값은 허용 |
|
|
196
|
+
| LL003 | error | `router_settings` 에 둔 `health_check_interval`/`health_check_concurrency`. 프록시가 기동을 거부함, `general_settings` 로 옮길 것 |
|
|
197
|
+
| LL101 | error | `fallbacks`·`context_window_fallbacks`·`content_policy_fallbacks`·`default_fallbacks` 의 대상이 `model_name` 이 아님(와일드카드·별칭은 인정). `store_model_in_db: true` 이거나 `model_list` 가 비어 있으면 warning |
|
|
198
|
+
| LL102 | warning | 폴백의 출발 그룹이 `model_name` 이 아님(`"*"` 은 허용) |
|
|
199
|
+
| LL103 | error | `model_group_alias` 가 없는 그룹을 가리킴 |
|
|
200
|
+
| LL104 | warning | `model_group_retry_policy` 의 그룹이 `model_name` 이 아님 |
|
|
201
|
+
| LL201 | error | `os.environ/NAME` 이 어디에도 정의되지 않음. `key_management_system` 이 설정돼 있으면 info |
|
|
202
|
+
| LL202 | warning | `api_key`, `*_password`, `*_secret`, `*_token` 같은 키에 값을 직접 적음. 값은 출력하지 않음 |
|
|
203
|
+
| LL301 | error | `general_settings.master_key` 가 **비어 있거나 공개된 예시 키**. 우회 설정(`dangerously_permit_weak_or_unset_master_key: true`)이 있으면 warning |
|
|
204
|
+
| LL401 | warning | 앞의 배포와 `model_name`·`litellm_params` 가 완전히 같은 중복. 이름만 같고 파라미터가 다르면 로드밸런싱이라 지적하지 않음 |
|
|
205
|
+
| LL402 | warning / info | `litellm_params.model` 의 제공자 접두사가 litellm 제공자 목록에 없음. `custom_llm_provider` 가 있으면 건너뜀 |
|
|
206
|
+
| LL900 | error (종료 2) | 입력을 읽을 수 없음: YAML 구문 오류, 중첩 100단계 초과, 별칭 확장 후 50만 노드 초과(별칭 폭탄), 없거나 깨진 `include` 파일(체인 50개 초과 포함). 줄:열과 일반적인 설명만 출력하고 소스 줄은 출력하지 않음 |
|
|
207
|
+
|
|
208
|
+
LL301 은 **약한 키 전반이 아니라 두 경우만** 잡습니다. litellm 1.108.4 의 소스(`master_key_boot_check.py`)는 길이·복잡도 기준 없이 "비어 있음"과 "공개된 예시 키의 SHA-256 해시와 일치"만 거부하기 때문에, 그 기준에 맞췄습니다. `sk-1234` 가 아닌 짧은 키는 이 도구가 지적하지 않습니다.
|
|
209
|
+
|
|
210
|
+
자세한 규칙 설명은 [docs/rules.md](https://github.com/LeeGyeongPil/litellm-lint/blob/v0.1.0/docs/rules.md)(영어) 를 보세요.
|
|
211
|
+
|
|
212
|
+
## 동작 원리
|
|
213
|
+
```mermaid
|
|
214
|
+
flowchart LR
|
|
215
|
+
A[config.yaml] --> B[YAML 읽기<br/>줄·열 보존]
|
|
216
|
+
S[(스냅숏<br/>litellm 1.108.4)] --> C
|
|
217
|
+
B --> C[키·타입 검사<br/>LL001-003]
|
|
218
|
+
B --> D[참조 검사<br/>LL101-104]
|
|
219
|
+
B --> E[환경 변수 검사<br/>LL201-202]
|
|
220
|
+
E -. 이름만 .-> F[.env 파일 / 프로세스 환경]
|
|
221
|
+
C --> G[지적 모음]
|
|
222
|
+
D --> G
|
|
223
|
+
E --> G
|
|
224
|
+
G --> H[텍스트 / JSON 출력<br/>종료 코드 0·1·2]
|
|
225
|
+
```
|
|
226
|
+
- **YAML 읽기**: `ruamel.yaml` 로 읽어 모든 값의 줄·열을 기억하므로 지적에 위치가 붙습니다.
|
|
227
|
+
- **스냅숏**: 실제 litellm 1.108.4 를 설치해 `scripts/gen_snapshot.py` 로 뽑은 키 목록(JSON 파일)입니다. 검사할 때는 litellm 을 import 하지 않아 오프라인으로 빠릅니다.
|
|
228
|
+
- **키·타입 검사**: 섹션별(`router_settings`, `litellm_settings`, `general_settings`, `litellm_params`)로 키가 스냅숏에 있는지 보고, 비슷한 이름이 있으면 제안합니다.
|
|
229
|
+
- **참조 검사**: `model_list` 의 `model_name` 들이 "모델 그룹"입니다. 폴백·별칭·재시도 정책이 가리키는 이름이 그룹에 있는지 확인합니다. 같은 `model_name` 을 여러 번 적는 것은 로드밸런싱이라 정상입니다.
|
|
230
|
+
- **환경 변수 검사**: `os.environ/NAME` 의 NAME 이 정의돼 있는지만 봅니다.
|
|
231
|
+
|
|
232
|
+
## 지원 버전과 한계
|
|
233
|
+
- 키 목록은 **litellm 1.108.4**(2026-11-05~09 릴리스 구간) 기준입니다. 더 새 버전의 설정 키는 "스냅숏에 없음" 경고(LL001)로 나올 수 있고, 더 옛 버전에서 사라진 키는 알 수 없습니다. 설치된 litellm 이 다르면 LL000 info 가 나옵니다.
|
|
234
|
+
- **정적 검사입니다.** 프록시를 띄우지 않고, 제공자별 필수 파라미터는 확인하지 않습니다.
|
|
235
|
+
- `litellm_settings` 값의 타입은 검사하지 않습니다(그 값들은 litellm 이 그대로 대입하는 설정이라 오탐을 피하려고). 폴백 4종만 리스트 모양을 확인합니다.
|
|
236
|
+
- `include` 로 쪼갠 파일은 따라가며 거기 정의된 `model_name` 을 폴백·별칭 대상으로 인정합니다(포함 파일 자체는 검사하지 않고, 없거나 깨진 파일은 LL900). DB 에 저장된 모델은 지원하지 않습니다. DB 모델을 쓰면(`store_model_in_db: true`) 폴백 대상 검사는 error 대신 warning 입니다.
|
|
237
|
+
- 입력 상한: 중첩 100단계 초과, 별칭 확장 후 50만 노드 초과는 LL900(종료 2)로 거부합니다.
|
|
238
|
+
- Python 3.10, 3.12, 3.14 에서 테스트했습니다.
|
|
239
|
+
|
|
240
|
+
**스냅숏 다시 만들기** — 더 새 litellm 에 맞추려면 격리 환경에서 스냅숏을 새로 뽑습니다(레포를 clone 한 상태에서).
|
|
241
|
+
```bash
|
|
242
|
+
uv run --isolated --python 3.12 --with "litellm[proxy]==<버전>" python scripts/gen_snapshot.py --out src/litellm_lint/snapshots/
|
|
243
|
+
```
|
|
244
|
+
`LITELLM_LINT_ALLOW_LITELLM=1 PYTHONPATH=src python -m pytest tests/test_gen_snapshot.py` 로 생성 코드의 전체 테스트를 돌릴 수 있습니다(litellm 이 설치된 환경에서만).
|
|
245
|
+
|
|
246
|
+
## 언제 쓰나
|
|
247
|
+
- 이럴 때: 배포 전에 설정 파일의 오타·끊어진 참조·빠진 환경 변수를 파일 단위로(여러 개를 한 번에도 가능) 빠르게 확인하고 싶을 때.
|
|
248
|
+
- 이럴 땐 다른 도구: 실제로 프록시가 요청을 처리하는지 확인 → LiteLLM 의 [공식 문서](https://docs.litellm.ai/docs/proxy/configs) 의 기동·헬스 체크, 일반 YAML 문법만 검사 → [yamllint](https://github.com/adrienverge/yamllint).
|
|
249
|
+
|
|
250
|
+
## 자주 겪는 문제
|
|
251
|
+
| 증상 | 원인 | 해결 |
|
|
252
|
+
|---|---|---|
|
|
253
|
+
| `LL201 ... not found in: no sources` | `--no-os-env` 를 줬는데 `--env-file` 이 없음 | `--env-file` 로 이름 목록 파일을 주거나 `--no-os-env` 를 뺌 |
|
|
254
|
+
| 새 설정 키가 `LL001 warning` 으로 나옴 | 스냅숏(1.108.4)보다 새 버전의 키 | 스냅숏을 다시 만들거나 `--ignore LL001` |
|
|
255
|
+
| 종료 코드 2 와 `LL900` | YAML 구문 오류, 없거나 깨진 `include` 파일, 너무 깊거나 큰 입력 | 보고된 줄:열 근처의 들여쓰기·따옴표, `include` 경로 확인 |
|
|
256
|
+
| pre-commit 에서 `LL201` 로 커밋이 막힘 | 개발자 셸에 해당 환경 변수가 없음 | 훅 `args` 에 `--no-os-env --env-file deploy.env.example` 추가 |
|
|
257
|
+
| `LL202` 경고가 계속 나옴 | 키 값을 설정에 직접 적음 | `os.environ/NAME` 으로 바꿈 |
|
|
258
|
+
| 경고만 있는데 CI 가 통과함 | 기본은 오류만 실패 처리 | `--strict` |
|
|
259
|
+
|
|
260
|
+
## 개발·기여
|
|
261
|
+
```bash
|
|
262
|
+
git clone https://github.com/LeeGyeongPil/litellm-lint && cd litellm-lint
|
|
263
|
+
uv run pytest
|
|
264
|
+
```
|
|
265
|
+
```
|
|
266
|
+
42 passed, 1 skipped in 3.14s
|
|
267
|
+
```
|
|
268
|
+
건너뛴 1개는 litellm 이 있어야 하는 스냅숏 전체 생성 테스트입니다. 버그·제안은 이슈로 남겨 주세요. 변경 기록은 [CHANGELOG.md](https://github.com/LeeGyeongPil/litellm-lint/blob/v0.1.0/CHANGELOG.md).
|
|
269
|
+
|
|
270
|
+
## 라이선스
|
|
271
|
+
MIT. litellm 은 BerriAI 의 별도 프로젝트이며, 이 도구는 litellm 에서 설정 키 이름 목록만 추출해 내장합니다(litellm 코드는 포함하지 않음).
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# litellm-lint
|
|
2
|
+
|
|
3
|
+
> **English summary** — A static linter for LiteLLM proxy `config.yaml` files (unofficial, not affiliated with LiteLLM). It catches typo'd keys, missing `os.environ/` variables and fallbacks or aliases that point at a model that does not exist, before you deploy. Install: `uv tool install git+https://github.com/LeeGyeongPil/litellm-lint`, run: `litellm-lint check config.yaml`.
|
|
4
|
+
|
|
5
|
+
LiteLLM 프록시는 설정 파일의 오타를 조용히 넘기는 경우가 많습니다. 이 도구는 프록시를 띄우기 전에 `config.yaml` 을 읽어 그런 실수를 줄 번호와 함께 알려 줍니다. 프록시를 실행하지 않고, 네트워크도 쓰지 않고, 키 값도 읽어 출력하지 않습니다.
|
|
6
|
+
|
|
7
|
+
> 비공식 도구입니다. 검사 기준은 **litellm 1.108.4** 에서 뽑아 둔 스냅숏입니다(아래 "지원 버전과 한계").
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
*오타·없는 환경 변수 5건과 끊어진 폴백 2건을 줄 번호와 함께 보여 주는 `litellm-lint check` 출력*
|
|
11
|
+
|
|
12
|
+
## 이런 분께
|
|
13
|
+
- 배포 전에 `config.yaml` 을 CI 나 pre-commit 에서 자동으로 확인하고 싶을 때
|
|
14
|
+
- `num_retires` 같은 오타가 에러 없이 무시된 경험이 있을 때
|
|
15
|
+
- `fallbacks` 에 적은 모델 이름이 `model_list` 에 실제로 있는지 확인하고 싶을 때
|
|
16
|
+
- `os.environ/NAME` 으로 적은 환경 변수가 배포 환경에 정의돼 있는지 미리 보고 싶을 때
|
|
17
|
+
|
|
18
|
+
## 설치
|
|
19
|
+
```bash
|
|
20
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # uv 가 없다면 (Python 3.10 이상 필요)
|
|
21
|
+
uv tool install git+https://github.com/LeeGyeongPil/litellm-lint
|
|
22
|
+
litellm-lint --version
|
|
23
|
+
```
|
|
24
|
+
```
|
|
25
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4)
|
|
26
|
+
```
|
|
27
|
+
설치 없이 한 번만 돌려 보려면 `uvx --from git+https://github.com/LeeGyeongPil/litellm-lint litellm-lint check config.yaml`. 레포를 받아 직접 쓰려면 `git clone` 후 `uv run litellm-lint ...`. 최소 리눅스 이미지에는 `git` 과 `curl` 이 필요합니다.
|
|
28
|
+
|
|
29
|
+
## 빠르게 시작하기
|
|
30
|
+
레포의 예제로 바로 해 볼 수 있습니다.
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/LeeGyeongPil/litellm-lint && cd litellm-lint
|
|
33
|
+
uv run litellm-lint check examples/bad_config.yaml --env-file examples/.env.example
|
|
34
|
+
```
|
|
35
|
+
```
|
|
36
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
37
|
+
examples/bad_config.yaml:7:16: error LL201 environment variable 'OPENAI_API_KEYY' not found in: examples/.env.example, process environment (did you mean 'OPENAI_API_KEY'?)
|
|
38
|
+
examples/bad_config.yaml:17:7: warning LL001 unknown key 'api_bse' in litellm_params (did you mean 'api_base'?)
|
|
39
|
+
examples/bad_config.yaml:20:3: error LL001 unknown key 'num_retires' in router_settings (did you mean 'num_retries'?)
|
|
40
|
+
examples/bad_config.yaml:22:18: error LL101 fallback target 'gpt-backup' in router_settings.fallbacks is not a model_name in model_list
|
|
41
|
+
examples/bad_config.yaml:24:3: error LL001 unknown key 'drop_parms' in litellm_settings (did you mean 'drop_params'?)
|
|
42
|
+
examples/bad_config.yaml:26:21: error LL101 fallback target 'nope-model' in litellm_settings.context_window_fallbacks is not a model_name in model_list
|
|
43
|
+
examples/bad_config.yaml:29:3: warning LL001 unknown key 'maser_key_typo' in general_settings: not in the litellm 1.108.4 snapshot (may be a newer setting, or a typo)
|
|
44
|
+
5 errors, 2 warnings
|
|
45
|
+
```
|
|
46
|
+
각 줄은 `파일:줄:열: 심각도 규칙코드 메시지` 입니다. 종료 코드는 오류가 있으면 1 입니다. 문제없는 설정은 이렇게 끝납니다.
|
|
47
|
+
```bash
|
|
48
|
+
uv run litellm-lint check examples/good_config.yaml --env-file examples/.env.example
|
|
49
|
+
```
|
|
50
|
+
```
|
|
51
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
52
|
+
0 errors, 0 warnings
|
|
53
|
+
```
|
|
54
|
+

|
|
55
|
+
*오류도 경고도 없으면 종료 코드 0*
|
|
56
|
+
|
|
57
|
+
## 사용법
|
|
58
|
+
```
|
|
59
|
+
litellm-lint check [--env-file PATH] [--no-os-env] [--strict] [--ignore CODES] [--format {text,json}] config [config ...]
|
|
60
|
+
litellm-lint schema [-o PATH]
|
|
61
|
+
litellm-lint --version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| 명령·옵션 | 하는 일 | 예 |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `check <config> [more ...]` | 설정을 검사하고 지적을 출력. 파일 여러 개 가능 | `litellm-lint check a.yaml b.yaml` |
|
|
67
|
+
| `--env-file PATH` | dotenv 파일에 적힌 **이름**을 "정의됨"으로 침(여러 번 가능) | `--env-file .env.prod` |
|
|
68
|
+
| `--no-os-env` | 지금 셸의 환경 변수는 정의된 것으로 치지 않음 | CI 에서 `.env` 만 기준으로 볼 때 |
|
|
69
|
+
| `--strict` | 경고에도 종료 코드 1 | `--strict` |
|
|
70
|
+
| `--ignore CODES` | 쉼표로 구분한 규칙 코드를 건너뜀 | `--ignore LL001,LL402` |
|
|
71
|
+
| `--format json` | 기계가 읽는 JSON 출력(파일이 여러 개면 파일별 객체의 배열) | `--format json` |
|
|
72
|
+
| `schema -o PATH` | 편집기용 JSON Schema(Draft 2020-12) 내보내기 | `schema -o litellm.schema.json` |
|
|
73
|
+
|
|
74
|
+
종료 코드: `0` 문제 없음(또는 경고만), `1` 오류 있음(`--strict` 면 경고 포함), `2` 사용법 오류 또는 입력을 읽을 수 없음(YAML 구문 오류, 없거나 깨진 `include` 파일, 너무 깊거나 큰 입력 = LL900). 파일이 여러 개면 가장 나쁜 값(2 > 1 > 0)이 종료 코드입니다.
|
|
75
|
+
|
|
76
|
+
파일을 여러 개 주면 헤더는 한 번만 나오고, 파일마다 지적과 요약 줄, 마지막에 `total` 줄이 붙습니다.
|
|
77
|
+
```bash
|
|
78
|
+
uv run litellm-lint check examples/good_config.yaml examples/bad_config.yaml --env-file examples/.env.example
|
|
79
|
+
```
|
|
80
|
+
```
|
|
81
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
82
|
+
examples/good_config.yaml: 0 errors, 0 warnings
|
|
83
|
+
examples/bad_config.yaml:7:16: error LL201 environment variable 'OPENAI_API_KEYY' not found in: examples/.env.example, process environment (did you mean 'OPENAI_API_KEY'?)
|
|
84
|
+
examples/bad_config.yaml:17:7: warning LL001 unknown key 'api_bse' in litellm_params (did you mean 'api_base'?)
|
|
85
|
+
examples/bad_config.yaml:20:3: error LL001 unknown key 'num_retires' in router_settings (did you mean 'num_retries'?)
|
|
86
|
+
examples/bad_config.yaml:22:18: error LL101 fallback target 'gpt-backup' in router_settings.fallbacks is not a model_name in model_list
|
|
87
|
+
examples/bad_config.yaml:24:3: error LL001 unknown key 'drop_parms' in litellm_settings (did you mean 'drop_params'?)
|
|
88
|
+
examples/bad_config.yaml:26:21: error LL101 fallback target 'nope-model' in litellm_settings.context_window_fallbacks is not a model_name in model_list
|
|
89
|
+
examples/bad_config.yaml:29:3: warning LL001 unknown key 'maser_key_typo' in general_settings: not in the litellm 1.108.4 snapshot (may be a newer setting, or a typo)
|
|
90
|
+
examples/bad_config.yaml: 5 errors, 2 warnings
|
|
91
|
+
total: 2 files, 5 errors, 2 warnings
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**시나리오 1 — 배포 파이프라인에서 막기.** `.env` 가 없는 CI 에서는 `--no-os-env --env-file deploy.env.example` 처럼 "배포 환경에 있어야 할 변수 이름 목록"을 기준으로 삼습니다. 아래는 `--ignore LL001` 로 오타 규칙을 끄고 환경 변수를 하나도 주지 않은 경우입니다.
|
|
95
|
+
```bash
|
|
96
|
+
uv run litellm-lint check examples/bad_config.yaml --no-os-env --ignore LL001
|
|
97
|
+
```
|
|
98
|
+
```
|
|
99
|
+
litellm-lint 0.1.0 (schema snapshot: litellm 1.108.4, generated 2026-11-10)
|
|
100
|
+
examples/bad_config.yaml:7:16: error LL201 environment variable 'OPENAI_API_KEYY' not found in: no sources
|
|
101
|
+
examples/bad_config.yaml:12:16: error LL201 environment variable 'OPENAI_API_KEY' not found in: no sources
|
|
102
|
+
examples/bad_config.yaml:22:18: error LL101 fallback target 'gpt-backup' in router_settings.fallbacks is not a model_name in model_list
|
|
103
|
+
examples/bad_config.yaml:26:21: error LL101 fallback target 'nope-model' in litellm_settings.context_window_fallbacks is not a model_name in model_list
|
|
104
|
+
examples/bad_config.yaml:28:15: error LL201 environment variable 'LITELLM_MASTER_KEY' not found in: no sources
|
|
105
|
+
5 errors, 0 warnings
|
|
106
|
+
```
|
|
107
|
+
정의된 환경 변수가 하나도 없으니 `os.environ/` 로 참조한 이름 3곳이 모두 LL201 로 잡힙니다.
|
|
108
|
+
|
|
109
|
+
**시나리오 2 — JSON 으로 다른 도구에 넘기기.** `--format json` 은 (파일 하나면 객체 하나, 여러 개면 객체의 배열로) `tool`, `version`, `snapshot`, `file`, `summary`, `diagnostics[]`(code, severity, message, file, line, column, key, suggestion)를 냅니다.
|
|
110
|
+
```bash
|
|
111
|
+
uv run litellm-lint check examples/good_config.yaml --env-file examples/.env.example --format json
|
|
112
|
+
```
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"tool": "litellm-lint",
|
|
116
|
+
"version": "0.1.0",
|
|
117
|
+
"snapshot": {
|
|
118
|
+
"litellm_version": "1.108.4",
|
|
119
|
+
"generated_at": "2026-11-10"
|
|
120
|
+
},
|
|
121
|
+
"file": "examples/good_config.yaml",
|
|
122
|
+
"summary": {
|
|
123
|
+
"errors": 0,
|
|
124
|
+
"warnings": 0,
|
|
125
|
+
"info": 0
|
|
126
|
+
},
|
|
127
|
+
"diagnostics": []
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**시나리오 3 — 편집기에서 바로 보기.** `litellm-lint schema -o litellm.schema.json` 으로 JSON Schema 를 만들어 YAML 편집기(예: VS Code 의 YAML 확장)에 연결하면 키 이름과 타입 오류를 저장 전에 볼 수 있습니다. 폴백·별칭·환경 변수 같은 **참조 검사는 스키마로 표현할 수 없어** `check` 에서만 됩니다.
|
|
132
|
+
|
|
133
|
+
**시나리오 4 — pre-commit.** 이 레포는 `.pre-commit-hooks.yaml` 을 제공합니다. 파일 이름이 `config*.yaml` 인 것만 검사하고, 한 번에 바뀐 파일을 모두 받습니다. 개발자 셸에는 API 키가 없는 경우가 많으므로, 아래처럼 `--no-os-env --env-file` 로 "배포 환경에 있어야 할 변수 이름 목록"(`deploy.env.example`, 이름만 적은 dotenv 파일)을 기준으로 삼으면 `os.environ/` 참조가 LL201 로 커밋을 막지 않습니다.
|
|
134
|
+
```yaml
|
|
135
|
+
repos:
|
|
136
|
+
- repo: https://github.com/LeeGyeongPil/litellm-lint
|
|
137
|
+
rev: v0.1.0
|
|
138
|
+
hooks:
|
|
139
|
+
- id: litellm-lint
|
|
140
|
+
args: [--no-os-env, --env-file, deploy.env.example]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Python 에서.** 공개 API 는 `check_file`, `export_schema`, `Diagnostic`, `Report`, `Severity`, `LintUsageError` 입니다.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from litellm_lint import check_file
|
|
147
|
+
|
|
148
|
+
report = check_file("examples/bad_config.yaml", env_files=["examples/.env.example"], use_os_env=False)
|
|
149
|
+
for d in sorted(report.diagnostics, key=lambda d: (d.line or 0, d.code)):
|
|
150
|
+
print(d.line, d.code, d.message)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`report.diagnostics` 는 줄 번호 순으로 정렬되어 있지 않아서 위처럼 직접 정렬합니다. 출력은 7건이며 첫 줄은 다음과 같습니다(위 `check` 결과와 같은 지적).
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
7 LL201 environment variable 'OPENAI_API_KEYY' not found in: examples/.env.example (did you mean 'OPENAI_API_KEY'?)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 설정
|
|
160
|
+
설정 파일은 따로 없습니다. 동작은 위 옵션으로만 정합니다.
|
|
161
|
+
- 환경 변수 **값은 읽어도 출력하지 않습니다.** 이름만 확인합니다. `examples/.env.example` 은 가짜 값이 든 예시이고, 도구는 그 안의 이름만 봅니다.
|
|
162
|
+
- LL201 은 `--env-file` 들, 설정 안의 `environment_variables`, (`--no-os-env` 를 주지 않았다면) 현재 프로세스 환경 순으로 이름을 찾습니다.
|
|
163
|
+
- API 키가 필요 없습니다. litellm 도 설치할 필요가 없습니다.
|
|
164
|
+
|
|
165
|
+
## 규칙 코드
|
|
166
|
+
| 코드 | 기본 심각도 | 무엇을 잡나 |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| LL000 | info | 설치된 litellm 버전이 스냅숏(1.108.4)과 다름. 패키지 메타데이터만 읽고 litellm 을 import 하지 않음 |
|
|
169
|
+
| LL001 | error / warning / info | 모르는 키. 같은 섹션의 비슷한 키가 있거나 다른 섹션에 있는 키면 error + 제안, 비슷한 게 없으면 warning(새 버전 키일 수 있음). `litellm_params` 안에서는 제안이 있으면 warning, 없으면 info |
|
|
170
|
+
| LL002 | error | 타입·구조 오류(`num_retries: three`, `default_fallbacks: "gpt-main"`, 매핑이 아닌 섹션, 폴백 리스트 원소가 `{출발: [대상, ...]}` 모양이 아님, `include` 가 경로 리스트가 아님, 문자열이 아닌 최상위 키, `model_name`·`litellm_params`·`model` 이 없는 `model_list` 항목). `os.environ/NAME`·숫자 문자열·빈 값은 허용 |
|
|
171
|
+
| LL003 | error | `router_settings` 에 둔 `health_check_interval`/`health_check_concurrency`. 프록시가 기동을 거부함, `general_settings` 로 옮길 것 |
|
|
172
|
+
| LL101 | error | `fallbacks`·`context_window_fallbacks`·`content_policy_fallbacks`·`default_fallbacks` 의 대상이 `model_name` 이 아님(와일드카드·별칭은 인정). `store_model_in_db: true` 이거나 `model_list` 가 비어 있으면 warning |
|
|
173
|
+
| LL102 | warning | 폴백의 출발 그룹이 `model_name` 이 아님(`"*"` 은 허용) |
|
|
174
|
+
| LL103 | error | `model_group_alias` 가 없는 그룹을 가리킴 |
|
|
175
|
+
| LL104 | warning | `model_group_retry_policy` 의 그룹이 `model_name` 이 아님 |
|
|
176
|
+
| LL201 | error | `os.environ/NAME` 이 어디에도 정의되지 않음. `key_management_system` 이 설정돼 있으면 info |
|
|
177
|
+
| LL202 | warning | `api_key`, `*_password`, `*_secret`, `*_token` 같은 키에 값을 직접 적음. 값은 출력하지 않음 |
|
|
178
|
+
| LL301 | error | `general_settings.master_key` 가 **비어 있거나 공개된 예시 키**. 우회 설정(`dangerously_permit_weak_or_unset_master_key: true`)이 있으면 warning |
|
|
179
|
+
| LL401 | warning | 앞의 배포와 `model_name`·`litellm_params` 가 완전히 같은 중복. 이름만 같고 파라미터가 다르면 로드밸런싱이라 지적하지 않음 |
|
|
180
|
+
| LL402 | warning / info | `litellm_params.model` 의 제공자 접두사가 litellm 제공자 목록에 없음. `custom_llm_provider` 가 있으면 건너뜀 |
|
|
181
|
+
| LL900 | error (종료 2) | 입력을 읽을 수 없음: YAML 구문 오류, 중첩 100단계 초과, 별칭 확장 후 50만 노드 초과(별칭 폭탄), 없거나 깨진 `include` 파일(체인 50개 초과 포함). 줄:열과 일반적인 설명만 출력하고 소스 줄은 출력하지 않음 |
|
|
182
|
+
|
|
183
|
+
LL301 은 **약한 키 전반이 아니라 두 경우만** 잡습니다. litellm 1.108.4 의 소스(`master_key_boot_check.py`)는 길이·복잡도 기준 없이 "비어 있음"과 "공개된 예시 키의 SHA-256 해시와 일치"만 거부하기 때문에, 그 기준에 맞췄습니다. `sk-1234` 가 아닌 짧은 키는 이 도구가 지적하지 않습니다.
|
|
184
|
+
|
|
185
|
+
자세한 규칙 설명은 [docs/rules.md](https://github.com/LeeGyeongPil/litellm-lint/blob/v0.1.0/docs/rules.md)(영어) 를 보세요.
|
|
186
|
+
|
|
187
|
+
## 동작 원리
|
|
188
|
+
```mermaid
|
|
189
|
+
flowchart LR
|
|
190
|
+
A[config.yaml] --> B[YAML 읽기<br/>줄·열 보존]
|
|
191
|
+
S[(스냅숏<br/>litellm 1.108.4)] --> C
|
|
192
|
+
B --> C[키·타입 검사<br/>LL001-003]
|
|
193
|
+
B --> D[참조 검사<br/>LL101-104]
|
|
194
|
+
B --> E[환경 변수 검사<br/>LL201-202]
|
|
195
|
+
E -. 이름만 .-> F[.env 파일 / 프로세스 환경]
|
|
196
|
+
C --> G[지적 모음]
|
|
197
|
+
D --> G
|
|
198
|
+
E --> G
|
|
199
|
+
G --> H[텍스트 / JSON 출력<br/>종료 코드 0·1·2]
|
|
200
|
+
```
|
|
201
|
+
- **YAML 읽기**: `ruamel.yaml` 로 읽어 모든 값의 줄·열을 기억하므로 지적에 위치가 붙습니다.
|
|
202
|
+
- **스냅숏**: 실제 litellm 1.108.4 를 설치해 `scripts/gen_snapshot.py` 로 뽑은 키 목록(JSON 파일)입니다. 검사할 때는 litellm 을 import 하지 않아 오프라인으로 빠릅니다.
|
|
203
|
+
- **키·타입 검사**: 섹션별(`router_settings`, `litellm_settings`, `general_settings`, `litellm_params`)로 키가 스냅숏에 있는지 보고, 비슷한 이름이 있으면 제안합니다.
|
|
204
|
+
- **참조 검사**: `model_list` 의 `model_name` 들이 "모델 그룹"입니다. 폴백·별칭·재시도 정책이 가리키는 이름이 그룹에 있는지 확인합니다. 같은 `model_name` 을 여러 번 적는 것은 로드밸런싱이라 정상입니다.
|
|
205
|
+
- **환경 변수 검사**: `os.environ/NAME` 의 NAME 이 정의돼 있는지만 봅니다.
|
|
206
|
+
|
|
207
|
+
## 지원 버전과 한계
|
|
208
|
+
- 키 목록은 **litellm 1.108.4**(2026-11-05~09 릴리스 구간) 기준입니다. 더 새 버전의 설정 키는 "스냅숏에 없음" 경고(LL001)로 나올 수 있고, 더 옛 버전에서 사라진 키는 알 수 없습니다. 설치된 litellm 이 다르면 LL000 info 가 나옵니다.
|
|
209
|
+
- **정적 검사입니다.** 프록시를 띄우지 않고, 제공자별 필수 파라미터는 확인하지 않습니다.
|
|
210
|
+
- `litellm_settings` 값의 타입은 검사하지 않습니다(그 값들은 litellm 이 그대로 대입하는 설정이라 오탐을 피하려고). 폴백 4종만 리스트 모양을 확인합니다.
|
|
211
|
+
- `include` 로 쪼갠 파일은 따라가며 거기 정의된 `model_name` 을 폴백·별칭 대상으로 인정합니다(포함 파일 자체는 검사하지 않고, 없거나 깨진 파일은 LL900). DB 에 저장된 모델은 지원하지 않습니다. DB 모델을 쓰면(`store_model_in_db: true`) 폴백 대상 검사는 error 대신 warning 입니다.
|
|
212
|
+
- 입력 상한: 중첩 100단계 초과, 별칭 확장 후 50만 노드 초과는 LL900(종료 2)로 거부합니다.
|
|
213
|
+
- Python 3.10, 3.12, 3.14 에서 테스트했습니다.
|
|
214
|
+
|
|
215
|
+
**스냅숏 다시 만들기** — 더 새 litellm 에 맞추려면 격리 환경에서 스냅숏을 새로 뽑습니다(레포를 clone 한 상태에서).
|
|
216
|
+
```bash
|
|
217
|
+
uv run --isolated --python 3.12 --with "litellm[proxy]==<버전>" python scripts/gen_snapshot.py --out src/litellm_lint/snapshots/
|
|
218
|
+
```
|
|
219
|
+
`LITELLM_LINT_ALLOW_LITELLM=1 PYTHONPATH=src python -m pytest tests/test_gen_snapshot.py` 로 생성 코드의 전체 테스트를 돌릴 수 있습니다(litellm 이 설치된 환경에서만).
|
|
220
|
+
|
|
221
|
+
## 언제 쓰나
|
|
222
|
+
- 이럴 때: 배포 전에 설정 파일의 오타·끊어진 참조·빠진 환경 변수를 파일 단위로(여러 개를 한 번에도 가능) 빠르게 확인하고 싶을 때.
|
|
223
|
+
- 이럴 땐 다른 도구: 실제로 프록시가 요청을 처리하는지 확인 → LiteLLM 의 [공식 문서](https://docs.litellm.ai/docs/proxy/configs) 의 기동·헬스 체크, 일반 YAML 문법만 검사 → [yamllint](https://github.com/adrienverge/yamllint).
|
|
224
|
+
|
|
225
|
+
## 자주 겪는 문제
|
|
226
|
+
| 증상 | 원인 | 해결 |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| `LL201 ... not found in: no sources` | `--no-os-env` 를 줬는데 `--env-file` 이 없음 | `--env-file` 로 이름 목록 파일을 주거나 `--no-os-env` 를 뺌 |
|
|
229
|
+
| 새 설정 키가 `LL001 warning` 으로 나옴 | 스냅숏(1.108.4)보다 새 버전의 키 | 스냅숏을 다시 만들거나 `--ignore LL001` |
|
|
230
|
+
| 종료 코드 2 와 `LL900` | YAML 구문 오류, 없거나 깨진 `include` 파일, 너무 깊거나 큰 입력 | 보고된 줄:열 근처의 들여쓰기·따옴표, `include` 경로 확인 |
|
|
231
|
+
| pre-commit 에서 `LL201` 로 커밋이 막힘 | 개발자 셸에 해당 환경 변수가 없음 | 훅 `args` 에 `--no-os-env --env-file deploy.env.example` 추가 |
|
|
232
|
+
| `LL202` 경고가 계속 나옴 | 키 값을 설정에 직접 적음 | `os.environ/NAME` 으로 바꿈 |
|
|
233
|
+
| 경고만 있는데 CI 가 통과함 | 기본은 오류만 실패 처리 | `--strict` |
|
|
234
|
+
|
|
235
|
+
## 개발·기여
|
|
236
|
+
```bash
|
|
237
|
+
git clone https://github.com/LeeGyeongPil/litellm-lint && cd litellm-lint
|
|
238
|
+
uv run pytest
|
|
239
|
+
```
|
|
240
|
+
```
|
|
241
|
+
42 passed, 1 skipped in 3.14s
|
|
242
|
+
```
|
|
243
|
+
건너뛴 1개는 litellm 이 있어야 하는 스냅숏 전체 생성 테스트입니다. 버그·제안은 이슈로 남겨 주세요. 변경 기록은 [CHANGELOG.md](https://github.com/LeeGyeongPil/litellm-lint/blob/v0.1.0/CHANGELOG.md).
|
|
244
|
+
|
|
245
|
+
## 라이선스
|
|
246
|
+
MIT. litellm 은 BerriAI 의 별도 프로젝트이며, 이 도구는 litellm 에서 설정 키 이름 목록만 추출해 내장합니다(litellm 코드는 포함하지 않음).
|
|
Binary file
|
|
Binary file
|