diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a76d31a5..b29e941fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,12 +87,12 @@ jobs: rm -rf codecov codecov.SHA256SUM codecov.SHA256SUM.sig - name: Run json schema extract - # This should be kept before the repository check to ensure that the schema is up-to-date + # This must be kept before the repository check to ensure that the schema is up-to-date run: | python build_helpers/extract_config_json_schema.py - name: Run command docs partials extract - # This should be kept before the repository check to ensure that the docs are up-to-date + # This must be kept before the repository check to ensure that the docs are up-to-date if: ${{ (matrix.python-version == '3.13') }} run: | python build_helpers/create_command_partials.py @@ -159,6 +159,7 @@ jobs: shell: powershell run: | $PSVersionTable + Get-PSRepository | Format-List * Set-PSRepository psgallery -InstallationPolicy trusted Install-Module -Name Pester -RequiredVersion 5.3.1 -Confirm:$false -Force -SkipPublisherCheck $Error.clear() diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index cd8994453..96d0524eb 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -290,6 +290,7 @@ jobs: docker buildx imagetools create \ --tag ${GHCR_IMAGE_NAME}:${TAG} \ --tag ${GHCR_IMAGE_NAME}:latest \ + --tag ${IMAGE_NAME}:latest \ ${IMAGE_NAME}:${TAG} - name: Docker images diff --git a/Dockerfile b/Dockerfile index 6ad49624c..5a1d54493 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.13.8-slim-bookworm AS base +FROM python:3.13.11-slim-bookworm AS base # Setup env ENV LANG=C.UTF-8 diff --git a/docker/Dockerfile.armhf b/docker/Dockerfile.armhf index dd0c9d670..d654400eb 100644 --- a/docker/Dockerfile.armhf +++ b/docker/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM python:3.11.13-slim-bookworm AS base +FROM python:3.11.14-slim-bookworm AS base # Setup env ENV LANG=C.UTF-8 diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 9d6807fa2..3085e9ac9 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -879,19 +879,20 @@ class Exchange: # Only allow 5 calls per pair to somewhat limit the impact raise ConfigurationError( f"This strategy requires {startup_candles} candles to start, " - "which is more than 5x " + f"which is more than 5x ({candle_limit * 5 - 1} candles) " f"the amount of candles {self.name} provides for {timeframe}." ) elif required_candle_call_count > 1: raise ConfigurationError( - f"This strategy requires {startup_candles} candles to start, which is more than " + f"This strategy requires {startup_candles} candles to start, " + f"which is more than ({candle_limit - 1} candles) " f"the amount of candles {self.name} provides for {timeframe}." ) if required_candle_call_count > 1: logger.warning( f"Using {required_candle_call_count} calls to get OHLCV. " f"This can result in slower operations for the bot. Please check " - f"if you really need {startup_candles} candles for your strategy" + f"if you really need {startup_candles} candles for your strategy." ) return required_candle_call_count diff --git a/requirements-dev.txt b/requirements-dev.txt index 38a49f661..a59805e46 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -30,3 +30,4 @@ types-filelock==3.2.7 types-requests==2.32.4.20250913 types-tabulate==0.9.0.20241207 types-python-dateutil==2.9.0.20251115 +pip-audit==2.10.0 diff --git a/requirements-freqai.txt b/requirements-freqai.txt index e2907a32b..1325c431a 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -3,7 +3,7 @@ -r requirements-plot.txt # Required for freqai -scikit-learn==1.7.2 +scikit-learn==1.8.0 joblib==1.5.3 lightgbm==4.6.0 xgboost==3.1.2 diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index b655f2ac9..4de1a4e34 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -3,7 +3,7 @@ # Required for hyperopt scipy==1.16.3 -scikit-learn==1.7.2 +scikit-learn==1.8.0 filelock==3.20.1 optuna==4.6.0 cmaes==0.12.0 diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 5772a1c4a..94428cbbf 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1012,7 +1012,7 @@ def test_validate_required_startup_candles(default_conf, mocker, caplog): ex._ft_has["ohlcv_has_history"] = False with pytest.raises( OperationalException, - match=r"This strategy requires 2500.*, " r"which is more than the amount.*", + match=r"This strategy requires 2500.*, " r"which is more than .* the amount", ): ex.validate_required_startup_candles(2500, "5m") diff --git a/tests/test_pip_audit.py b/tests/test_pip_audit.py new file mode 100644 index 000000000..ab9017b89 --- /dev/null +++ b/tests/test_pip_audit.py @@ -0,0 +1,92 @@ +""" +Run pip audit to check for known security vulnerabilities in installed packages. +Original Idea and base for this implementation by Michael Kennedy's blog: +https://mkennedy.codes/posts/python-supply-chain-security-made-easy/ +""" + +import subprocess +import sys +from pathlib import Path + +import pytest + + +def test_pip_audit_no_vulnerabilities(): + """ + Run pip-audit to check for known security vulnerabilities. + + This test will fail if any vulnerabilities are detected in the installed packages. + + Note: CVE-2025-53000 (nbconvert Windows vulnerability) is ignored as it only affects + Windows platforms and is a known acceptable risk for this project. + """ + # Get the project root directory + project_root = Path(__file__).parent.parent + command = [ + sys.executable, + "-m", + "pip_audit", + # "--format=json", + "--progress-spinner=off", + "--ignore-vuln", + "CVE-2025-53000", + "--skip-editable", + ] + + # Run pip-audit with JSON output for easier parsing + try: + result = subprocess.run( + command, + cwd=project_root, + capture_output=True, + text=True, + timeout=120, # 2 minute timeout + ) + except subprocess.TimeoutExpired: + pytest.fail("pip-audit command timed out after 120 seconds") + except FileNotFoundError: + pytest.fail("pip-audit not installed or not accessible") + + # Check if pip-audit found any vulnerabilities + if result.returncode != 0: + # pip-audit returns non-zero when vulnerabilities are found + error_output = result.stdout + "\n" + result.stderr + + # Check if it's an actual vulnerability vs an error + if "vulnerabilities found" in error_output.lower() or '"dependencies"' in result.stdout: + pytest.fail( + f"pip-audit detected security vulnerabilities!\n\n" + f"Output:\n{result.stdout}\n\n" + f"Please review and update vulnerable packages.\n" + f"Run manually with: {' '.join(command)}" + ) + else: + # Some other error occurred + pytest.fail( + f"pip-audit failed to run properly:\n\nReturn code: {result.returncode}\n" + f"Output: {error_output}\n" + ) + + # Success - no vulnerabilities found + assert result.returncode == 0, "pip-audit should return 0 when no vulnerabilities are found" + + +def test_pip_audit_runs_successfully(): + """ + Verify that pip-audit can run successfully (even if vulnerabilities are found). + + This is a smoke test to ensure pip-audit is properly installed and functional. + """ + try: + result = subprocess.run( + [sys.executable, "-m", "pip_audit", "--version"], + capture_output=True, + text=True, + timeout=10, + ) + assert result.returncode == 0, f"pip-audit --version failed: {result.stderr}" + assert "pip-audit" in result.stdout.lower(), "pip-audit version output unexpected" + except FileNotFoundError: + pytest.fail("pip-audit not installed") + except subprocess.TimeoutExpired: + pytest.fail("pip-audit --version timed out")