diff --git a/Dockerfile b/Dockerfile index 62f02ca..a37d1ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,8 +39,8 @@ RUN apt-get update \ WORKDIR /app -COPY requirements.txt . -RUN pip install --user --no-cache-dir -r requirements.txt +COPY requirements.txt requirements.lock ./ +RUN pip install --user --no-cache-dir -r requirements.lock # === Stage 2: Runtime === FROM python:3.12-slim AS runtime diff --git a/docs/deploy-guide.md b/docs/deploy-guide.md index a95d740..324812a 100644 --- a/docs/deploy-guide.md +++ b/docs/deploy-guide.md @@ -29,6 +29,12 @@ bash /a0/usr/projects/leocrm/scripts/fast-deploy.sh full 2. `git add -A && git commit -m '...' && git push origin main` 3. Dann deploy +## Dependencies aendern (Lockfile) +- requirements.txt = gewuenschte Ranges; requirements.lock = exakt getestetes Set +- Nach jeder Aenderung an requirements.txt: `pip install pip-tools && pip-compile requirements.txt -o requirements.lock` +- Lock-Diff reviewen (welche transitiven Versionen ziehen die neuen Ranges?) +- CI-Gate auditiert das LOCK: `pip-audit -r requirements.lock --strict --no-deps` + ## Container-Info - Coolify App UUID: xf7smknlger3hvkrsb910tui (neu erstellt 2026-08-06) - Container-Name aendert sich bei jedem Coolify-Deploy (Suffix) diff --git a/requirements.lock b/requirements.lock new file mode 100644 index 0000000..1bff0ed --- /dev/null +++ b/requirements.lock @@ -0,0 +1,328 @@ +# LeoCRM dependency lockfile — EXACT tested set +# Regenerate after changing requirements.txt: +# pip install pip-tools && pip-compile requirements.txt -o requirements.lock +# Audit gate: pip-audit -r requirements.lock --strict --no-deps + +aiofiles==25.1.0 + # via -r requirements.txt +aiohappyeyeballs==2.7.1 + # via aiohttp +aiohttp==3.14.3 + # via litellm +aioimaplib==2.0.1 + # via -r requirements.txt +aiosignal==1.4.0 + # via aiohttp +aiosmtplib==5.1.2 + # via -r requirements.txt +alembic==1.19.1 + # via -r requirements.txt +annotated-doc==0.0.5 + # via fastapi +annotated-types==0.8.0 + # via pydantic +anyio==4.14.2 + # via + # httpx + # openai + # starlette + # watchfiles +argon2-cffi==25.1.0 + # via minio +argon2-cffi-bindings==26.1.0 + # via argon2-cffi +arq==0.28.0 + # via -r requirements.txt +asyncpg==0.31.0 + # via -r requirements.txt +attrs==26.1.0 + # via + # aiohttp + # jsonschema + # referencing +bcrypt==4.0.1 + # via + # -r requirements.txt + # passlib +boto3==1.43.80 + # via litellm +botocore==1.43.80 + # via + # boto3 + # s3transfer +brotli==1.2.0 + # via fonttools +certifi==2026.7.22 + # via + # httpcore + # httpx + # minio + # requests +cffi==2.1.1 + # via + # argon2-cffi-bindings + # cryptography + # weasyprint +charset-normalizer==3.5.1 + # via requests +click==8.4.2 + # via + # arq + # huggingface-hub + # litellm + # uvicorn +croniter==6.2.4 + # via -r requirements.txt +cryptography==50.0.1 + # via + # -r requirements.txt + # pgpy +cssselect2==0.9.0 + # via weasyprint +distro==1.9.0 + # via openai +dnspython==2.8.0 + # via email-validator +email-validator==2.3.0 + # via -r requirements.txt +et-xmlfile==2.0.0 + # via openpyxl +fastapi==0.141.1 + # via -r requirements.txt +fastuuid==0.14.0 + # via litellm +filelock==3.32.4 + # via huggingface-hub +fonttools[woff]==4.63.0 + # via weasyprint +frozenlist==1.8.0 + # via + # aiohttp + # aiosignal +fsspec==2026.7.0 + # via huggingface-hub +greenlet==3.5.5 + # via -r requirements.txt +h11==0.16.0 + # via + # httpcore + # uvicorn +hf-xet==1.6.0 + # via huggingface-hub +hiredis==3.4.1 + # via redis +httpcore==1.0.9 + # via httpx +httptools==0.8.0 + # via uvicorn +httpx==0.28.1 + # via + # -r requirements.txt + # huggingface-hub + # litellm + # openai +huggingface-hub==1.28.0 + # via tokenizers +idna==3.19 + # via + # anyio + # email-validator + # httpx + # requests + # yarl +importlib-metadata==8.9.0 + # via litellm +jinja2==3.1.6 + # via + # -r requirements.txt + # litellm +jiter==0.16.0 + # via openai +jmespath==1.1.0 + # via + # boto3 + # botocore +jsonschema==4.26.0 + # via litellm +jsonschema-specifications==2025.9.1 + # via jsonschema +litellm==1.98.0 + # via -r requirements.txt +lxml==6.1.2 + # via + # python-docx + # python-pptx +mako==1.4.1 + # via alembic +markupsafe==3.0.3 + # via + # jinja2 + # mako +minio==7.2.20 + # via -r requirements.txt +multidict==6.7.1 + # via + # aiohttp + # yarl +nh3==0.3.7 + # via -r requirements.txt +openai==2.54.0 + # via litellm +openpyxl==3.1.5 + # via -r requirements.txt +packaging==26.3 + # via huggingface-hub +passlib[bcrypt]==1.7.4 + # via -r requirements.txt +pgpy==0.6.0 + # via -r requirements.txt +pgvector==0.5.0 + # via -r requirements.txt +pillow==12.3.0 + # via + # python-pptx + # weasyprint +prometheus-client==0.26.0 + # via -r requirements.txt +propcache==0.5.2 + # via + # aiohttp + # yarl +pyasn1==0.6.4 + # via pgpy +pycparser==3.0 + # via cffi +pycryptodome==3.23.0 + # via minio +pydantic==2.13.4 + # via + # -r requirements.txt + # fastapi + # litellm + # openai + # pydantic-settings +pydantic-core==2.46.4 + # via pydantic +pydantic-settings==2.15.0 + # via + # -r requirements.txt + # litellm +pydyf==0.12.1 + # via weasyprint +pyjwt==2.13.0 + # via redis +pypdf==6.16.2 + # via -r requirements.txt +pyphen==0.18.1 + # via weasyprint +python-dateutil==2.9.0.post0 + # via + # botocore + # croniter +python-docx==1.2.0 + # via -r requirements.txt +python-dotenv==1.2.3 + # via + # litellm + # pydantic-settings + # uvicorn +python-multipart==0.0.32 + # via -r requirements.txt +python-pptx==1.0.2 + # via -r requirements.txt +pyyaml==6.0.3 + # via + # huggingface-hub + # uvicorn +redis[hiredis]==5.3.1 + # via + # -r requirements.txt + # arq +referencing==0.37.0 + # via + # jsonschema + # jsonschema-specifications +regex==2026.7.19 + # via tiktoken +requests==2.34.2 + # via tiktoken +rpds-py==2026.6.3 + # via + # jsonschema + # referencing +s3transfer==0.19.2 + # via boto3 +six==1.17.0 + # via python-dateutil +sniffio==1.3.1 + # via openai +sqlalchemy==2.0.35 + # via + # -r requirements.txt + # alembic +starlette==1.3.1 + # via + # -r requirements.txt + # fastapi +structlog==26.1.0 + # via -r requirements.txt +tiktoken==0.14.0 + # via litellm +tinycss2==1.5.1 + # via + # cssselect2 + # weasyprint +tinyhtml5==2.1.0 + # via weasyprint +tokenizers==0.23.1 + # via litellm +tqdm==4.70.0 + # via + # huggingface-hub + # openai +typing-extensions==4.16.0 + # via + # alembic + # fastapi + # huggingface-hub + # minio + # openai + # pydantic + # pydantic-core + # python-docx + # python-pptx + # sqlalchemy + # typing-inspection +typing-inspection==0.4.4 + # via + # fastapi + # pydantic + # pydantic-settings +urllib3==2.7.0 + # via + # botocore + # minio + # requests +uvicorn[standard]==0.52.4 + # via -r requirements.txt +uvloop==0.22.1 + # via uvicorn +watchfiles==1.2.0 + # via uvicorn +weasyprint==69.0 + # via -r requirements.txt +webencodings==0.6.1 + # via + # cssselect2 + # tinycss2 + # tinyhtml5 +websockets==17.0.1 + # via uvicorn +xlsxwriter==3.2.9 + # via python-pptx +yarl==1.24.5 + # via aiohttp +zipp==4.1.0 + # via importlib-metadata +zopfli==0.4.3 + # via fonttools diff --git a/scripts/ci_pipeline.sh b/scripts/ci_pipeline.sh index 0c752f0..05308ec 100644 --- a/scripts/ci_pipeline.sh +++ b/scripts/ci_pipeline.sh @@ -96,7 +96,11 @@ else fi # ── 13. Dependency Scan (if pip-audit installed) ───────────────────────────── -if command -v pip-audit &>/dev/null; then +# Audit against the LOCKFILE (exact tested set), not the ranges file. +if [ -f requirements.lock ] && command -v pip-audit &>/dev/null; then + check "Dependency Scan (pip-audit on lock)" "pip-audit -r requirements.lock --strict --no-deps 2>&1 | tail -5" + check "Pip Consistency (pip check)" "pip check" +elif command -v pip-audit &>/dev/null; then check "Dependency Scan (pip-audit)" "pip-audit -r requirements.txt --strict 2>&1 | tail -5" check "Pip Consistency (pip check)" "pip check" else