diff --git a/.github/workflows/docker-tests.yml b/.github/workflows/docker-tests.yml index 918f3bcaf1d..647f3e55cdb 100644 --- a/.github/workflows/docker-tests.yml +++ b/.github/workflows/docker-tests.yml @@ -49,28 +49,30 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=min - - name: "Setup Python" + - name: "Create Docker network" + run: docker network create net-test + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: 0.5.24 + enable-cache: true + cache-dependency-glob: "uv.lock" + + - name: "Set up Python" uses: actions/setup-python@v5 with: - python-version: "3.x" - cache: 'pipenv' + python-version-file: "./docker/test/.python-version" - - name: "Install dependencies" + # running serially to reduce test flakiness + - name: Lint and run the tests run: | cd docker/test - python -m pip install --upgrade pipenv wheel - pipenv install --deploy - - - name: "Create Docker network" - run: docker network create net-test - - - name: "Run tests" + uv sync --all-extras --dev --locked + uv run ruff check + uv run pytest tests -n 1 --durations=0 --color=yes env: CROWDSEC_TEST_VERSION: test CROWDSEC_TEST_FLAVORS: ${{ matrix.flavor }} CROWDSEC_TEST_NETWORK: net-test CROWDSEC_TEST_TIMEOUT: 90 - # running serially to reduce test flakiness - run: | - cd docker/test - pipenv run pytest -n 1 --durations=0 --color=yes diff --git a/Dockerfile b/Dockerfile index 880df88dc02..ee6d54abb02 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # vim: set ft=dockerfile: -FROM golang:1.23-alpine3.20 AS build +FROM docker.io/golang:1.23-alpine3.20 AS build ARG BUILD_VERSION @@ -31,7 +31,7 @@ RUN make clean release DOCKER_BUILD=1 BUILD_STATIC=1 CGO_CFLAGS="-D_LARGEFILE64_ # In case we need to remove agents here.. # cscli machines list -o json | yq '.[].machineId' | xargs -r cscli machines delete -FROM alpine:latest AS slim +FROM docker.io/alpine:latest AS slim RUN apk add --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community tzdata bash rsync && \ mkdir -p /staging/etc/crowdsec && \ diff --git a/Dockerfile.debian b/Dockerfile.debian index 5d47f167e99..f37ba02a7c2 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,5 +1,5 @@ # vim: set ft=dockerfile: -FROM golang:1.23-bookworm AS build +FROM docker.io/golang:1.23-bookworm AS build ARG BUILD_VERSION @@ -36,7 +36,7 @@ RUN make clean release DOCKER_BUILD=1 BUILD_STATIC=1 && \ # In case we need to remove agents here.. # cscli machines list -o json | yq '.[].machineId' | xargs -r cscli machines delete -FROM debian:bookworm-slim AS slim +FROM docker.io/debian:bookworm-slim AS slim ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NOWARNINGS="yes" diff --git a/docker/test/.python-version b/docker/test/.python-version new file mode 100644 index 00000000000..e4fba218358 --- /dev/null +++ b/docker/test/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/docker/test/Pipfile b/docker/test/Pipfile deleted file mode 100644 index c57ccb628e8..00000000000 --- a/docker/test/Pipfile +++ /dev/null @@ -1,11 +0,0 @@ -[packages] -pytest-dotenv = "0.5.2" -pytest-xdist = "3.5.0" -pytest-cs = {ref = "0.7.19", git = "https://github.com/crowdsecurity/pytest-cs.git"} - -[dev-packages] -gnureadline = "8.1.2" -ipdb = "0.13.13" - -[requires] -python_version = "*" diff --git a/docker/test/Pipfile.lock b/docker/test/Pipfile.lock deleted file mode 100644 index 99184d9f2a2..00000000000 --- a/docker/test/Pipfile.lock +++ /dev/null @@ -1,604 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "b5d25a7199d15a900b285be1af97cf7b7083c6637d631ad777b454471c8319fe" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "*" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "certifi": { - "hashes": [ - "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", - "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" - ], - "markers": "python_version >= '3.6'", - "version": "==2024.8.30" - }, - "cffi": { - "hashes": [ - "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", - "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", - "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", - "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", - "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", - "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", - "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", - "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", - "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", - "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", - "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", - "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", - "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", - "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", - "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", - "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", - "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", - "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", - "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", - "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", - "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", - "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", - "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", - "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", - "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", - "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", - "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", - "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", - "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", - "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", - "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", - "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", - "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", - "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", - "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", - "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", - "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", - "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", - "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", - "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", - "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", - "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", - "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", - "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", - "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", - "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", - "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", - "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", - "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", - "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", - "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", - "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", - "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", - "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", - "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", - "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", - "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", - "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", - "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", - "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", - "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", - "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", - "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", - "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", - "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", - "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", - "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" - ], - "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.17.1" - }, - "charset-normalizer": { - "hashes": [ - "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", - "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", - "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", - "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", - "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", - "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", - "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", - "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", - "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", - "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", - "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", - "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", - "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", - "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", - "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", - "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", - "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", - "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", - "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", - "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", - "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", - "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", - "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", - "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", - "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", - "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", - "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", - "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", - "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", - "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", - "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", - "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", - "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", - "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", - "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", - "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", - "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", - "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", - "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", - "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", - "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", - "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", - "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", - "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", - "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", - "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", - "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", - "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", - "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", - "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", - "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", - "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", - "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", - "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", - "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", - "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", - "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", - "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", - "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", - "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", - "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", - "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", - "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", - "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", - "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", - "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", - "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", - "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", - "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", - "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", - "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", - "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", - "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", - "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", - "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", - "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", - "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", - "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", - "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", - "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", - "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", - "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", - "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", - "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", - "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", - "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", - "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", - "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", - "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.2" - }, - "cryptography": { - "hashes": [ - "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", - "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", - "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", - "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", - "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", - "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", - "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", - "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", - "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", - "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", - "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", - "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", - "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", - "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", - "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", - "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", - "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", - "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", - "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", - "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", - "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", - "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", - "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", - "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", - "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", - "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", - "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289" - ], - "markers": "python_version >= '3.7'", - "version": "==43.0.1" - }, - "docker": { - "hashes": [ - "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", - "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0" - ], - "markers": "python_version >= '3.8'", - "version": "==7.1.0" - }, - "execnet": { - "hashes": [ - "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", - "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" - ], - "markers": "python_version >= '3.8'", - "version": "==2.1.1" - }, - "idna": { - "hashes": [ - "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", - "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" - ], - "markers": "python_version >= '3.6'", - "version": "==3.10" - }, - "iniconfig": { - "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" - }, - "packaging": { - "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" - ], - "markers": "python_version >= '3.8'", - "version": "==24.1" - }, - "pluggy": { - "hashes": [ - "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", - "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" - ], - "markers": "python_version >= '3.8'", - "version": "==1.5.0" - }, - "psutil": { - "hashes": [ - "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", - "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0", - "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c", - "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", - "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", - "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c", - "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", - "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3", - "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", - "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", - "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6", - "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", - "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c", - "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", - "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", - "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14", - "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==6.0.0" - }, - "pycparser": { - "hashes": [ - "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", - "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" - ], - "markers": "python_version >= '3.8'", - "version": "==2.22" - }, - "pytest": { - "hashes": [ - "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", - "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" - ], - "markers": "python_version >= '3.8'", - "version": "==8.3.3" - }, - "pytest-cs": { - "git": "https://github.com/crowdsecurity/pytest-cs.git", - "ref": "aea7e8549faa32f5e1d1f17755a5db3712396a2a" - }, - "pytest-datadir": { - "hashes": [ - "sha256:1617ed92f9afda0c877e4eac91904b5f779d24ba8f5e438752e3ae39d8d2ee3f", - "sha256:34adf361bcc7b37961bbc1dfa8d25a4829e778bab461703c38a5c50ca9c36dc8" - ], - "markers": "python_version >= '3.8'", - "version": "==1.5.0" - }, - "pytest-dotenv": { - "hashes": [ - "sha256:2dc6c3ac6d8764c71c6d2804e902d0ff810fa19692e95fe138aefc9b1aa73732", - "sha256:40a2cece120a213898afaa5407673f6bd924b1fa7eafce6bda0e8abffe2f710f" - ], - "index": "pypi", - "version": "==0.5.2" - }, - "pytest-xdist": { - "hashes": [ - "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a", - "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.5.0" - }, - "python-dotenv": { - "hashes": [ - "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", - "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" - ], - "markers": "python_version >= '3.8'", - "version": "==1.0.1" - }, - "pyyaml": { - "hashes": [ - "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", - "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", - "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", - "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", - "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", - "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", - "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", - "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", - "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", - "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", - "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", - "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", - "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", - "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", - "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", - "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", - "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", - "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", - "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", - "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", - "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", - "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", - "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", - "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", - "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", - "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", - "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", - "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", - "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", - "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", - "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", - "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", - "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", - "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", - "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", - "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", - "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", - "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", - "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", - "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", - "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", - "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", - "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", - "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", - "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", - "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", - "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", - "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", - "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", - "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", - "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", - "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", - "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.2" - }, - "requests": { - "hashes": [ - "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", - "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" - ], - "markers": "python_version >= '3.8'", - "version": "==2.32.3" - }, - "trustme": { - "hashes": [ - "sha256:5375ad7fb427074bec956592e0d4ee2a4cf4da68934e1ba4bcf4217126bc45e6", - "sha256:ce105b68fb9f6d7ac7a9ee6e95bb2347a22ce4d3be78ef9a6494d5ef890e1e16" - ], - "markers": "python_version >= '3.8'", - "version": "==1.1.0" - }, - "urllib3": { - "hashes": [ - "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", - "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" - ], - "markers": "python_version >= '3.8'", - "version": "==2.2.3" - } - }, - "develop": { - "asttokens": { - "hashes": [ - "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", - "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" - ], - "version": "==2.4.1" - }, - "decorator": { - "hashes": [ - "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", - "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" - ], - "markers": "python_version >= '3.11'", - "version": "==5.1.1" - }, - "executing": { - "hashes": [ - "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", - "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab" - ], - "markers": "python_version >= '3.8'", - "version": "==2.1.0" - }, - "gnureadline": { - "hashes": [ - "sha256:17a651e0c49d4b44e8ccf8992edc5a544e33ed9695d3b940ef002858c2215744", - "sha256:194bafa818d0fc3d46f8d71a8811a297a493c1264d3e2d0a71b1b1ff05f8fc15", - "sha256:1e3a8aaf1d61d351c16ad2d3425caf5768603ff5d0e86ba61da9b8756bdd1b95", - "sha256:264f22e865975a3c2ac1183f431dddd8ff7de5a645b89a801c6a276d800f49f3", - "sha256:2753aa1e46b4260b38da424c6a7da7a3ddac161a0b4e6fb71c1093e9ef3d2e73", - "sha256:2816bac8be6bc0e3aa2301acac76e308137eeef1b618c9e0c95c1f89a139a4d8", - "sha256:2ce5c49ecc54e1df0193e90422806a5940f908553206689aeaa04bc959d3aa9a", - "sha256:33ea248385e0d87a3fada38c9164a5756861aa59d6ee010c8be30eeb41f41b49", - "sha256:3903cba2987d42340f1d85c38d3780e954c95e64bfe1839002c7818aa63f8ac3", - "sha256:4262a6aa356ab22ef642f43a7f94eb42a72d6f0c532edb4e8c6b933f573056d2", - "sha256:49df5a432e4ff39cee1b0632c6d0e5fb304757113e502d70b50e33d9ffa47372", - "sha256:4ad9b10409d969ba42acbf89e58352cf3043a5155c2ee677d061e292336b5479", - "sha256:5e1e2d34b0c4ad81c7b00019fafa6de2faf6969c55fa58229e26267cae34047e", - "sha256:5fde3e6417d9004381e8e9835e0a89d81d2d77eeace9364d2e3d9fb64054d449", - "sha256:72da8bac1eb24b6c8237a33d7019a3f004a3d5ba867337175ed764831d9a2c99", - "sha256:74f2538ac15ff4ef9534823abdef077bb34c7dd343e204a36d978f09e168462f", - "sha256:861936c9b362d96152af2d73ccb6f3e901e70f0e4a2e7e62f4e226e91d349edb", - "sha256:8c4690d6c89dbead0958b19263ae67ef995e6109d6bc880cb0e40720cb1ba301", - "sha256:aa29a18594277ea691f92b0c6627d594c0f3387a6685e2e42038ab3f718c794e", - "sha256:b422ff3a78e281ee2e19b0eff70efa48396284bbefa86b83438d668ea9d038a3", - "sha256:c1bcb32e3b63442570d6425055aa6d5c3b6e8b09b9c7d1f8333e70203166a5a3", - "sha256:c402bc6e107beb015ae18c3d2e11f28375f049e464423ead88b35affe80f9be0", - "sha256:c7971653083a48049abd52baa9c8c0188aee362e7b2dd236fe51ecd4e6bc9bbe", - "sha256:de3d8ea66f1b5d00ed843b8925fc07476b8c838c38e584af8639c6a976a43d08", - "sha256:deb921c2cbc14671bb81f3f33d9363a9d0720203b5d716baee32e51c399e914b", - "sha256:e84e903de1514043e6a22866a1973c2ad5f5717f78e9d54e4d6809c48fbd3d81", - "sha256:ecdc4368bd2f7ae9a22de31b024455222082cb49b98ee69ffd0a59734bf648e1" - ], - "index": "pypi", - "version": "==8.1.2" - }, - "ipdb": { - "hashes": [ - "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", - "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.13" - }, - "ipython": { - "hashes": [ - "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a", - "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35" - ], - "markers": "python_version >= '3.11'", - "version": "==8.28.0" - }, - "jedi": { - "hashes": [ - "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", - "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0" - ], - "markers": "python_version >= '3.6'", - "version": "==0.19.1" - }, - "matplotlib-inline": { - "hashes": [ - "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", - "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca" - ], - "markers": "python_version >= '3.8'", - "version": "==0.1.7" - }, - "parso": { - "hashes": [ - "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", - "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d" - ], - "markers": "python_version >= '3.6'", - "version": "==0.8.4" - }, - "pexpect": { - "hashes": [ - "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", - "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f" - ], - "markers": "sys_platform != 'win32' and sys_platform != 'emscripten'", - "version": "==4.9.0" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90", - "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.48" - }, - "ptyprocess": { - "hashes": [ - "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", - "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" - ], - "version": "==0.7.0" - }, - "pure-eval": { - "hashes": [ - "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", - "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42" - ], - "version": "==0.2.3" - }, - "pygments": { - "hashes": [ - "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", - "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" - ], - "markers": "python_version >= '3.8'", - "version": "==2.18.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "stack-data": { - "hashes": [ - "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", - "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695" - ], - "version": "==0.6.3" - }, - "traitlets": { - "hashes": [ - "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", - "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f" - ], - "markers": "python_version >= '3.8'", - "version": "==5.14.3" - }, - "wcwidth": { - "hashes": [ - "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", - "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5" - ], - "version": "==0.2.13" - } - } -} diff --git a/docker/test/README.md b/docker/test/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docker/test/pyproject.toml b/docker/test/pyproject.toml new file mode 100644 index 00000000000..d32d184424f --- /dev/null +++ b/docker/test/pyproject.toml @@ -0,0 +1,41 @@ +[project] +name = "crowdsec-docker-tests" +version = "0.1.0" +description = "Docker tests for Crowdsec" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "pytest>=8.3.4", + "pytest-cs", + "pytest-dotenv>=0.5.2", + "pytest-xdist>=3.6.1", +] + +[dependency-groups] +dev = [ + "ipdb>=0.13.13", + "ruff>=0.9.3", +] + +[tool.uv.sources] +pytest-cs = { git = "https://github.com/crowdsecurity/pytest-cs" } + +[tool.ruff] + +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 +] + +ignore = [ + "B008", # do not perform function calls in argument defaults +] diff --git a/docker/test/tests/conftest.py b/docker/test/tests/conftest.py index 3498da82660..d32ffa28c37 100644 --- a/docker/test/tests/conftest.py +++ b/docker/test/tests/conftest.py @@ -1,11 +1,6 @@ - pytest_plugins = ("cs",) def pytest_configure(config): - config.addinivalue_line( - 'markers', 'docker: mark tests for lone or manually orchestrated containers' - ) - config.addinivalue_line( - 'markers', 'compose: mark tests for docker compose projects' - ) + config.addinivalue_line("markers", "docker: mark tests for lone or manually orchestrated containers") + config.addinivalue_line("markers", "compose: mark tests for docker compose projects") diff --git a/docker/test/tests/test_agent.py b/docker/test/tests/test_agent.py index e55d11af850..aec1bbdaae8 100644 --- a/docker/test/tests/test_agent.py +++ b/docker/test/tests/test_agent.py @@ -10,12 +10,12 @@ def test_no_agent(crowdsec, flavor): """Test DISABLE_AGENT=true""" env = { - 'DISABLE_AGENT': 'true', + "DISABLE_AGENT": "true", } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*CrowdSec Local API listening on *:8080*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -24,23 +24,25 @@ def test_no_agent(crowdsec, flavor): def test_machine_register(crowdsec, flavor, tmp_path_factory): """A local agent is always registered for use by cscli""" - data_dir = tmp_path_factory.mktemp('data') + data_dir = tmp_path_factory.mktemp("data") env = { - 'DISABLE_AGENT': 'true', + "DISABLE_AGENT": "true", } volumes = { - data_dir: {'bind': '/var/lib/crowdsec/data', 'mode': 'rw'}, + data_dir: {"bind": "/var/lib/crowdsec/data", "mode": "rw"}, } with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: - cs.wait_for_log([ + cs.wait_for_log( + [ "*Generate local agent credentials*", "*CrowdSec Local API listening on *:8080*", - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + ] + ) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -48,27 +50,31 @@ def test_machine_register(crowdsec, flavor, tmp_path_factory): # The local agent is not registered, because we didn't persist local_api_credentials.yaml with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: - cs.wait_for_log([ + cs.wait_for_log( + [ "*Generate local agent credentials*", "*CrowdSec Local API listening on *:8080*", - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + ] + ) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout - config_dir = tmp_path_factory.mktemp('config') + config_dir = tmp_path_factory.mktemp("config") - volumes[config_dir] = {'bind': '/etc/crowdsec', 'mode': 'rw'} + volumes[config_dir] = {"bind": "/etc/crowdsec", "mode": "rw"} with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: - cs.wait_for_log([ + cs.wait_for_log( + [ "*Generate local agent credentials*", "*CrowdSec Local API listening on *:8080*", - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + ] + ) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -76,12 +82,14 @@ def test_machine_register(crowdsec, flavor, tmp_path_factory): # The local agent is now already registered with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: - cs.wait_for_log([ + cs.wait_for_log( + [ "*Local agent already registered*", "*CrowdSec Local API listening on *:8080*", - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + ] + ) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout diff --git a/docker/test/tests/test_agent_only.py b/docker/test/tests/test_agent_only.py index 038b726e324..4e1689e0b9b 100644 --- a/docker/test/tests/test_agent_only.py +++ b/docker/test/tests/test_agent_only.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -from http import HTTPStatus import random +from http import HTTPStatus import pytest @@ -10,19 +10,19 @@ def test_split_lapi_agent(crowdsec, flavor): rand = str(random.randint(0, 10000)) - lapiname = f'lapi-{rand}' - agentname = f'agent-{rand}' + lapiname = f"lapi-{rand}" + agentname = f"agent-{rand}" lapi_env = { - 'AGENT_USERNAME': 'testagent', - 'AGENT_PASSWORD': 'testpassword', + "AGENT_USERNAME": "testagent", + "AGENT_PASSWORD": "testpassword", } agent_env = { - 'AGENT_USERNAME': 'testagent', - 'AGENT_PASSWORD': 'testpassword', - 'DISABLE_LOCAL_API': 'true', - 'LOCAL_API_URL': f'http://{lapiname}:8080', + "AGENT_USERNAME": "testagent", + "AGENT_PASSWORD": "testpassword", + "DISABLE_LOCAL_API": "true", + "LOCAL_API_URL": f"http://{lapiname}:8080", } cs_lapi = crowdsec(name=lapiname, environment=lapi_env, flavor=flavor) @@ -30,10 +30,10 @@ def test_split_lapi_agent(crowdsec, flavor): with cs_lapi as lapi: lapi.wait_for_log("*CrowdSec Local API listening on *:8080*") - lapi.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) + lapi.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) with cs_agent as agent: agent.wait_for_log("*Starting processing data*") - res = agent.cont.exec_run('cscli lapi status') + res = agent.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout diff --git a/docker/test/tests/test_bouncer.py b/docker/test/tests/test_bouncer.py index 98b86de858c..d87aff734c5 100644 --- a/docker/test/tests/test_bouncer.py +++ b/docker/test/tests/test_bouncer.py @@ -5,8 +5,8 @@ """ import hashlib -from http import HTTPStatus import json +from http import HTTPStatus import pytest @@ -21,36 +21,33 @@ def hex512(s): def test_register_bouncer_env(crowdsec, flavor): """Test installing bouncers at startup, from envvar""" - env = { - 'BOUNCER_KEY_bouncer1name': 'bouncer1key', - 'BOUNCER_KEY_bouncer2name': 'bouncer2key' - } + env = {"BOUNCER_KEY_bouncer1name": "bouncer1key", "BOUNCER_KEY_bouncer2name": "bouncer2key"} with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli bouncers list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli bouncers list -o json") assert res.exit_code == 0 j = json.loads(res.output) assert len(j) == 2 bouncer1, bouncer2 = j - assert bouncer1['name'] == 'bouncer1name' - assert bouncer2['name'] == 'bouncer2name' + assert bouncer1["name"] == "bouncer1name" + assert bouncer2["name"] == "bouncer2name" # add a second bouncer at runtime - res = cs.cont.exec_run('cscli bouncers add bouncer3name -k bouncer3key') + res = cs.cont.exec_run("cscli bouncers add bouncer3name -k bouncer3key") assert res.exit_code == 0 - res = cs.cont.exec_run('cscli bouncers list -o json') + res = cs.cont.exec_run("cscli bouncers list -o json") assert res.exit_code == 0 j = json.loads(res.output) assert len(j) == 3 bouncer3 = j[2] - assert bouncer3['name'] == 'bouncer3name' + assert bouncer3["name"] == "bouncer3name" # remove all bouncers - res = cs.cont.exec_run('cscli bouncers delete bouncer1name bouncer2name bouncer3name') + res = cs.cont.exec_run("cscli bouncers delete bouncer1name bouncer2name bouncer3name") assert res.exit_code == 0 - res = cs.cont.exec_run('cscli bouncers list -o json') + res = cs.cont.exec_run("cscli bouncers list -o json") assert res.exit_code == 0 j = json.loads(res.output) assert len(j) == 0 diff --git a/docker/test/tests/test_capi.py b/docker/test/tests/test_capi.py index 08b3a70471e..ad25f7a766f 100644 --- a/docker/test/tests/test_capi.py +++ b/docker/test/tests/test_capi.py @@ -3,6 +3,7 @@ from http import HTTPStatus import pytest + pytestmark = pytest.mark.docker @@ -10,13 +11,13 @@ def test_no_capi(crowdsec, flavor): """Test no CAPI (disabled by default in tests)""" env = { - 'DISABLE_ONLINE_API': 'true', + "DISABLE_ONLINE_API": "true", } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli capi status') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli capi status") assert res.exit_code == 1 assert "You can successfully interact with Central API (CAPI)" not in res.output.decode() @@ -29,17 +30,19 @@ def test_capi(crowdsec, flavor): """Test CAPI""" env = { - 'DISABLE_ONLINE_API': 'false', + "DISABLE_ONLINE_API": "false", } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli capi status') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli capi status") assert res.exit_code == 0 assert "You can successfully interact with Central API (CAPI)" in res.output.decode() - cs.wait_for_log([ - "*Successfully registered to Central API (CAPI)*", - "*Registration to online API done*", - ]) + cs.wait_for_log( + [ + "*Successfully registered to Central API (CAPI)*", + "*Registration to online API done*", + ] + ) diff --git a/docker/test/tests/test_capi_whitelists.py b/docker/test/tests/test_capi_whitelists.py index 19378ba86f0..6cdd5f401f5 100644 --- a/docker/test/tests/test_capi_whitelists.py +++ b/docker/test/tests/test_capi_whitelists.py @@ -1,32 +1,32 @@ #!/usr/bin/env python from http import HTTPStatus -import yaml import pytest +import yaml pytestmark = pytest.mark.docker -def test_capi_whitelists(crowdsec, tmp_path_factory, flavor,): +def test_capi_whitelists( + crowdsec, + tmp_path_factory, + flavor, +): """Test CAPI_WHITELISTS_PATH""" - env = { - "CAPI_WHITELISTS_PATH": "/path/to/whitelists.yaml" - } + env = {"CAPI_WHITELISTS_PATH": "/path/to/whitelists.yaml"} whitelists = tmp_path_factory.mktemp("whitelists") with open(whitelists / "whitelists.yaml", "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"} - } + volumes = {whitelists / "whitelists.yaml": {"bind": "/path/to/whitelists.yaml", "mode": "ro"}} with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli config show-yaml') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli config show-yaml") assert res.exit_code == 0 stdout = res.output.decode() y = yaml.safe_load(stdout) - assert y['api']['server']['capi_whitelists_path'] == '/path/to/whitelists.yaml' + assert y["api"]["server"]["capi_whitelists_path"] == "/path/to/whitelists.yaml" diff --git a/docker/test/tests/test_cold_logs.py b/docker/test/tests/test_cold_logs.py index 6f6c578ebe0..2eb3248ffd7 100644 --- a/docker/test/tests/test_cold_logs.py +++ b/docker/test/tests/test_cold_logs.py @@ -2,16 +2,15 @@ import datetime -from pytest_cs import Status - import pytest +from pytest_cs import Status pytestmark = pytest.mark.docker def test_cold_logs(crowdsec, tmp_path_factory, flavor): env = { - 'DSN': 'file:///var/log/toto.log', + "DSN": "file:///var/log/toto.log", } logs = tmp_path_factory.mktemp("logs") @@ -20,11 +19,11 @@ def test_cold_logs(crowdsec, tmp_path_factory, flavor): with open(logs / "toto.log", "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') + 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") volumes = { - logs / "toto.log": {'bind': '/var/log/toto.log', 'mode': 'ro'}, + logs / "toto.log": {"bind": "/var/log/toto.log", "mode": "ro"}, } # missing type @@ -32,20 +31,22 @@ def test_cold_logs(crowdsec, tmp_path_factory, flavor): with crowdsec(flavor=flavor, environment=env, volumes=volumes, wait_status=Status.EXITED) as cs: cs.wait_for_log("*-dsn requires a -type argument*") - env['TYPE'] = 'syslog' + env["TYPE"] = "syslog" with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: - cs.wait_for_log([ - "*Adding file /var/log/toto.log to filelist*", - "*reading /var/log/toto.log at once*", - "*Ip 1.1.1.172 performed 'crowdsecurity/ssh-bf' (6 events over 5s)*", - "*crowdsec shutdown*" - ]) + cs.wait_for_log( + [ + "*Adding file /var/log/toto.log to filelist*", + "*reading /var/log/toto.log at once*", + "*Ip 1.1.1.172 performed 'crowdsecurity/ssh-bf' (6 events over 5s)*", + "*crowdsec shutdown*", + ] + ) def test_cold_logs_missing_dsn(crowdsec, flavor): env = { - 'TYPE': 'syslog', + "TYPE": "syslog", } with crowdsec(flavor=flavor, environment=env, wait_status=Status.EXITED) as cs: diff --git a/docker/test/tests/test_flavors.py b/docker/test/tests/test_flavors.py index 7e78b8d681b..a48fe428c7b 100644 --- a/docker/test/tests/test_flavors.py +++ b/docker/test/tests/test_flavors.py @@ -15,8 +15,8 @@ def test_cscli_lapi(crowdsec, flavor): """Test if cscli can talk to lapi""" with crowdsec(flavor=flavor) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - x = cs.cont.exec_run('cscli lapi status') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + x = cs.cont.exec_run("cscli lapi status") assert x.exit_code == 0 stdout = x.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -27,35 +27,34 @@ def test_flavor_content(crowdsec, flavor): """Test flavor contents""" with crowdsec(flavor=flavor) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - x = cs.cont.exec_run('ls -1 /var/lib/crowdsec/data/') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + x = cs.cont.exec_run("ls -1 /var/lib/crowdsec/data/") assert x.exit_code == 0 stdout = x.output.decode() - if 'slim' in flavor or 'plugins' in flavor: - assert 'GeoLite2-City.mmdb' not in stdout - assert 'GeoLite2-ASN.mmdb' not in stdout + if "slim" in flavor or "plugins" in flavor: + assert "GeoLite2-City.mmdb" not in stdout + assert "GeoLite2-ASN.mmdb" not in stdout else: - assert 'GeoLite2-City.mmdb' in stdout - assert 'GeoLite2-ASN.mmdb' in stdout - assert 'crowdsec.db' in stdout + assert "GeoLite2-City.mmdb" in stdout + assert "GeoLite2-ASN.mmdb" in stdout + assert "crowdsec.db" in stdout - x = cs.cont.exec_run( - 'ls -1 /usr/local/lib/crowdsec/plugins/') + x = cs.cont.exec_run("ls -1 /usr/local/lib/crowdsec/plugins/") stdout = x.output.decode() - if 'slim' in flavor: + if "slim" in flavor: # the exact return code and full message depend # on the 'ls' implementation (busybox vs coreutils) assert x.exit_code != 0 - assert 'No such file or directory' in stdout - assert 'notification-email' not in stdout - assert 'notification-http' not in stdout - assert 'notification-slack' not in stdout - assert 'notification-splunk' not in stdout - assert 'notification-sentinel' not in stdout + assert "No such file or directory" in stdout + assert "notification-email" not in stdout + assert "notification-http" not in stdout + assert "notification-slack" not in stdout + assert "notification-splunk" not in stdout + assert "notification-sentinel" not in stdout else: assert x.exit_code == 0 - assert 'notification-email' in stdout - assert 'notification-http' in stdout - assert 'notification-slack' in stdout - assert 'notification-splunk' in stdout - assert 'notification-sentinel' in stdout + assert "notification-email" in stdout + assert "notification-http" in stdout + assert "notification-slack" in stdout + assert "notification-splunk" in stdout + assert "notification-sentinel" in stdout diff --git a/docker/test/tests/test_hello.py b/docker/test/tests/test_hello.py index a21fde85044..a3ff4f07a93 100644 --- a/docker/test/tests/test_hello.py +++ b/docker/test/tests/test_hello.py @@ -13,24 +13,23 @@ def test_docker_cli_run(): """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) + res = subprocess.run(["docker", "run", "--rm", "hello-world"], capture_output=True, text=True) assert 0 == res.returncode - assert 'Hello from Docker!' in res.stdout + assert "Hello from Docker!" in res.stdout def test_docker_run(docker_client): """Test if docker run works from the python SDK.""" - output = docker_client.containers.run('hello-world', remove=True) + 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): """Test with python SDK (async).""" - cont = docker_client.containers.run('hello-world', detach=True) - assert cont.status == 'created' - assert cont.attrs['State']['ExitCode'] == 0 + cont = docker_client.containers.run("hello-world", detach=True) + assert cont.status == "created" + assert cont.attrs["State"]["ExitCode"] == 0 lines = cont.logs().decode().splitlines() assert "Hello from Docker!" in lines cont.remove(force=True) diff --git a/docker/test/tests/test_hub.py b/docker/test/tests/test_hub.py index e70555ea855..a7134fcb5c8 100644 --- a/docker/test/tests/test_hub.py +++ b/docker/test/tests/test_hub.py @@ -4,8 +4,8 @@ Test pre-installed hub items. """ -from http import HTTPStatus import json +from http import HTTPStatus import pytest @@ -16,12 +16,12 @@ def test_preinstalled_hub(crowdsec, flavor): """Test hub objects installed in the entrypoint""" with crowdsec(flavor=flavor) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli hub list -o json', stderr=False) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli hub list -o json", stderr=False) assert res.exit_code == 0 j = json.loads(res.output) - collections = {c['name']: c for c in j['collections']} - assert collections['crowdsecurity/linux']['status'] == 'enabled' - parsers = {c['name']: c for c in j['parsers']} - assert parsers['crowdsecurity/whitelists']['status'] == 'enabled' - assert parsers['crowdsecurity/docker-logs']['status'] == 'enabled' + collections = {c["name"]: c for c in j["collections"]} + assert collections["crowdsecurity/linux"]["status"] == "enabled" + parsers = {c["name"]: c for c in j["parsers"]} + assert parsers["crowdsecurity/whitelists"]["status"] == "enabled" + assert parsers["crowdsecurity/docker-logs"]["status"] == "enabled" diff --git a/docker/test/tests/test_hub_collections.py b/docker/test/tests/test_hub_collections.py index 0d1b3ee5e94..71fa698af06 100644 --- a/docker/test/tests/test_hub_collections.py +++ b/docker/test/tests/test_hub_collections.py @@ -4,8 +4,8 @@ Test collection management """ -from http import HTTPStatus import json +from http import HTTPStatus import pytest @@ -14,98 +14,98 @@ def test_install_two_collections(crowdsec, flavor): """Test installing collections at startup""" - it1 = 'crowdsecurity/apache2' - it2 = 'crowdsecurity/asterisk' - env = { - 'COLLECTIONS': f'{it1} {it2}' - } + it1 = "crowdsecurity/apache2" + it2 = "crowdsecurity/asterisk" + env = {"COLLECTIONS": f"{it1} {it2}"} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli collections list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli collections list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name']: c for c in j['collections']} - assert items[it1]['status'] == 'enabled' - assert items[it2]['status'] == 'enabled' - cs.wait_for_log([ - f'*enabling collections:{it1}*', - f'*enabling collections:{it2}*', - ]) + items = {c["name"]: c for c in j["collections"]} + assert items[it1]["status"] == "enabled" + assert items[it2]["status"] == "enabled" + cs.wait_for_log( + [ + f"*enabling collections:{it1}*", + f"*enabling collections:{it2}*", + ] + ) def test_disable_collection(crowdsec, flavor): """Test removing a pre-installed collection at startup""" - it = 'crowdsecurity/linux' - env = { - 'DISABLE_COLLECTIONS': it - } + it = "crowdsecurity/linux" + env = {"DISABLE_COLLECTIONS": it} with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli collections list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli collections list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name'] for c in j['collections']} + items = {c["name"] for c in j["collections"]} assert it not in items - cs.wait_for_log([ - f'*disabling collections:{it}*', - ]) + cs.wait_for_log( + [ + f"*disabling collections:{it}*", + ] + ) def test_install_and_disable_collection(crowdsec, flavor): """Declare a collection to install AND disable: disable wins""" - it = 'crowdsecurity/apache2' + it = "crowdsecurity/apache2" env = { - 'COLLECTIONS': it, - 'DISABLE_COLLECTIONS': it, + "COLLECTIONS": it, + "DISABLE_COLLECTIONS": it, } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli collections list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli collections list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name'] for c in j['collections']} + items = {c["name"] for c in j["collections"]} assert it not in items logs = cs.log_lines() # check that there was no attempt to install - assert not any(f'enabling collections:{it}' in line for line in logs) + assert not any(f"enabling collections:{it}" in line for line in logs) # already done in bats, prividing here as example of a somewhat complex test def test_taint_bubble_up(crowdsec, tmp_path_factory, flavor): - coll = 'crowdsecurity/nginx' - env = { - 'COLLECTIONS': f'{coll}' - } + coll = "crowdsecurity/nginx" + env = {"COLLECTIONS": f"{coll}"} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli collections list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli collections list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name']: c for c in j['collections']} + items = {c["name"]: c for c in j["collections"]} # implicit check for tainted=False - assert items[coll]['status'] == 'enabled' - cs.wait_for_log([ - f'*enabling collections:{coll}*', - ]) + assert items[coll]["status"] == "enabled" + cs.wait_for_log( + [ + f"*enabling collections:{coll}*", + ] + ) - scenario = 'crowdsecurity/http-crawl-non_statics' + scenario = "crowdsecurity/http-crawl-non_statics" # the description won't be read back, it's from the index yq_command = f"yq -e -i '.description=\"tainted\"' /etc/crowdsec/hub/scenarios/{scenario}.yaml" res = cs.cont.exec_run(yq_command) assert res.exit_code == 0 - res = cs.cont.exec_run(f'cscli scenarios inspect {scenario} -o json') + res = cs.cont.exec_run(f"cscli scenarios inspect {scenario} -o json") assert res.exit_code == 0 j = json.loads(res.output) - assert j['tainted'] is True + assert j["tainted"] is True - res = cs.cont.exec_run('cscli collections list -o json') + res = cs.cont.exec_run("cscli collections list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name']: c for c in j['collections']} - assert items['crowdsecurity/nginx']['status'] == 'enabled,tainted' - assert items['crowdsecurity/base-http-scenarios']['status'] == 'enabled,tainted' + items = {c["name"]: c for c in j["collections"]} + assert items["crowdsecurity/nginx"]["status"] == "enabled,tainted" + assert items["crowdsecurity/base-http-scenarios"]["status"] == "enabled,tainted" diff --git a/docker/test/tests/test_hub_parsers.py b/docker/test/tests/test_hub_parsers.py index 8cfaeecf94c..42794d20b42 100644 --- a/docker/test/tests/test_hub_parsers.py +++ b/docker/test/tests/test_hub_parsers.py @@ -4,8 +4,8 @@ Test parser management """ -from http import HTTPStatus import json +from http import HTTPStatus import pytest @@ -14,60 +14,54 @@ def test_install_two_parsers(crowdsec, flavor): """Test installing parsers at startup""" - it1 = 'crowdsecurity/cpanel-logs' - it2 = 'crowdsecurity/cowrie-logs' - env = { - 'PARSERS': f'{it1} {it2}' - } + it1 = "crowdsecurity/cpanel-logs" + it2 = "crowdsecurity/cowrie-logs" + env = {"PARSERS": f"{it1} {it2}"} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_log([ - f'*parsers install "{it1}"*', - f'*parsers install "{it2}"*', - "*Starting processing data*" - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli parsers list -o json') + cs.wait_for_log([f'*parsers install "{it1}"*', f'*parsers install "{it2}"*', "*Starting processing data*"]) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli parsers list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name']: c for c in j['parsers']} - assert items[it1]['status'] == 'enabled' - assert items[it2]['status'] == 'enabled' + items = {c["name"]: c for c in j["parsers"]} + assert items[it1]["status"] == "enabled" + assert items[it2]["status"] == "enabled" # XXX check that the parser is preinstalled by default def test_disable_parser(crowdsec, flavor): """Test removing a pre-installed parser at startup""" - it = 'crowdsecurity/whitelists' - env = { - 'DISABLE_PARSERS': it - } + it = "crowdsecurity/whitelists" + env = {"DISABLE_PARSERS": it} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_log([ - f'*parsers remove "{it}"*', - "*Starting processing data*", - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli parsers list -o json') + cs.wait_for_log( + [ + f'*parsers remove "{it}"*', + "*Starting processing data*", + ] + ) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli parsers list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name'] for c in j['parsers']} + items = {c["name"] for c in j["parsers"]} assert it not in items def test_install_and_disable_parser(crowdsec, flavor): """Declare a parser to install AND disable: disable wins""" - it = 'crowdsecurity/cpanel-logs' + it = "crowdsecurity/cpanel-logs" env = { - 'PARSERS': it, - 'DISABLE_PARSERS': it, + "PARSERS": it, + "DISABLE_PARSERS": it, } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli parsers list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli parsers list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name'] for c in j['parsers']} + items = {c["name"] for c in j["parsers"]} assert it not in items logs = cs.log_lines() # check that there was no attempt to install diff --git a/docker/test/tests/test_hub_postoverflows.py b/docker/test/tests/test_hub_postoverflows.py index 80fdbc2b7bd..69f383cda24 100644 --- a/docker/test/tests/test_hub_postoverflows.py +++ b/docker/test/tests/test_hub_postoverflows.py @@ -4,8 +4,9 @@ Test postoverflow management """ -from http import HTTPStatus import json +from http import HTTPStatus + import pytest pytestmark = pytest.mark.docker @@ -13,24 +14,20 @@ def test_install_two_postoverflows(crowdsec, flavor): """Test installing postoverflows at startup""" - it1 = 'crowdsecurity/cdn-whitelist' - it2 = 'crowdsecurity/ipv6_to_range' - env = { - 'POSTOVERFLOWS': f'{it1} {it2}' - } + it1 = "crowdsecurity/cdn-whitelist" + it2 = "crowdsecurity/ipv6_to_range" + env = {"POSTOVERFLOWS": f"{it1} {it2}"} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_log([ - f'*postoverflows install "{it1}"*', - f'*postoverflows install "{it2}"*', - "*Starting processing data*" - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli postoverflows list -o json') + cs.wait_for_log( + [f'*postoverflows install "{it1}"*', f'*postoverflows install "{it2}"*', "*Starting processing data*"] + ) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli postoverflows list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name']: c for c in j['postoverflows']} - assert items[it1]['status'] == 'enabled' - assert items[it2]['status'] == 'enabled' + items = {c["name"]: c for c in j["postoverflows"]} + assert items[it1]["status"] == "enabled" + assert items[it2]["status"] == "enabled" def test_disable_postoverflow(): @@ -40,18 +37,18 @@ def test_disable_postoverflow(): def test_install_and_disable_postoverflow(crowdsec, flavor): """Declare a postoverflow to install AND disable: disable wins""" - it = 'crowdsecurity/cdn-whitelist' + it = "crowdsecurity/cdn-whitelist" env = { - 'POSTOVERFLOWS': it, - 'DISABLE_POSTOVERFLOWS': it, + "POSTOVERFLOWS": it, + "DISABLE_POSTOVERFLOWS": it, } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli postoverflows list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli postoverflows list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name'] for c in j['postoverflows']} + items = {c["name"] for c in j["postoverflows"]} assert it not in items logs = cs.log_lines() # check that there was no attempt to install diff --git a/docker/test/tests/test_hub_scenarios.py b/docker/test/tests/test_hub_scenarios.py index 2a8c3a275f2..4376a3ce64a 100644 --- a/docker/test/tests/test_hub_scenarios.py +++ b/docker/test/tests/test_hub_scenarios.py @@ -4,8 +4,8 @@ Test scenario management """ -from http import HTTPStatus import json +from http import HTTPStatus import pytest @@ -14,59 +14,48 @@ def test_install_two_scenarios(crowdsec, flavor): """Test installing scenarios at startup""" - it1 = 'crowdsecurity/cpanel-bf-attempt' - it2 = 'crowdsecurity/asterisk_bf' - env = { - 'SCENARIOS': f'{it1} {it2}' - } + it1 = "crowdsecurity/cpanel-bf-attempt" + it2 = "crowdsecurity/asterisk_bf" + env = {"SCENARIOS": f"{it1} {it2}"} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_log([ - f'*scenarios install "{it1}"*', - f'*scenarios install "{it2}"*', - "*Starting processing data*" - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli scenarios list -o json') + cs.wait_for_log([f'*scenarios install "{it1}"*', f'*scenarios install "{it2}"*', "*Starting processing data*"]) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli scenarios list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name']: c for c in j['scenarios']} - assert items[it1]['status'] == 'enabled' - assert items[it2]['status'] == 'enabled' + items = {c["name"]: c for c in j["scenarios"]} + assert items[it1]["status"] == "enabled" + assert items[it2]["status"] == "enabled" def test_disable_scenario(crowdsec, flavor): """Test removing a pre-installed scenario at startup""" - it = 'crowdsecurity/ssh-bf' - env = { - 'DISABLE_SCENARIOS': it - } + it = "crowdsecurity/ssh-bf" + env = {"DISABLE_SCENARIOS": it} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_log([ - f'*scenarios remove "{it}"*', - "*Starting processing data*" - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli scenarios list -o json') + cs.wait_for_log([f'*scenarios remove "{it}"*', "*Starting processing data*"]) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli scenarios list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name'] for c in j['scenarios']} + items = {c["name"] for c in j["scenarios"]} assert it not in items def test_install_and_disable_scenario(crowdsec, flavor): """Declare a scenario to install AND disable: disable wins""" - it = 'crowdsecurity/asterisk_bf' + it = "crowdsecurity/asterisk_bf" env = { - 'SCENARIOS': it, - 'DISABLE_SCENARIOS': it, + "SCENARIOS": it, + "DISABLE_SCENARIOS": it, } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli scenarios list -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli scenarios list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name'] for c in j['scenarios']} + items = {c["name"] for c in j["scenarios"]} assert it not in items logs = cs.cont.logs().decode().splitlines() # check that there was no attempt to install diff --git a/docker/test/tests/test_local_api_url.py b/docker/test/tests/test_local_api_url.py index aa90c9fb798..e38af3fedbe 100644 --- a/docker/test/tests/test_local_api_url.py +++ b/docker/test/tests/test_local_api_url.py @@ -10,12 +10,9 @@ def test_local_api_url_default(crowdsec, flavor): """Test LOCAL_API_URL (default)""" with crowdsec(flavor=flavor) as cs: - cs.wait_for_log([ - "*CrowdSec Local API listening on *:8080*", - "*Starting processing data*" - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + cs.wait_for_log(["*CrowdSec Local API listening on *:8080*", "*Starting processing data*"]) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "on http://0.0.0.0:8080/" in stdout @@ -24,16 +21,11 @@ def test_local_api_url_default(crowdsec, flavor): def test_local_api_url(crowdsec, flavor): """Test LOCAL_API_URL (custom)""" - env = { - "LOCAL_API_URL": "http://127.0.0.1:8080" - } + env = {"LOCAL_API_URL": "http://127.0.0.1:8080"} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_log([ - "*CrowdSec Local API listening on *:8080*", - "*Starting processing data*" - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + cs.wait_for_log(["*CrowdSec Local API listening on *:8080*", "*Starting processing data*"]) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "on http://127.0.0.1:8080/" in stdout @@ -48,16 +40,16 @@ def test_local_api_url_ipv6(crowdsec, flavor): # FIXME: https://forums.docker.com/t/assigning-default-ipv6-addresses/128665/3 # FIXME: https://github.com/moby/moby/issues/41438 - env = { - "LOCAL_API_URL": "http://[::1]:8080" - } + env = {"LOCAL_API_URL": "http://[::1]:8080"} with crowdsec(flavor=flavor, environment=env) as cs: - cs.wait_for_log([ - "*Starting processing data*", - "*CrowdSec Local API listening on [::1]:8080*", - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli lapi status') + cs.wait_for_log( + [ + "*Starting processing data*", + "*CrowdSec Local API listening on [::1]:8080*", + ] + ) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "on http://[::1]:8080/" in stdout diff --git a/docker/test/tests/test_local_item.py b/docker/test/tests/test_local_item.py index 3d6ac2fc954..e4c8e3c165a 100644 --- a/docker/test/tests/test_local_item.py +++ b/docker/test/tests/test_local_item.py @@ -4,8 +4,8 @@ Test bind-mounting local items """ -from http import HTTPStatus import json +from http import HTTPStatus import pytest @@ -15,33 +15,29 @@ def test_inject_local_item(crowdsec, tmp_path_factory, flavor): """Test mounting a custom whitelist at startup""" - localitems = tmp_path_factory.mktemp('localitems') - custom_whitelists = localitems / 'custom_whitelists.yaml' + localitems = tmp_path_factory.mktemp("localitems") + custom_whitelists = localitems / "custom_whitelists.yaml" - with open(custom_whitelists, 'w') as f: + with open(custom_whitelists, "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'} - } + volumes = {custom_whitelists: {"bind": "/etc/crowdsec/parsers/s02-enrich/custom_whitelists.yaml"}} with crowdsec(flavor=flavor, volumes=volumes) as cs: - cs.wait_for_log([ - "*Starting processing data*" - ]) - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) + cs.wait_for_log(["*Starting processing data*"]) + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) # the parser should be enabled - res = cs.cont.exec_run('cscli parsers list -o json') + res = cs.cont.exec_run("cscli parsers list -o json") assert res.exit_code == 0 j = json.loads(res.output) - items = {c['name']: c for c in j['parsers']} - assert items['custom_whitelists.yaml']['status'] == 'enabled,local' + items = {c["name"]: c for c in j["parsers"]} + assert items["custom_whitelists.yaml"]["status"] == "enabled,local" # regression test: the linux collection should not be tainted # (the parsers were not copied from /staging when using "cp -an" with local parsers) - res = cs.cont.exec_run('cscli collections inspect crowdsecurity/linux -o json') + res = cs.cont.exec_run("cscli collections inspect crowdsecurity/linux -o json") assert res.exit_code == 0 j = json.loads(res.output) # crowdsec <= 1.5.5 omits a "tainted" when it's false - assert j.get('tainted', False) is False + assert j.get("tainted", False) is False diff --git a/docker/test/tests/test_metrics.py b/docker/test/tests/test_metrics.py index 8a6d5318156..bd41bdcea41 100644 --- a/docker/test/tests/test_metrics.py +++ b/docker/test/tests/test_metrics.py @@ -12,12 +12,12 @@ def test_metrics_port_default(crowdsec, flavor): metrics_port = 6060 with crowdsec(flavor=flavor) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - cs.wait_for_http(metrics_port, '/metrics', want_status=HTTPStatus.OK) - res = cs.cont.exec_run(f'wget -O - http://127.0.0.1:{metrics_port}/metrics') - if 'executable file not found' in res.output.decode(): + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + cs.wait_for_http(metrics_port, "/metrics", want_status=HTTPStatus.OK) + res = cs.cont.exec_run(f"wget -O - http://127.0.0.1:{metrics_port}/metrics") + if "executable file not found" in res.output.decode(): # TODO: find an alternative to wget - pytest.skip('wget not found') + pytest.skip("wget not found") assert res.exit_code == 0 stdout = res.output.decode() assert "# HELP cs_info Information about Crowdsec." in stdout @@ -25,15 +25,15 @@ def test_metrics_port_default(crowdsec, flavor): def test_metrics_port_default_ipv6(crowdsec, flavor): """Test metrics (ipv6)""" - pytest.skip('ipv6 not supported yet') + pytest.skip("ipv6 not supported yet") port = 6060 with crowdsec(flavor=flavor) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run(f'wget -O - http://[::1]:{port}/metrics') - if 'executable file not found' in res.output.decode(): + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run(f"wget -O - http://[::1]:{port}/metrics") + if "executable file not found" in res.output.decode(): # TODO: find an alternative to wget - pytest.skip('wget not found') + pytest.skip("wget not found") assert res.exit_code == 0 stdout = res.output.decode() assert "# HELP cs_info Information about Crowdsec." in stdout @@ -42,16 +42,14 @@ def test_metrics_port_default_ipv6(crowdsec, flavor): def test_metrics_port(crowdsec, flavor): """Test metrics (custom METRICS_PORT)""" port = 7070 - env = { - "METRICS_PORT": port - } + env = {"METRICS_PORT": port} with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run(f'wget -O - http://127.0.0.1:{port}/metrics') - if 'executable file not found' in res.output.decode(): + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run(f"wget -O - http://127.0.0.1:{port}/metrics") + if "executable file not found" in res.output.decode(): # TODO: find an alternative to wget - pytest.skip('wget not found') + pytest.skip("wget not found") assert res.exit_code == 0 stdout = res.output.decode() assert "# HELP cs_info Information about Crowdsec." in stdout @@ -59,18 +57,16 @@ def test_metrics_port(crowdsec, flavor): def test_metrics_port_ipv6(crowdsec, flavor): """Test metrics (custom METRICS_PORT, ipv6)""" - pytest.skip('ipv6 not supported yet') + pytest.skip("ipv6 not supported yet") port = 7070 - env = { - "METRICS_PORT": port - } + env = {"METRICS_PORT": port} with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run(f'wget -O - http://[::1]:{port}/metrics') - if 'executable file not found' in res.output.decode(): + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run(f"wget -O - http://[::1]:{port}/metrics") + if "executable file not found" in res.output.decode(): # TODO: find an alternative to wget - pytest.skip('wget not found') + pytest.skip("wget not found") assert res.exit_code == 0 stdout = res.output.decode() assert "# HELP cs_info Information about Crowdsec." in stdout diff --git a/docker/test/tests/test_nolapi.py b/docker/test/tests/test_nolapi.py index 6edb354fe75..e5dbc3c2624 100644 --- a/docker/test/tests/test_nolapi.py +++ b/docker/test/tests/test_nolapi.py @@ -1,8 +1,7 @@ #!/usr/bin/env python -from pytest_cs import Status - import pytest +from pytest_cs import Status pytestmark = pytest.mark.docker @@ -10,7 +9,7 @@ def test_no_agent(crowdsec, flavor): """Test DISABLE_LOCAL_API=true (failing stand-alone container)""" env = { - 'DISABLE_LOCAL_API': 'true', + "DISABLE_LOCAL_API": "true", } # if an alternative lapi url is not defined, the container should exit diff --git a/docker/test/tests/test_simple.py b/docker/test/tests/test_simple.py index 951d8be4b24..b5c8425b371 100644 --- a/docker/test/tests/test_simple.py +++ b/docker/test/tests/test_simple.py @@ -13,4 +13,4 @@ def test_crowdsec(crowdsec, flavor): 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 "true" == res.output.decode().strip() diff --git a/docker/test/tests/test_tls.py b/docker/test/tests/test_tls.py index d2f512fcbc1..220738a9f07 100644 --- a/docker/test/tests/test_tls.py +++ b/docker/test/tests/test_tls.py @@ -6,9 +6,8 @@ import uuid -from pytest_cs import Status - import pytest +from pytest_cs import Status pytestmark = pytest.mark.docker @@ -17,8 +16,8 @@ def test_missing_key_file(crowdsec, flavor): """Test that cscli and agent can communicate to LAPI with TLS""" env = { - 'CERT_FILE': '/etc/ssl/crowdsec/cert.pem', - 'USE_TLS': 'true', + "CERT_FILE": "/etc/ssl/crowdsec/cert.pem", + "USE_TLS": "true", } with crowdsec(flavor=flavor, environment=env, wait_status=Status.EXITED) as cs: @@ -29,8 +28,8 @@ def test_missing_cert_file(crowdsec, flavor): """Test that cscli and agent can communicate to LAPI with TLS""" env = { - 'KEY_FILE': '/etc/ssl/crowdsec/cert.key', - 'USE_TLS': 'true', + "KEY_FILE": "/etc/ssl/crowdsec/cert.key", + "USE_TLS": "true", } with crowdsec(flavor=flavor, environment=env, wait_status=Status.EXITED) as cs: @@ -41,14 +40,14 @@ def test_tls_missing_ca(crowdsec, flavor, certs_dir): """Missing CA cert, unknown authority""" env = { - 'CERT_FILE': '/etc/ssl/crowdsec/lapi.crt', - 'KEY_FILE': '/etc/ssl/crowdsec/lapi.key', - 'USE_TLS': 'true', - 'LOCAL_API_URL': 'https://localhost:8080', + "CERT_FILE": "/etc/ssl/crowdsec/lapi.crt", + "KEY_FILE": "/etc/ssl/crowdsec/lapi.key", + "USE_TLS": "true", + "LOCAL_API_URL": "https://localhost:8080", } volumes = { - certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname="lapi"): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } with crowdsec(flavor=flavor, environment=env, volumes=volumes, wait_status=Status.EXITED) as cs: @@ -59,22 +58,22 @@ def test_tls_legacy_var(crowdsec, flavor, certs_dir): """Test server-only certificate, legacy variables""" env = { - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'CERT_FILE': '/etc/ssl/crowdsec/lapi.crt', - 'KEY_FILE': '/etc/ssl/crowdsec/lapi.key', - 'USE_TLS': 'true', - 'LOCAL_API_URL': 'https://localhost:8080', + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "CERT_FILE": "/etc/ssl/crowdsec/lapi.crt", + "KEY_FILE": "/etc/ssl/crowdsec/lapi.key", + "USE_TLS": "true", + "LOCAL_API_URL": "https://localhost:8080", } volumes = { - certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname="lapi"): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: cs.wait_for_log("*Starting processing data*") # TODO: wait_for_https - cs.wait_for_http(8080, '/health', want_status=None) - x = cs.cont.exec_run('cscli lapi status') + cs.wait_for_http(8080, "/health", want_status=None) + x = cs.cont.exec_run("cscli lapi status") assert x.exit_code == 0 stdout = x.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -84,24 +83,24 @@ def test_tls_mutual_monolith(crowdsec, flavor, certs_dir): """Server and client certificates, on the same container""" env = { - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt', - 'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key', - 'CLIENT_CERT_FILE': '/etc/ssl/crowdsec/agent.crt', - 'CLIENT_KEY_FILE': '/etc/ssl/crowdsec/agent.key', - 'USE_TLS': 'true', - 'LOCAL_API_URL': 'https://localhost:8080', + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "LAPI_CERT_FILE": "/etc/ssl/crowdsec/lapi.crt", + "LAPI_KEY_FILE": "/etc/ssl/crowdsec/lapi.key", + "CLIENT_CERT_FILE": "/etc/ssl/crowdsec/agent.crt", + "CLIENT_KEY_FILE": "/etc/ssl/crowdsec/agent.key", + "USE_TLS": "true", + "LOCAL_API_URL": "https://localhost:8080", } volumes = { - certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname="lapi"): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: cs.wait_for_log("*Starting processing data*") # TODO: wait_for_https - cs.wait_for_http(8080, '/health', want_status=None) - x = cs.cont.exec_run('cscli lapi status') + cs.wait_for_http(8080, "/health", want_status=None) + x = cs.cont.exec_run("cscli lapi status") assert x.exit_code == 0 stdout = x.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -111,26 +110,27 @@ def test_tls_lapi_var(crowdsec, flavor, certs_dir): """Test server-only certificate, lapi variables""" env = { - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt', - 'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key', - 'USE_TLS': 'true', - 'LOCAL_API_URL': 'https://localhost:8080', + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "LAPI_CERT_FILE": "/etc/ssl/crowdsec/lapi.crt", + "LAPI_KEY_FILE": "/etc/ssl/crowdsec/lapi.key", + "USE_TLS": "true", + "LOCAL_API_URL": "https://localhost:8080", } volumes = { - certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname="lapi"): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs: cs.wait_for_log("*Starting processing data*") # TODO: wait_for_https - cs.wait_for_http(8080, '/health', want_status=None) - x = cs.cont.exec_run('cscli lapi status') + cs.wait_for_http(8080, "/health", want_status=None) + x = cs.cont.exec_run("cscli lapi status") assert x.exit_code == 0 stdout = x.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout + # TODO: bad lapi hostname # the cert is valid, but has a CN that doesn't match the hostname # we must set insecure_skip_verify to true to use it @@ -140,50 +140,49 @@ def test_tls_split_lapi_agent(crowdsec, flavor, certs_dir): """Server-only certificate, split containers""" rand = uuid.uuid1() - lapiname = 'lapi-' + str(rand) - agentname = 'agent-' + str(rand) + lapiname = "lapi-" + str(rand) + agentname = "agent-" + str(rand) lapi_env = { - 'USE_TLS': 'true', - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt', - 'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key', - 'AGENT_USERNAME': 'testagent', - 'AGENT_PASSWORD': 'testpassword', - 'LOCAL_API_URL': 'https://localhost:8080', + "USE_TLS": "true", + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "LAPI_CERT_FILE": "/etc/ssl/crowdsec/lapi.crt", + "LAPI_KEY_FILE": "/etc/ssl/crowdsec/lapi.key", + "AGENT_USERNAME": "testagent", + "AGENT_PASSWORD": "testpassword", + "LOCAL_API_URL": "https://localhost:8080", } agent_env = { - 'USE_TLS': 'true', - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'AGENT_USERNAME': 'testagent', - 'AGENT_PASSWORD': 'testpassword', - 'LOCAL_API_URL': f'https://{lapiname}:8080', - 'DISABLE_LOCAL_API': 'true', - 'CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF': 'false', + "USE_TLS": "true", + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "AGENT_USERNAME": "testagent", + "AGENT_PASSWORD": "testpassword", + "LOCAL_API_URL": f"https://{lapiname}:8080", + "DISABLE_LOCAL_API": "true", + "CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF": "false", } volumes = { - certs_dir(lapi_hostname=lapiname): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname=lapiname): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes) cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes) with cs_lapi as lapi: - lapi.wait_for_log([ - "*(tls) Client Auth Type set to VerifyClientCertIfGiven*", - "*CrowdSec Local API listening on *:8080*" - ]) + lapi.wait_for_log( + ["*(tls) Client Auth Type set to VerifyClientCertIfGiven*", "*CrowdSec Local API listening on *:8080*"] + ) # TODO: wait_for_https - lapi.wait_for_http(8080, '/health', want_status=None) + lapi.wait_for_http(8080, "/health", want_status=None) with cs_agent as agent: agent.wait_for_log("*Starting processing data*") - res = agent.cont.exec_run('cscli lapi status') + res = agent.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout - res = lapi.cont.exec_run('cscli lapi status') + res = lapi.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -193,48 +192,47 @@ def test_tls_mutual_split_lapi_agent(crowdsec, flavor, certs_dir): """Server and client certificates, split containers""" rand = uuid.uuid1() - lapiname = 'lapi-' + str(rand) - agentname = 'agent-' + str(rand) + lapiname = "lapi-" + str(rand) + agentname = "agent-" + str(rand) lapi_env = { - 'USE_TLS': 'true', - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt', - 'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key', - 'LOCAL_API_URL': 'https://localhost:8080', + "USE_TLS": "true", + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "LAPI_CERT_FILE": "/etc/ssl/crowdsec/lapi.crt", + "LAPI_KEY_FILE": "/etc/ssl/crowdsec/lapi.key", + "LOCAL_API_URL": "https://localhost:8080", } agent_env = { - 'USE_TLS': 'true', - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'CLIENT_CERT_FILE': '/etc/ssl/crowdsec/agent.crt', - 'CLIENT_KEY_FILE': '/etc/ssl/crowdsec/agent.key', - 'LOCAL_API_URL': f'https://{lapiname}:8080', - 'DISABLE_LOCAL_API': 'true', - 'CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF': 'false', + "USE_TLS": "true", + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "CLIENT_CERT_FILE": "/etc/ssl/crowdsec/agent.crt", + "CLIENT_KEY_FILE": "/etc/ssl/crowdsec/agent.key", + "LOCAL_API_URL": f"https://{lapiname}:8080", + "DISABLE_LOCAL_API": "true", + "CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF": "false", } volumes = { - certs_dir(lapi_hostname=lapiname): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname=lapiname): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes) cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes) with cs_lapi as lapi: - lapi.wait_for_log([ - "*(tls) Client Auth Type set to VerifyClientCertIfGiven*", - "*CrowdSec Local API listening on *:8080*" - ]) + lapi.wait_for_log( + ["*(tls) Client Auth Type set to VerifyClientCertIfGiven*", "*CrowdSec Local API listening on *:8080*"] + ) # TODO: wait_for_https - lapi.wait_for_http(8080, '/health', want_status=None) + lapi.wait_for_http(8080, "/health", want_status=None) with cs_agent as agent: agent.wait_for_log("*Starting processing data*") - res = agent.cont.exec_run('cscli lapi status') + res = agent.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout - res = lapi.cont.exec_run('cscli lapi status') + res = lapi.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout @@ -244,78 +242,78 @@ def test_tls_client_ou(crowdsec, flavor, certs_dir): """Check behavior of client certificate vs AGENTS_ALLOWED_OU""" rand = uuid.uuid1() - lapiname = 'lapi-' + str(rand) - agentname = 'agent-' + str(rand) + lapiname = "lapi-" + str(rand) + agentname = "agent-" + str(rand) lapi_env = { - 'USE_TLS': 'true', - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt', - 'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key', - 'LOCAL_API_URL': 'https://localhost:8080', + "USE_TLS": "true", + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "LAPI_CERT_FILE": "/etc/ssl/crowdsec/lapi.crt", + "LAPI_KEY_FILE": "/etc/ssl/crowdsec/lapi.key", + "LOCAL_API_URL": "https://localhost:8080", } agent_env = { - 'USE_TLS': 'true', - 'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt', - 'CLIENT_CERT_FILE': '/etc/ssl/crowdsec/agent.crt', - 'CLIENT_KEY_FILE': '/etc/ssl/crowdsec/agent.key', - 'LOCAL_API_URL': f'https://{lapiname}:8080', - 'DISABLE_LOCAL_API': 'true', - 'CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF': 'false', + "USE_TLS": "true", + "CACERT_FILE": "/etc/ssl/crowdsec/ca.crt", + "CLIENT_CERT_FILE": "/etc/ssl/crowdsec/agent.crt", + "CLIENT_KEY_FILE": "/etc/ssl/crowdsec/agent.key", + "LOCAL_API_URL": f"https://{lapiname}:8080", + "DISABLE_LOCAL_API": "true", + "CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF": "false", } volumes = { - certs_dir(lapi_hostname=lapiname, agent_ou='custom-client-ou'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname=lapiname, agent_ou="custom-client-ou"): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes) cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes) with cs_lapi as lapi: - lapi.wait_for_log([ - "*(tls) Client Auth Type set to VerifyClientCertIfGiven*", - "*CrowdSec Local API listening on *:8080*" - ]) + lapi.wait_for_log( + ["*(tls) Client Auth Type set to VerifyClientCertIfGiven*", "*CrowdSec Local API listening on *:8080*"] + ) # TODO: wait_for_https - lapi.wait_for_http(8080, '/health', want_status=None) + lapi.wait_for_http(8080, "/health", want_status=None) with cs_agent as agent: - lapi.wait_for_log([ - "*client certificate OU ?custom-client-ou? doesn't match expected OU ?agent-ou?*", - ]) + lapi.wait_for_log( + [ + "*client certificate OU ?custom-client-ou? doesn't match expected OU ?agent-ou?*", + ] + ) - lapi_env['AGENTS_ALLOWED_OU'] = 'custom-client-ou' + lapi_env["AGENTS_ALLOWED_OU"] = "custom-client-ou" # change container names to avoid conflict # recreate certificates because they need the new hostname rand = uuid.uuid1() - lapiname = 'lapi-' + str(rand) - agentname = 'agent-' + str(rand) + lapiname = "lapi-" + str(rand) + agentname = "agent-" + str(rand) - agent_env['LOCAL_API_URL'] = f'https://{lapiname}:8080' + agent_env["LOCAL_API_URL"] = f"https://{lapiname}:8080" volumes = { - certs_dir(lapi_hostname=lapiname, agent_ou='custom-client-ou'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'}, + certs_dir(lapi_hostname=lapiname, agent_ou="custom-client-ou"): {"bind": "/etc/ssl/crowdsec", "mode": "ro"}, } cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes) cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes) with cs_lapi as lapi: - lapi.wait_for_log([ - "*(tls) Client Auth Type set to VerifyClientCertIfGiven*", - "*CrowdSec Local API listening on *:8080*" - ]) + lapi.wait_for_log( + ["*(tls) Client Auth Type set to VerifyClientCertIfGiven*", "*CrowdSec Local API listening on *:8080*"] + ) # TODO: wait_for_https - lapi.wait_for_http(8080, '/health', want_status=None) + lapi.wait_for_http(8080, "/health", want_status=None) with cs_agent as agent: agent.wait_for_log("*Starting processing data*") - res = agent.cont.exec_run('cscli lapi status') + res = agent.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout - res = lapi.cont.exec_run('cscli lapi status') + res = lapi.cont.exec_run("cscli lapi status") assert res.exit_code == 0 stdout = res.output.decode() assert "You can successfully interact with Local API (LAPI)" in stdout diff --git a/docker/test/tests/test_version.py b/docker/test/tests/test_version.py index c152d2e4e6c..baac61c36ab 100644 --- a/docker/test/tests/test_version.py +++ b/docker/test/tests/test_version.py @@ -10,9 +10,9 @@ def test_version_docker_platform(crowdsec, flavor): for waiter in cs.log_waiters(): with waiter as matcher: matcher.fnmatch_lines(["*Starting processing data*"]) - res = cs.cont.exec_run('cscli version') + res = cs.cont.exec_run("cscli version") assert res.exit_code == 0 - assert 'Platform: docker' in res.output.decode() - res = cs.cont.exec_run('crowdsec -version') + assert "Platform: docker" in res.output.decode() + res = cs.cont.exec_run("crowdsec -version") assert res.exit_code == 0 - assert 'Platform: docker' in res.output.decode() + assert "Platform: docker" in res.output.decode() diff --git a/docker/test/tests/test_wal.py b/docker/test/tests/test_wal.py index e3edbcaf385..e1fe3d260be 100644 --- a/docker/test/tests/test_wal.py +++ b/docker/test/tests/test_wal.py @@ -11,8 +11,8 @@ def test_use_wal_default(crowdsec, flavor): """Test USE_WAL default""" with crowdsec(flavor=flavor) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli config show --key Config.DbConfig.UseWal -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli config show --key Config.DbConfig.UseWal -o json") assert res.exit_code == 0 stdout = res.output.decode() assert "false" in stdout @@ -21,12 +21,12 @@ def test_use_wal_default(crowdsec, flavor): def test_use_wal_true(crowdsec, flavor): """Test USE_WAL=true""" env = { - 'USE_WAL': 'true', + "USE_WAL": "true", } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli config show --key Config.DbConfig.UseWal -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli config show --key Config.DbConfig.UseWal -o json") assert res.exit_code == 0 stdout = res.output.decode() assert "true" in stdout @@ -35,12 +35,12 @@ def test_use_wal_true(crowdsec, flavor): def test_use_wal_false(crowdsec, flavor): """Test USE_WAL=false""" env = { - 'USE_WAL': 'false', + "USE_WAL": "false", } with crowdsec(flavor=flavor, environment=env) as cs: cs.wait_for_log("*Starting processing data*") - cs.wait_for_http(8080, '/health', want_status=HTTPStatus.OK) - res = cs.cont.exec_run('cscli config show --key Config.DbConfig.UseWal -o json') + cs.wait_for_http(8080, "/health", want_status=HTTPStatus.OK) + res = cs.cont.exec_run("cscli config show --key Config.DbConfig.UseWal -o json") assert res.exit_code == 0 stdout = res.output.decode() assert "false" in stdout diff --git a/docker/test/uv.lock b/docker/test/uv.lock new file mode 100644 index 00000000000..d8cc42c89ab --- /dev/null +++ b/docker/test/uv.lock @@ -0,0 +1,587 @@ +version = 1 +requires-python = ">=3.12" + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, +] + +[[package]] +name = "certifi" +version = "2024.12.14" +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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, + { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, + { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, + { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, + { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, + { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, + { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, + { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, + { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, + { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, + { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, + { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, + { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, + { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, + { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, + { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, + { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, + { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, + { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, + { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, + { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, + { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, + { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, + { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, + { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, + { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, + { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "crowdsec-docker-tests" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "pytest" }, + { name = "pytest-cs" }, + { name = "pytest-dotenv" }, + { name = "pytest-xdist" }, +] + +[package.dev-dependencies] +dev = [ + { name = "ipdb" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "pytest", specifier = ">=8.3.4" }, + { name = "pytest-cs", git = "https://github.com/crowdsecurity/pytest-cs" }, + { name = "pytest-dotenv", specifier = ">=0.5.2" }, + { name = "pytest-xdist", specifier = ">=3.6.1" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ipdb", specifier = ">=0.13.13" }, + { name = "ruff", specifier = ">=0.9.3" }, +] + +[[package]] +name = "cryptography" +version = "44.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/09/8cc67f9b84730ad330b3b72cf867150744bf07ff113cda21a15a1c6d2c7c/cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", size = 6541833 }, + { url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 }, + { url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 }, + { url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 }, + { url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498 }, + { url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 }, + { url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 }, + { url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 }, + { url = "https://files.pythonhosted.org/packages/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 }, + { url = "https://files.pythonhosted.org/packages/64/b1/50d7739254d2002acae64eed4fc43b24ac0cc44bf0a0d388d1ca06ec5bb1/cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", size = 3202055 }, + { url = "https://files.pythonhosted.org/packages/11/18/61e52a3d28fc1514a43b0ac291177acd1b4de00e9301aaf7ef867076ff8a/cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", size = 6542801 }, + { url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 }, + { url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 }, + { url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 }, + { url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160 }, + { url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 }, + { url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 }, + { url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 }, + { url = "https://files.pythonhosted.org/packages/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 }, + { url = "https://files.pythonhosted.org/packages/97/9b/443270b9210f13f6ef240eff73fd32e02d381e7103969dc66ce8e89ee901/cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", size = 3202071 }, +] + +[[package]] +name = "decorator" +version = "5.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, +] + +[[package]] +name = "docker" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774 }, +] + +[[package]] +name = "execnet" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612 }, +] + +[[package]] +name = "executing" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "ipdb" +version = "0.13.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "decorator" }, + { name = "ipython" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130 }, +] + +[[package]] +name = "ipython" +version = "8.31.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/60/d0feb6b6d9fe4ab89fe8fe5b47cbf6cd936bfd9f1e7ffa9d0015425aeed6/ipython-8.31.0-py3-none-any.whl", hash = "sha256:46ec58f8d3d076a61d128fe517a51eb730e3aaf0c184ea8c17d16e366660c6a6", size = 821583 }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } +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 = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.50" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/e1/bd15cb8ffdcfeeb2bdc215de3c3cffca11408d829e4b8416dcfe71ba8854/prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab", size = 429087 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198", size = 387816 }, +] + +[[package]] +name = "psutil" +version = "6.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/5a/07871137bb752428aa4b659f910b399ba6f291156bdea939be3e96cae7cb/psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5", size = 508502 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/99/ca79d302be46f7bdd8321089762dd4476ee725fce16fc2b2e1dbba8cac17/psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8", size = 247511 }, + { url = "https://files.pythonhosted.org/packages/0b/6b/73dbde0dd38f3782905d4587049b9be64d76671042fdcaf60e2430c6796d/psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377", size = 248985 }, + { url = "https://files.pythonhosted.org/packages/17/38/c319d31a1d3f88c5b79c68b3116c129e5133f1822157dd6da34043e32ed6/psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003", size = 284488 }, + { url = "https://files.pythonhosted.org/packages/9c/39/0f88a830a1c8a3aba27fededc642da37613c57cbff143412e3536f89784f/psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160", size = 287477 }, + { url = "https://files.pythonhosted.org/packages/47/da/99f4345d4ddf2845cb5b5bd0d93d554e84542d116934fde07a0c50bd4e9f/psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3", size = 289017 }, + { url = "https://files.pythonhosted.org/packages/38/53/bd755c2896f4461fd4f36fa6a6dcb66a88a9e4b9fd4e5b66a77cf9d4a584/psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53", size = 250602 }, + { url = "https://files.pythonhosted.org/packages/7b/d7/7831438e6c3ebbfa6e01a927127a6cb42ad3ab844247f3c5b96bea25d73d/psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649", size = 254444 }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, +] + +[[package]] +name = "pytest" +version = "8.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, +] + +[[package]] +name = "pytest-cs" +version = "0.7.20" +source = { git = "https://github.com/crowdsecurity/pytest-cs#73380b837a80337f361414bebbaf4b914713c4ae" } +dependencies = [ + { name = "docker" }, + { name = "psutil" }, + { name = "pytest" }, + { name = "pytest-datadir" }, + { name = "pytest-dotenv" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "trustme" }, +] + +[[package]] +name = "pytest-datadir" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/97/a93900d82635aa3f419c3cd2059b4de7d7fe44e415eaf00c298854582dcc/pytest-datadir-1.5.0.tar.gz", hash = "sha256:1617ed92f9afda0c877e4eac91904b5f779d24ba8f5e438752e3ae39d8d2ee3f", size = 8821 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/90/96b9474cddda5ef9e10e6f1871c0fadfa153b605e0e749ba30437bfb62a0/pytest_datadir-1.5.0-py3-none-any.whl", hash = "sha256:34adf361bcc7b37961bbc1dfa8d25a4829e778bab461703c38a5c50ca9c36dc8", size = 5095 }, +] + +[[package]] +name = "pytest-dotenv" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "python-dotenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/b0/cafee9c627c1bae228eb07c9977f679b3a7cb111b488307ab9594ba9e4da/pytest-dotenv-0.5.2.tar.gz", hash = "sha256:2dc6c3ac6d8764c71c6d2804e902d0ff810fa19692e95fe138aefc9b1aa73732", size = 3782 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/da/9da67c67b3d0963160e3d2cbc7c38b6fae342670cc8e6d5936644b2cf944/pytest_dotenv-0.5.2-py3-none-any.whl", hash = "sha256:40a2cece120a213898afaa5407673f6bd924b1fa7eafce6bda0e8abffe2f710f", size = 3993 }, +] + +[[package]] +name = "pytest-xdist" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", size = 46108 }, +] + +[[package]] +name = "python-dotenv" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, +] + +[[package]] +name = "pywin32" +version = "308" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, + { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, + { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, + { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, + { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, + { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "ruff" +version = "0.9.3" +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 } +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 }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, +] + +[[package]] +name = "trustme" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/c5/931476f4cf1cd9e736f32651005078061a50dc164a2569fb874e00eb2786/trustme-1.2.1.tar.gz", hash = "sha256:6528ba2bbc7f2db41f33825c8dd13e3e3eb9d334ba0f909713c8c3139f4ae47f", size = 26844 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/f3/c34dbabf6da5eda56fe923226769d40e11806952cd7f46655dd06e10f018/trustme-1.2.1-py3-none-any.whl", hash = "sha256:d768e5fc57c86dfc5ec9365102e9b092541cd6954b35d8c1eea01a84f35a762a", size = 16530 }, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, +]