mirror of
https://github.com/crowdsecurity/crowdsec.git
synced 2025-05-10 11:55:53 +02:00
CI: lint docker tests (#3443)
This commit is contained in:
parent
5136d928ed
commit
b3da6e03ff
26 changed files with 155 additions and 152 deletions
1
.github/workflows/docker-tests.yml
vendored
1
.github/workflows/docker-tests.yml
vendored
|
@ -70,6 +70,7 @@ jobs:
|
|||
cd docker/test
|
||||
uv sync --all-extras --dev --locked
|
||||
uv run ruff check
|
||||
uv run basedpyright
|
||||
uv run pytest tests -n 1 --durations=0 --color=yes
|
||||
env:
|
||||
CROWDSEC_TEST_VERSION: test
|
||||
|
|
|
@ -13,6 +13,7 @@ dependencies = [
|
|||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"basedpyright>=1.26.0",
|
||||
"ipdb>=0.13.13",
|
||||
"ruff>=0.9.3",
|
||||
]
|
||||
|
@ -26,16 +27,34 @@ line-length = 120
|
|||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"C", # flake8-comprehensions
|
||||
"B", # flake8-bugbear
|
||||
"UP", # pyupgrade
|
||||
"C90", # macabe
|
||||
"ALL"
|
||||
]
|
||||
|
||||
ignore = [
|
||||
"B008", # do not perform function calls in argument defaults
|
||||
"ANN", # Missing type annotations
|
||||
"COM", # flake8-commas
|
||||
"D", # pydocstyle
|
||||
"ERA", # eradicate
|
||||
"FIX", # flake8-fixme
|
||||
"TD", # flake8-todos
|
||||
|
||||
"INP001", # File `...` is part of an implicit namespace package. Add an `__init__.py`.
|
||||
"E501", # line too long
|
||||
# ^ does not ignore comments that can't be moved to their own line, line noqa, pyright
|
||||
# so we take care of line lenghts only with "ruff format"
|
||||
"PLR2004", # Magic value used in comparison, consider replacing `...` with a constant variable
|
||||
"S101", # Use of 'assert' detected
|
||||
"S603", # `subprocess` call: check for execution of untrusted input
|
||||
"S607", # Starting a process with a partial executable path
|
||||
]
|
||||
|
||||
[tool.basedpyright]
|
||||
reportUnknownArgumentType = "none"
|
||||
reportUnknownParameterType = "none"
|
||||
reportMissingParameterType = "none"
|
||||
reportMissingTypeStubs = "none"
|
||||
reportUnknownVariableType = "none"
|
||||
reportUnknownMemberType = "none"
|
||||
reportUnreachable = "none"
|
||||
reportAny = "none"
|
||||
|
||||
|
|
0
docker/test/tests/__init__.py
Normal file
0
docker/test/tests/__init__.py
Normal file
|
@ -1,6 +1,8 @@
|
|||
from _pytest.config import Config
|
||||
|
||||
pytest_plugins = ("cs",)
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
def pytest_configure(config: Config) -> None:
|
||||
config.addinivalue_line("markers", "docker: mark tests for lone or manually orchestrated containers")
|
||||
config.addinivalue_line("markers", "compose: mark tests for docker compose projects")
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
|
@ -7,7 +5,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_no_agent(crowdsec, flavor):
|
||||
def test_no_agent(crowdsec, flavor: str) -> None:
|
||||
"""Test DISABLE_AGENT=true"""
|
||||
env = {
|
||||
"DISABLE_AGENT": "true",
|
||||
|
@ -21,7 +19,7 @@ def test_no_agent(crowdsec, flavor):
|
|||
assert "You can successfully interact with Local API (LAPI)" in stdout
|
||||
|
||||
|
||||
def test_machine_register(crowdsec, flavor, tmp_path_factory):
|
||||
def test_machine_register(crowdsec, flavor: str, tmp_path_factory: pytest.TempPathFactory) -> None:
|
||||
"""A local agent is always registered for use by cscli"""
|
||||
|
||||
data_dir = tmp_path_factory.mktemp("data")
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import random
|
||||
import secrets
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
|
@ -8,8 +6,8 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_split_lapi_agent(crowdsec, flavor):
|
||||
rand = str(random.randint(0, 10000))
|
||||
def test_split_lapi_agent(crowdsec, flavor: str) -> None:
|
||||
rand = str(secrets.randbelow(10000))
|
||||
lapiname = f"lapi-{rand}"
|
||||
agentname = f"agent-{rand}"
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test bouncer management: pre-installed, run-time installation and removal.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from http import HTTPStatus
|
||||
|
||||
|
@ -13,12 +10,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def hex512(s):
|
||||
"""Return the sha512 hash of a string as a hex string"""
|
||||
return hashlib.sha512(s.encode()).hexdigest()
|
||||
|
||||
|
||||
def test_register_bouncer_env(crowdsec, flavor):
|
||||
def test_register_bouncer_env(crowdsec, flavor: str) -> None:
|
||||
"""Test installing bouncers at startup, from envvar"""
|
||||
|
||||
env = {"BOUNCER_KEY_bouncer1name": "bouncer1key", "BOUNCER_KEY_bouncer2name": "bouncer2key"}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
|
@ -7,7 +5,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_no_capi(crowdsec, flavor):
|
||||
def test_no_capi(crowdsec, flavor: str) -> None:
|
||||
"""Test no CAPI (disabled by default in tests)"""
|
||||
|
||||
env = {
|
||||
|
@ -26,7 +24,7 @@ def test_no_capi(crowdsec, flavor):
|
|||
assert not any("Registration to online API done" in line for line in logs)
|
||||
|
||||
|
||||
def test_capi(crowdsec, flavor):
|
||||
def test_capi(crowdsec, flavor: str) -> None:
|
||||
"""Test CAPI"""
|
||||
|
||||
env = {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
|
@ -8,16 +6,12 @@ import yaml
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_capi_whitelists(
|
||||
crowdsec,
|
||||
tmp_path_factory,
|
||||
flavor,
|
||||
):
|
||||
def test_capi_whitelists(crowdsec, tmp_path_factory: pytest.TempPathFactory, flavor: str) -> None:
|
||||
"""Test CAPI_WHITELISTS_PATH"""
|
||||
env = {"CAPI_WHITELISTS_PATH": "/path/to/whitelists.yaml"}
|
||||
|
||||
whitelists = tmp_path_factory.mktemp("whitelists")
|
||||
with open(whitelists / "whitelists.yaml", "w") as f:
|
||||
with (whitelists / "whitelists.yaml").open("w") as f:
|
||||
yaml.dump({"ips": ["1.2.3.4", "2.3.4.5"], "cidrs": ["1.2.3.0/24"]}, f)
|
||||
|
||||
volumes = {whitelists / "whitelists.yaml": {"bind": "/path/to/whitelists.yaml", "mode": "ro"}}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
@ -8,19 +6,19 @@ from pytest_cs import Status
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_cold_logs(crowdsec, tmp_path_factory, flavor):
|
||||
def test_cold_logs(crowdsec, tmp_path_factory: pytest.TempPathFactory, flavor: str) -> None:
|
||||
env = {
|
||||
"DSN": "file:///var/log/toto.log",
|
||||
}
|
||||
|
||||
logs = tmp_path_factory.mktemp("logs")
|
||||
|
||||
now = datetime.datetime.now() - datetime.timedelta(minutes=1)
|
||||
with open(logs / "toto.log", "w") as f:
|
||||
now = datetime.datetime.now(tz=datetime.UTC) - datetime.timedelta(minutes=1)
|
||||
with (logs / "toto.log").open("w") as f:
|
||||
# like date '+%b %d %H:%M:%S' but in python
|
||||
for i in range(10):
|
||||
ts = (now + datetime.timedelta(seconds=i)).strftime("%b %d %H:%M:%S")
|
||||
f.write(ts + " sd-126005 sshd[12422]: Invalid user netflix from 1.1.1.172 port 35424\n")
|
||||
_ = f.write(ts + " sd-126005 sshd[12422]: Invalid user netflix from 1.1.1.172 port 35424\n")
|
||||
|
||||
volumes = {
|
||||
logs / "toto.log": {"bind": "/var/log/toto.log", "mode": "ro"},
|
||||
|
@ -44,7 +42,7 @@ def test_cold_logs(crowdsec, tmp_path_factory, flavor):
|
|||
)
|
||||
|
||||
|
||||
def test_cold_logs_missing_dsn(crowdsec, flavor):
|
||||
def test_cold_logs_missing_dsn(crowdsec, flavor: str) -> None:
|
||||
env = {
|
||||
"TYPE": "syslog",
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test basic behavior of all the image variants
|
||||
"""
|
||||
|
@ -11,7 +9,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_cscli_lapi(crowdsec, flavor):
|
||||
def test_cscli_lapi(crowdsec, flavor: str) -> None:
|
||||
"""Test if cscli can talk to lapi"""
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
cs.wait_for_log("*Starting processing data*")
|
||||
|
@ -23,7 +21,7 @@ def test_cscli_lapi(crowdsec, flavor):
|
|||
|
||||
|
||||
@pytest.mark.skip(reason="currently broken by hub upgrade")
|
||||
def test_flavor_content(crowdsec, flavor):
|
||||
def test_flavor_content(crowdsec, flavor: str) -> None:
|
||||
"""Test flavor contents"""
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
cs.wait_for_log("*Starting processing data*")
|
||||
|
|
|
@ -1,31 +1,30 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Smoke tests in case docker is not set up correctly or has connection issues.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
|
||||
import docker
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_docker_cli_run():
|
||||
def test_docker_cli_run() -> None:
|
||||
"""Test if docker run works from the command line. Capture stdout too"""
|
||||
res = subprocess.run(["docker", "run", "--rm", "hello-world"], capture_output=True, text=True)
|
||||
assert 0 == res.returncode
|
||||
res = subprocess.run(["docker", "run", "--rm", "hello-world"], capture_output=True, text=True, check=True)
|
||||
assert res.returncode == 0
|
||||
assert "Hello from Docker!" in res.stdout
|
||||
|
||||
|
||||
def test_docker_run(docker_client):
|
||||
def test_docker_run(docker_client: docker.DockerClient) -> None:
|
||||
"""Test if docker run works from the python SDK."""
|
||||
output = docker_client.containers.run("hello-world", remove=True)
|
||||
lines = output.decode().splitlines()
|
||||
assert "Hello from Docker!" in lines
|
||||
|
||||
|
||||
def test_docker_run_detach(docker_client):
|
||||
def test_docker_run_detach(docker_client: docker.DockerClient) -> None:
|
||||
"""Test with python SDK (async)."""
|
||||
cont = docker_client.containers.run("hello-world", detach=True)
|
||||
assert cont.status == "created"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test pre-installed hub items.
|
||||
"""
|
||||
|
@ -12,7 +10,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_preinstalled_hub(crowdsec, flavor):
|
||||
def test_preinstalled_hub(crowdsec, flavor: str) -> None:
|
||||
"""Test hub objects installed in the entrypoint"""
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
cs.wait_for_log("*Starting processing data*")
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test collection management
|
||||
"""
|
||||
|
@ -12,7 +10,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_install_two_collections(crowdsec, flavor):
|
||||
def test_install_two_collections(crowdsec, flavor: str) -> None:
|
||||
"""Test installing collections at startup"""
|
||||
it1 = "crowdsecurity/apache2"
|
||||
it2 = "crowdsecurity/asterisk"
|
||||
|
@ -33,7 +31,7 @@ def test_install_two_collections(crowdsec, flavor):
|
|||
)
|
||||
|
||||
|
||||
def test_disable_collection(crowdsec, flavor):
|
||||
def test_disable_collection(crowdsec, flavor: str) -> None:
|
||||
"""Test removing a pre-installed collection at startup"""
|
||||
it = "crowdsecurity/linux"
|
||||
env = {"DISABLE_COLLECTIONS": it}
|
||||
|
@ -52,7 +50,7 @@ def test_disable_collection(crowdsec, flavor):
|
|||
)
|
||||
|
||||
|
||||
def test_install_and_disable_collection(crowdsec, flavor):
|
||||
def test_install_and_disable_collection(crowdsec, flavor: str) -> None:
|
||||
"""Declare a collection to install AND disable: disable wins"""
|
||||
it = "crowdsecurity/apache2"
|
||||
env = {
|
||||
|
@ -73,7 +71,7 @@ def test_install_and_disable_collection(crowdsec, flavor):
|
|||
|
||||
|
||||
# already done in bats, prividing here as example of a somewhat complex test
|
||||
def test_taint_bubble_up(crowdsec, tmp_path_factory, flavor):
|
||||
def test_taint_bubble_up(crowdsec, flavor: str) -> None:
|
||||
coll = "crowdsecurity/nginx"
|
||||
env = {"COLLECTIONS": f"{coll}"}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test parser management
|
||||
"""
|
||||
|
@ -12,7 +10,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_install_two_parsers(crowdsec, flavor):
|
||||
def test_install_two_parsers(crowdsec, flavor: str) -> None:
|
||||
"""Test installing parsers at startup"""
|
||||
it1 = "crowdsecurity/cpanel-logs"
|
||||
it2 = "crowdsecurity/cowrie-logs"
|
||||
|
@ -29,7 +27,7 @@ def test_install_two_parsers(crowdsec, flavor):
|
|||
|
||||
|
||||
# XXX check that the parser is preinstalled by default
|
||||
def test_disable_parser(crowdsec, flavor):
|
||||
def test_disable_parser(crowdsec, flavor: str) -> None:
|
||||
"""Test removing a pre-installed parser at startup"""
|
||||
it = "crowdsecurity/whitelists"
|
||||
env = {"DISABLE_PARSERS": it}
|
||||
|
@ -48,7 +46,7 @@ def test_disable_parser(crowdsec, flavor):
|
|||
assert it not in items
|
||||
|
||||
|
||||
def test_install_and_disable_parser(crowdsec, flavor):
|
||||
def test_install_and_disable_parser(crowdsec, flavor: str) -> None:
|
||||
"""Declare a parser to install AND disable: disable wins"""
|
||||
it = "crowdsecurity/cpanel-logs"
|
||||
env = {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test postoverflow management
|
||||
"""
|
||||
|
@ -12,7 +10,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_install_two_postoverflows(crowdsec, flavor):
|
||||
def test_install_two_postoverflows(crowdsec, flavor: str) -> None:
|
||||
"""Test installing postoverflows at startup"""
|
||||
it1 = "crowdsecurity/cdn-whitelist"
|
||||
it2 = "crowdsecurity/ipv6_to_range"
|
||||
|
@ -30,12 +28,12 @@ def test_install_two_postoverflows(crowdsec, flavor):
|
|||
assert items[it2]["status"] == "enabled"
|
||||
|
||||
|
||||
def test_disable_postoverflow():
|
||||
def test_disable_postoverflow() -> None:
|
||||
"""Test removing a pre-installed postoverflow at startup"""
|
||||
pytest.skip("we don't preinstall postoverflows")
|
||||
|
||||
|
||||
def test_install_and_disable_postoverflow(crowdsec, flavor):
|
||||
def test_install_and_disable_postoverflow(crowdsec, flavor: str) -> None:
|
||||
"""Declare a postoverflow to install AND disable: disable wins"""
|
||||
it = "crowdsecurity/cdn-whitelist"
|
||||
env = {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test scenario management
|
||||
"""
|
||||
|
@ -12,7 +10,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_install_two_scenarios(crowdsec, flavor):
|
||||
def test_install_two_scenarios(crowdsec, flavor: str) -> None:
|
||||
"""Test installing scenarios at startup"""
|
||||
it1 = "crowdsecurity/cpanel-bf-attempt"
|
||||
it2 = "crowdsecurity/asterisk_bf"
|
||||
|
@ -28,7 +26,7 @@ def test_install_two_scenarios(crowdsec, flavor):
|
|||
assert items[it2]["status"] == "enabled"
|
||||
|
||||
|
||||
def test_disable_scenario(crowdsec, flavor):
|
||||
def test_disable_scenario(crowdsec, flavor: str) -> None:
|
||||
"""Test removing a pre-installed scenario at startup"""
|
||||
it = "crowdsecurity/ssh-bf"
|
||||
env = {"DISABLE_SCENARIOS": it}
|
||||
|
@ -42,7 +40,7 @@ def test_disable_scenario(crowdsec, flavor):
|
|||
assert it not in items
|
||||
|
||||
|
||||
def test_install_and_disable_scenario(crowdsec, flavor):
|
||||
def test_install_and_disable_scenario(crowdsec, flavor: str) -> None:
|
||||
"""Declare a scenario to install AND disable: disable wins"""
|
||||
it = "crowdsecurity/asterisk_bf"
|
||||
env = {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
|
@ -7,7 +5,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_local_api_url_default(crowdsec, flavor):
|
||||
def test_local_api_url_default(crowdsec, flavor: str) -> None:
|
||||
"""Test LOCAL_API_URL (default)"""
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
cs.wait_for_log(["*CrowdSec Local API listening on *:8080*", "*Starting processing data*"])
|
||||
|
@ -19,7 +17,7 @@ def test_local_api_url_default(crowdsec, flavor):
|
|||
assert "You can successfully interact with Local API (LAPI)" in stdout
|
||||
|
||||
|
||||
def test_local_api_url(crowdsec, flavor):
|
||||
def test_local_api_url(crowdsec, flavor: str) -> None:
|
||||
"""Test LOCAL_API_URL (custom)"""
|
||||
env = {"LOCAL_API_URL": "http://127.0.0.1:8080"}
|
||||
with crowdsec(flavor=flavor, environment=env) as cs:
|
||||
|
@ -32,7 +30,7 @@ def test_local_api_url(crowdsec, flavor):
|
|||
assert "You can successfully interact with Local API (LAPI)" in stdout
|
||||
|
||||
|
||||
def test_local_api_url_ipv6(crowdsec, flavor):
|
||||
def test_local_api_url_ipv6(crowdsec, flavor: str) -> None:
|
||||
"""Test LOCAL_API_URL (custom with ipv6)"""
|
||||
pytest.skip("ipv6 not supported yet")
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test bind-mounting local items
|
||||
"""
|
||||
|
@ -12,14 +10,14 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_inject_local_item(crowdsec, tmp_path_factory, flavor):
|
||||
def test_inject_local_item(crowdsec, tmp_path_factory: pytest.TempPathFactory, flavor: str) -> None:
|
||||
"""Test mounting a custom whitelist at startup"""
|
||||
|
||||
localitems = tmp_path_factory.mktemp("localitems")
|
||||
custom_whitelists = localitems / "custom_whitelists.yaml"
|
||||
|
||||
with open(custom_whitelists, "w") as f:
|
||||
f.write('{"whitelist":{"reason":"Good IPs","ip":["1.2.3.4"]}}')
|
||||
with custom_whitelists.open("w") as f:
|
||||
_ = f.write('{"whitelist":{"reason":"Good IPs","ip":["1.2.3.4"]}}')
|
||||
|
||||
volumes = {custom_whitelists: {"bind": "/etc/crowdsec/parsers/s02-enrich/custom_whitelists.yaml"}}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
|
@ -7,7 +5,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_metrics_port_default(crowdsec, flavor):
|
||||
def test_metrics_port_default(crowdsec, flavor: str) -> None:
|
||||
"""Test metrics"""
|
||||
metrics_port = 6060
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
|
@ -23,7 +21,7 @@ def test_metrics_port_default(crowdsec, flavor):
|
|||
assert "# HELP cs_info Information about Crowdsec." in stdout
|
||||
|
||||
|
||||
def test_metrics_port_default_ipv6(crowdsec, flavor):
|
||||
def test_metrics_port_default_ipv6(crowdsec, flavor: str) -> None:
|
||||
"""Test metrics (ipv6)"""
|
||||
pytest.skip("ipv6 not supported yet")
|
||||
port = 6060
|
||||
|
@ -39,7 +37,7 @@ def test_metrics_port_default_ipv6(crowdsec, flavor):
|
|||
assert "# HELP cs_info Information about Crowdsec." in stdout
|
||||
|
||||
|
||||
def test_metrics_port(crowdsec, flavor):
|
||||
def test_metrics_port(crowdsec, flavor: str) -> None:
|
||||
"""Test metrics (custom METRICS_PORT)"""
|
||||
port = 7070
|
||||
env = {"METRICS_PORT": port}
|
||||
|
@ -55,7 +53,7 @@ def test_metrics_port(crowdsec, flavor):
|
|||
assert "# HELP cs_info Information about Crowdsec." in stdout
|
||||
|
||||
|
||||
def test_metrics_port_ipv6(crowdsec, flavor):
|
||||
def test_metrics_port_ipv6(crowdsec, flavor: str) -> None:
|
||||
"""Test metrics (custom METRICS_PORT, ipv6)"""
|
||||
pytest.skip("ipv6 not supported yet")
|
||||
port = 7070
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import pytest
|
||||
from pytest_cs import Status
|
||||
|
||||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_no_agent(crowdsec, flavor):
|
||||
def test_no_agent(crowdsec, flavor: str) -> None:
|
||||
"""Test DISABLE_LOCAL_API=true (failing stand-alone container)"""
|
||||
env = {
|
||||
"DISABLE_LOCAL_API": "true",
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
# XXX this is redundant, already tested in pytest_cs
|
||||
def test_crowdsec(crowdsec, flavor):
|
||||
def test_crowdsec(crowdsec, flavor: str) -> None:
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
for waiter in cs.log_waiters():
|
||||
with waiter as matcher:
|
||||
matcher.fnmatch_lines(["*Starting processing data*"])
|
||||
res = cs.cont.exec_run('sh -c "echo $CI_TESTING"')
|
||||
assert res.exit_code == 0
|
||||
assert "true" == res.output.decode().strip()
|
||||
assert res.output.decode().strip() == "true"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Test agent-lapi and cscli-lapi communication via TLS, on the same container.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
import uuid
|
||||
from collections.abc import Callable
|
||||
|
||||
import pytest
|
||||
from pytest_cs import Status
|
||||
|
@ -12,7 +12,7 @@ from pytest_cs import Status
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_missing_key_file(crowdsec, flavor):
|
||||
def test_missing_key_file(crowdsec, flavor: str) -> None:
|
||||
"""Test that cscli and agent can communicate to LAPI with TLS"""
|
||||
|
||||
env = {
|
||||
|
@ -24,7 +24,7 @@ def test_missing_key_file(crowdsec, flavor):
|
|||
cs.wait_for_log("*local API server stopped with error: missing TLS key file*")
|
||||
|
||||
|
||||
def test_missing_cert_file(crowdsec, flavor):
|
||||
def test_missing_cert_file(crowdsec, flavor: str) -> None:
|
||||
"""Test that cscli and agent can communicate to LAPI with TLS"""
|
||||
|
||||
env = {
|
||||
|
@ -36,7 +36,7 @@ def test_missing_cert_file(crowdsec, flavor):
|
|||
cs.wait_for_log("*local API server stopped with error: missing TLS cert file*")
|
||||
|
||||
|
||||
def test_tls_missing_ca(crowdsec, flavor, certs_dir):
|
||||
def test_tls_missing_ca(crowdsec, flavor: str, certs_dir: Callable[..., pathlib.Path]) -> None:
|
||||
"""Missing CA cert, unknown authority"""
|
||||
|
||||
env = {
|
||||
|
@ -54,7 +54,7 @@ def test_tls_missing_ca(crowdsec, flavor, certs_dir):
|
|||
cs.wait_for_log("*certificate signed by unknown authority*")
|
||||
|
||||
|
||||
def test_tls_legacy_var(crowdsec, flavor, certs_dir):
|
||||
def test_tls_legacy_var(crowdsec, flavor: str, certs_dir: Callable[..., pathlib.Path]) -> None:
|
||||
"""Test server-only certificate, legacy variables"""
|
||||
|
||||
env = {
|
||||
|
@ -79,7 +79,7 @@ def test_tls_legacy_var(crowdsec, flavor, certs_dir):
|
|||
assert "You can successfully interact with Local API (LAPI)" in stdout
|
||||
|
||||
|
||||
def test_tls_mutual_monolith(crowdsec, flavor, certs_dir):
|
||||
def test_tls_mutual_monolith(crowdsec, flavor: str, certs_dir: Callable[..., pathlib.Path]) -> None:
|
||||
"""Server and client certificates, on the same container"""
|
||||
|
||||
env = {
|
||||
|
@ -106,7 +106,7 @@ def test_tls_mutual_monolith(crowdsec, flavor, certs_dir):
|
|||
assert "You can successfully interact with Local API (LAPI)" in stdout
|
||||
|
||||
|
||||
def test_tls_lapi_var(crowdsec, flavor, certs_dir):
|
||||
def test_tls_lapi_var(crowdsec, flavor: str, certs_dir: Callable[..., pathlib.Path]) -> None:
|
||||
"""Test server-only certificate, lapi variables"""
|
||||
|
||||
env = {
|
||||
|
@ -136,7 +136,7 @@ def test_tls_lapi_var(crowdsec, flavor, certs_dir):
|
|||
# we must set insecure_skip_verify to true to use it
|
||||
|
||||
|
||||
def test_tls_split_lapi_agent(crowdsec, flavor, certs_dir):
|
||||
def test_tls_split_lapi_agent(crowdsec, flavor: str, certs_dir: Callable[..., pathlib.Path]) -> None:
|
||||
"""Server-only certificate, split containers"""
|
||||
|
||||
rand = uuid.uuid1()
|
||||
|
@ -188,7 +188,7 @@ def test_tls_split_lapi_agent(crowdsec, flavor, certs_dir):
|
|||
assert "You can successfully interact with Local API (LAPI)" in stdout
|
||||
|
||||
|
||||
def test_tls_mutual_split_lapi_agent(crowdsec, flavor, certs_dir):
|
||||
def test_tls_mutual_split_lapi_agent(crowdsec, flavor: str, certs_dir: Callable[..., pathlib.Path]) -> None:
|
||||
"""Server and client certificates, split containers"""
|
||||
|
||||
rand = uuid.uuid1()
|
||||
|
@ -238,7 +238,7 @@ def test_tls_mutual_split_lapi_agent(crowdsec, flavor, certs_dir):
|
|||
assert "You can successfully interact with Local API (LAPI)" in stdout
|
||||
|
||||
|
||||
def test_tls_client_ou(crowdsec, flavor, certs_dir):
|
||||
def test_tls_client_ou(crowdsec, flavor: str, certs_dir: Callable[..., pathlib.Path]) -> None:
|
||||
"""Check behavior of client certificate vs AGENTS_ALLOWED_OU"""
|
||||
|
||||
rand = uuid.uuid1()
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_version_docker_platform(crowdsec, flavor):
|
||||
def test_version_docker_platform(crowdsec, flavor: str) -> None:
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
for waiter in cs.log_waiters():
|
||||
with waiter as matcher:
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
import pytest
|
||||
|
@ -7,7 +5,7 @@ import pytest
|
|||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
||||
def test_use_wal_default(crowdsec, flavor):
|
||||
def test_use_wal_default(crowdsec, flavor: str) -> None:
|
||||
"""Test USE_WAL default"""
|
||||
with crowdsec(flavor=flavor) as cs:
|
||||
cs.wait_for_log("*Starting processing data*")
|
||||
|
@ -18,7 +16,7 @@ def test_use_wal_default(crowdsec, flavor):
|
|||
assert "false" in stdout
|
||||
|
||||
|
||||
def test_use_wal_true(crowdsec, flavor):
|
||||
def test_use_wal_true(crowdsec, flavor: str) -> None:
|
||||
"""Test USE_WAL=true"""
|
||||
env = {
|
||||
"USE_WAL": "true",
|
||||
|
@ -32,7 +30,7 @@ def test_use_wal_true(crowdsec, flavor):
|
|||
assert "true" in stdout
|
||||
|
||||
|
||||
def test_use_wal_false(crowdsec, flavor):
|
||||
def test_use_wal_false(crowdsec, flavor: str) -> None:
|
||||
"""Test USE_WAL=false"""
|
||||
env = {
|
||||
"USE_WAL": "false",
|
||||
|
|
86
docker/test/uv.lock
generated
86
docker/test/uv.lock
generated
|
@ -11,12 +11,24 @@ wheels = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2024.12.14"
|
||||
name = "basedpyright"
|
||||
version = "1.26.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 }
|
||||
dependencies = [
|
||||
{ name = "nodejs-wheel-binaries" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/18/c2/5685d040d4f2598788d42bfd2db5f808e9aa2eaee77fcae3c2fbe4ea0e7c/basedpyright-1.26.0.tar.gz", hash = "sha256:5e01f6eb9290a09ef39672106cf1a02924fdc8970e521838bc502ccf0676f32f", size = 24932771 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/72/65308f45bb73efc93075426cac5f37eea937ae364aa675785521cb3512c7/basedpyright-1.26.0-py3-none-any.whl", hash = "sha256:5a6a17f2c389ec313dd2c3644f40e8221bc90252164802e626055341c0a37381", size = 11504579 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.1.31"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -109,6 +121,7 @@ dependencies = [
|
|||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "basedpyright" },
|
||||
{ name = "ipdb" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
@ -123,6 +136,7 @@ requires-dist = [
|
|||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "basedpyright", specifier = ">=1.26.0" },
|
||||
{ name = "ipdb", specifier = ">=0.13.13" },
|
||||
{ name = "ruff", specifier = ">=0.9.3" },
|
||||
]
|
||||
|
@ -232,7 +246,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
version = "8.31.0"
|
||||
version = "8.32.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
|
@ -245,9 +259,9 @@ dependencies = [
|
|||
{ name = "stack-data" },
|
||||
{ name = "traitlets" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/01/35/6f90fdddff7a08b7b715fccbd2427b5212c9525cd043d26fdc45bee0708d/ipython-8.31.0.tar.gz", hash = "sha256:b6a2274606bec6166405ff05e54932ed6e5cfecaca1fc05f2cacde7bb074d70b", size = 5501011 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/36/80/4d2a072e0db7d250f134bc11676517299264ebe16d62a8619d49a78ced73/ipython-8.32.0.tar.gz", hash = "sha256:be2c91895b0b9ea7ba49d33b23e2040c352b33eb6a519cca7ce6e0c743444251", size = 5507441 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/04/60/d0feb6b6d9fe4ab89fe8fe5b47cbf6cd936bfd9f1e7ffa9d0015425aeed6/ipython-8.31.0-py3-none-any.whl", hash = "sha256:46ec58f8d3d076a61d128fe517a51eb730e3aaf0c184ea8c17d16e366660c6a6", size = 821583 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/e1/f4474a7ecdb7745a820f6f6039dc43c66add40f1bcc66485607d93571af6/ipython-8.32.0-py3-none-any.whl", hash = "sha256:cae85b0c61eff1fc48b0a8002de5958b6528fa9c8defb1894da63f42613708aa", size = 825524 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -274,6 +288,22 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodejs-wheel-binaries"
|
||||
version = "22.13.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5d/c5/1af2fc54fcc18f4a99426b46f18832a04f755ee340019e1be536187c1e1c/nodejs_wheel_binaries-22.13.1.tar.gz", hash = "sha256:a0c15213c9c3383541be4400a30959883868ce5da9cebb3d63ddc7fe61459308", size = 8053 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/e9/b0dd118e0fd4eabe1ec9c3d9a68df4d811282e8837b811d804f23742e117/nodejs_wheel_binaries-22.13.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:e4f64d0e26600d51cbdd98a6718a19c2d1b8c7538e9e353e95a634a06a8e1a58", size = 51015650 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/a6/9ba835f5d4f3f6b1f01191e7ac0874871f9743de5c42a5a9a54e67c2e2a6/nodejs_wheel_binaries-22.13.1-py2.py3-none-macosx_11_0_x86_64.whl", hash = "sha256:afcb40484bb02f23137f838014724604ae183fd767b30da95b0be1510a40c06d", size = 51814957 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/2e/a430207e5f22bd3dcffb81acbddf57ee4108b9e2b0f99a5578dc2c1ff7fc/nodejs_wheel_binaries-22.13.1-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fc88c98eebabfc36b5270a4ab974a2682746931567ca76a5ca49c54482bbb51", size = 57148437 },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/f4/5731b6f0c8af434619b4f1b8fd895bc33fca60168cd68133e52841872114/nodejs_wheel_binaries-22.13.1-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9f75ea8f5e3e5416256fcb00a98cbe14c8d3b6dcaf17da29c4ade5723026d8", size = 57634451 },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/28/83166f7e39812e9ef99cfa3e722c54e32dd9de6a1290f3216c2e5d1f4957/nodejs_wheel_binaries-22.13.1-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:94608702ef6c389d32e89ff3b7a925cb5dedaf55b5d98bd0c4fb3450a8b6d1c1", size = 58794510 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/64/4832ec26d0a7ca7a5574df265d85c6832f9a624024511fc34958227ad740/nodejs_wheel_binaries-22.13.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:53a40d0269689aa2eaf2e261cbe5ec256644bc56aae0201ef344b7d8f40ccc79", size = 59738596 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/cd/def29615dac250cda3d141e1c03b7153b9a027360bde0272a6768c5fae33/nodejs_wheel_binaries-22.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:549371a929a29fbce8d0ab8f1b5410549946d4f1b0376a5ce635b45f6d05298f", size = 40455444 },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/d7/6de2bc615203bf590ca437a5cac145b2f86d994ce329489125a0a90ba715/nodejs_wheel_binaries-22.13.1-py2.py3-none-win_arm64.whl", hash = "sha256:cf72d50d755f4e5c0709b0449de01768d96b3b1ec7aa531561415b88f179ad8b", size = 36200929 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.2"
|
||||
|
@ -393,8 +423,8 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "pytest-cs"
|
||||
version = "0.7.20"
|
||||
source = { git = "https://github.com/crowdsecurity/pytest-cs#73380b837a80337f361414bebbaf4b914713c4ae" }
|
||||
version = "0.7.21"
|
||||
source = { git = "https://github.com/crowdsecurity/pytest-cs#1eb949d7befa6fe172bf459616b267d4ffc01179" }
|
||||
dependencies = [
|
||||
{ name = "docker" },
|
||||
{ name = "psutil" },
|
||||
|
@ -509,27 +539,27 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1e/7f/60fda2eec81f23f8aa7cbbfdf6ec2ca11eb11c273827933fb2541c2ce9d8/ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a", size = 3586740 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/17/529e78f49fc6f8076f50d985edd9a2cf011d1dbadb1cdeacc1d12afc1d26/ruff-0.9.4.tar.gz", hash = "sha256:6907ee3529244bb0ed066683e075f09285b38dd5b4039370df6ff06041ca19e7", size = 3599458 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/77/4fb790596d5d52c87fd55b7160c557c400e90f6116a56d82d76e95d9374a/ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624", size = 11656815 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/a8/3338ecb97573eafe74505f28431df3842c1933c5f8eae615427c1de32858/ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c", size = 11594821 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/89/320223c3421962762531a6b2dd58579b858ca9916fb2674874df5e97d628/ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4", size = 11040475 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/bd/1d775eac5e51409535804a3a888a9623e87a8f4b53e2491580858a083692/ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439", size = 11856207 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/c6/3e14e09be29587393d188454064a4aa85174910d16644051a80444e4fd88/ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5", size = 11420460 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/42/b7ca38ffd568ae9b128a2fa76353e9a9a3c80ef19746408d4ce99217ecc1/ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4", size = 12605472 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/a1/3167023f23e3530fde899497ccfe239e4523854cb874458ac082992d206c/ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1", size = 13243123 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/b4/3c600758e320f5bf7de16858502e849f4216cb0151f819fa0d1154874802/ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5", size = 12744650 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/38/266fbcbb3d0088862c9bafa8b1b99486691d2945a90b9a7316336a0d9a1b/ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4", size = 14458585 },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/a6/47fd0e96990ee9b7a4abda62de26d291bd3f7647218d05b7d6d38af47c30/ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6", size = 12419624 },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/5d/de0b7652e09f7dda49e1a3825a164a65f4998175b6486603c7601279baad/ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730", size = 11843238 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/be/3f341ceb1c62b565ec1fb6fd2139cc40b60ae6eff4b6fb8f94b1bb37c7a9/ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2", size = 11484012 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/c8/ff8acbd33addc7e797e702cf00bfde352ab469723720c5607b964491d5cf/ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519", size = 12038494 },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/b1/8d9a2c0efbbabe848b55f877bc10c5001a37ab10aca13c711431673414e5/ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b", size = 12473639 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/44/a673647105b1ba6da9824a928634fe23186ab19f9d526d7bdf278cd27bc3/ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c", size = 9834353 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/01/65cadb59bf8d4fbe33d1a750103e6883d9ef302f60c28b73b773092fbde5/ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4", size = 10821444 },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/cb/b3fe58a136a27d981911cba2f18e4b29f15010623b79f0f2510fd0d31fd3/ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b", size = 10038168 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/f8/3fafb7804d82e0699a122101b5bee5f0d6e17c3a806dcbc527bb7d3f5b7a/ruff-0.9.4-py3-none-linux_armv6l.whl", hash = "sha256:64e73d25b954f71ff100bb70f39f1ee09e880728efb4250c632ceed4e4cdf706", size = 11668400 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/a6/2efa772d335da48a70ab2c6bb41a096c8517ca43c086ea672d51079e3d1f/ruff-0.9.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6ce6743ed64d9afab4fafeaea70d3631b4d4b28b592db21a5c2d1f0ef52934bf", size = 11628395 },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/d7/cd822437561082f1c9d7225cc0d0fbb4bad117ad7ac3c41cd5d7f0fa948c/ruff-0.9.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:54499fb08408e32b57360f6f9de7157a5fec24ad79cb3f42ef2c3f3f728dfe2b", size = 11090052 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/67/3660d58e893d470abb9a13f679223368ff1684a4ef40f254a0157f51b448/ruff-0.9.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37c892540108314a6f01f105040b5106aeb829fa5fb0561d2dcaf71485021137", size = 11882221 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/d1/757559995c8ba5f14dfec4459ef2dd3fcea82ac43bc4e7c7bf47484180c0/ruff-0.9.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de9edf2ce4b9ddf43fd93e20ef635a900e25f622f87ed6e3047a664d0e8f810e", size = 11424862 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/96/7915a7c6877bb734caa6a2af424045baf6419f685632469643dbd8eb2958/ruff-0.9.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87c90c32357c74f11deb7fbb065126d91771b207bf9bfaaee01277ca59b574ec", size = 12626735 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/cc/dadb9b35473d7cb17c7ffe4737b4377aeec519a446ee8514123ff4a26091/ruff-0.9.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56acd6c694da3695a7461cc55775f3a409c3815ac467279dfa126061d84b314b", size = 13255976 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/c3/ad2dd59d3cabbc12df308cced780f9c14367f0321e7800ca0fe52849da4c/ruff-0.9.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0c93e7d47ed951b9394cf352d6695b31498e68fd5782d6cbc282425655f687a", size = 12752262 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/17/5f1971e54bd71604da6788efd84d66d789362b1105e17e5ccc53bba0289b/ruff-0.9.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4c8772670aecf037d1bf7a07c39106574d143b26cfe5ed1787d2f31e800214", size = 14401648 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/24/6200b13ea611b83260501b6955b764bb320e23b2b75884c60ee7d3f0b68e/ruff-0.9.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfc5f1d7afeda8d5d37660eeca6d389b142d7f2b5a1ab659d9214ebd0e025231", size = 12414702 },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/cb/f5d50d0c4ecdcc7670e348bd0b11878154bc4617f3fdd1e8ad5297c0d0ba/ruff-0.9.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faa935fc00ae854d8b638c16a5f1ce881bc3f67446957dd6f2af440a5fc8526b", size = 11859608 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/f4/9c8499ae8426da48363bbb78d081b817b0f64a9305f9b7f87eab2a8fb2c1/ruff-0.9.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a6c634fc6f5a0ceae1ab3e13c58183978185d131a29c425e4eaa9f40afe1e6d6", size = 11485702 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/59/30490e483e804ccaa8147dd78c52e44ff96e1c30b5a95d69a63163cdb15b/ruff-0.9.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:433dedf6ddfdec7f1ac7575ec1eb9844fa60c4c8c2f8887a070672b8d353d34c", size = 12067782 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/8c/893fa9551760b2f8eb2a351b603e96f15af167ceaf27e27ad873570bc04c/ruff-0.9.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d612dbd0f3a919a8cc1d12037168bfa536862066808960e0cc901404b77968f0", size = 12483087 },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/15/f6751c07c21ca10e3f4a51ea495ca975ad936d780c347d9808bcedbd7182/ruff-0.9.4-py3-none-win32.whl", hash = "sha256:db1192ddda2200671f9ef61d9597fcef89d934f5d1705e571a93a67fb13a4402", size = 9852302 },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/41/2d2d2c6a72e62566f730e49254f602dfed23019c33b5b21ea8f8917315a1/ruff-0.9.4-py3-none-win_amd64.whl", hash = "sha256:05bebf4cdbe3ef75430d26c375773978950bbf4ee3c95ccb5448940dc092408e", size = 10850051 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/e6/3d6ec3bc3d254e7f005c543a661a41c3e788976d0e52a1ada195bd664344/ruff-0.9.4-py3-none-win_arm64.whl", hash = "sha256:585792f1e81509e38ac5123492f8875fbc36f3ede8185af0a26df348e5154f41", size = 10078251 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue