diff --git a/.github/workflows/daily.yaml b/.github/workflows/daily.yaml index 24f2983..72f55d7 100644 --- a/.github/workflows/daily.yaml +++ b/.github/workflows/daily.yaml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] - keycloak-version: ["20.0", "21.0", "22.0", "23.0", "24.0", "latest"] + keycloak-version: ["21.0", "22.0", "23.0", "24.0", "25.0", "latest"] env: KEYCLOAK_DOCKER_IMAGE_TAG: ${{ matrix.keycloak-version }} steps: diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 4553417..9cef1c3 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -56,7 +56,7 @@ jobs: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] - keycloak-version: ["20.0", "21.0", "22.0", "23.0", "24.0", "latest"] + keycloak-version: ["21.0", "22.0", "23.0", "24.0", "25.0", "latest"] needs: - check-commits - check-linting diff --git a/README.md b/README.md index 52244a3..2a9847f 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,11 @@ in order to give our user base more time for smoother upgrades. Current list of supported Keycloak versions: +- 25.X - 24.X - 23.X - 22.X - 21.X -- 20.X ## Python version support diff --git a/poetry.lock b/poetry.lock index 9331ca5..5f57a92 100644 --- a/poetry.lock +++ b/poetry.lock @@ -163,13 +163,13 @@ files = [ [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -506,43 +506,43 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.7" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, - {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, - {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, - {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, - {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, - {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, - {file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] @@ -632,18 +632,18 @@ test = ["pytest (>=6)"] [[package]] name = "filelock" -version = "3.14.0" +version = "3.15.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, - {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, + {file = "filelock-3.15.1-py3-none-any.whl", hash = "sha256:71b3102950e91dfc1bb4209b64be4dc8854f40e5f534428d8684f953ac847fac"}, + {file = "filelock-3.15.1.tar.gz", hash = "sha256:58a2549afdf9e02e10720eaa4d4470f56386d7a6f72edd7d0596337af8ed7ad8"}, ] [package.extras] docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] @@ -1115,13 +1115,13 @@ files = [ [[package]] name = "more-itertools" -version = "10.2.0" +version = "10.3.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.8" files = [ - {file = "more-itertools-10.2.0.tar.gz", hash = "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1"}, - {file = "more_itertools-10.2.0-py3-none-any.whl", hash = "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684"}, + {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, + {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, ] [[package]] @@ -1162,24 +1162,24 @@ files = [ [[package]] name = "nodeenv" -version = "1.9.0" +version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.9.0-py2.py3-none-any.whl", hash = "sha256:508ecec98f9f3330b636d4448c0f1a56fc68017c68f1e7857ebc52acf0eb879a"}, - {file = "nodeenv-1.9.0.tar.gz", hash = "sha256:07f144e90dae547bf0d4ee8da0ee42664a42a04e02ed68e06324348dafe4bdb1"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -1195,13 +1195,13 @@ files = [ [[package]] name = "pkginfo" -version = "1.11.0" +version = "1.11.1" description = "Query metadata from sdists / bdists / installed packages." optional = false python-versions = ">=3.8" files = [ - {file = "pkginfo-1.11.0-py3-none-any.whl", hash = "sha256:6d4998d1cd42c297af72cc0eab5f5bab1d356fb8a55b828fa914173f8bc1ba05"}, - {file = "pkginfo-1.11.0.tar.gz", hash = "sha256:dba885aa82e31e80d615119874384923f4e011c2a39b0c4b7104359e36cb7087"}, + {file = "pkginfo-1.11.1-py3-none-any.whl", hash = "sha256:bfa76a714fdfc18a045fcd684dbfc3816b603d9d075febef17cb6582bea29573"}, + {file = "pkginfo-1.11.1.tar.gz", hash = "sha256:2e0dca1cf4c8e39644eed32408ea9966ee15e0d324c62ba899a393b3c6b467aa"}, ] [package.extras] @@ -1355,13 +1355,13 @@ testing = ["covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytes [[package]] name = "pytest" -version = "8.2.1" +version = "8.2.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, - {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, + {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, + {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, ] [package.dependencies] @@ -1921,13 +1921,13 @@ files = [ [[package]] name = "tox" -version = "4.15.0" +version = "4.15.1" description = "tox is a generic virtualenv management and test command line tool" optional = false python-versions = ">=3.8" files = [ - {file = "tox-4.15.0-py3-none-any.whl", hash = "sha256:300055f335d855b2ab1b12c5802de7f62a36d4fd53f30bd2835f6a201dda46ea"}, - {file = "tox-4.15.0.tar.gz", hash = "sha256:7a0beeef166fbe566f54f795b4906c31b428eddafc0102ac00d20998dd1933f6"}, + {file = "tox-4.15.1-py3-none-any.whl", hash = "sha256:f00a5dc4222b358e69694e47e3da0227ac41253509bca9f45aa8f012053e8d9d"}, + {file = "tox-4.15.1.tar.gz", hash = "sha256:53a092527d65e873e39213ebd4bd027a64623320b6b0326136384213f95b7076"}, ] [package.dependencies] @@ -1970,13 +1970,13 @@ urllib3 = ">=1.26.0" [[package]] name = "typing-extensions" -version = "4.12.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -2043,18 +2043,18 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "zipp" -version = "3.19.1" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.1-py3-none-any.whl", hash = "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091"}, - {file = "zipp-3.19.1.tar.gz", hash = "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" diff --git a/tests/test_keycloak_admin.py b/tests/test_keycloak_admin.py index 600bab6..c658846 100644 --- a/tests/test_keycloak_admin.py +++ b/tests/test_keycloak_admin.py @@ -1220,7 +1220,10 @@ def test_clients(admin: KeycloakAdmin, realm: str): with pytest.raises(KeycloakGetError) as err: admin.get_client_service_account_user(client_id=client_id) - assert err.match(UNKOWN_ERROR_REGEX) + + assert ('b\'{"error":"Service account not enabled for the client' in str(err)) or err.match( + UNKOWN_ERROR_REGEX + ) # Test delete client res = admin.delete_client(client_id=auth_client_id) @@ -1665,7 +1668,7 @@ def test_client_default_client_scopes(admin: KeycloakAdmin, realm: str, client: # Test get client default scopes # keycloak default roles: web-origins, acr, profile, roles, email default_client_scopes = admin.get_client_default_client_scopes(client_id) - assert len(default_client_scopes) == 5, default_client_scopes + assert len(default_client_scopes) in [6, 5], default_client_scopes # Test add a client scope to client default scopes default_client_scope = "test-client-default-scope" @@ -1685,12 +1688,12 @@ def test_client_default_client_scopes(admin: KeycloakAdmin, realm: str, client: client_id, new_client_scope_id, new_default_client_scope_data ) default_client_scopes = admin.get_client_default_client_scopes(client_id) - assert len(default_client_scopes) == 6, default_client_scopes + assert len(default_client_scopes) in [6, 7], default_client_scopes # Test remove a client default scope admin.delete_client_default_client_scope(client_id, new_client_scope_id) default_client_scopes = admin.get_client_default_client_scopes(client_id) - assert len(default_client_scopes) == 5, default_client_scopes + assert len(default_client_scopes) in [5, 6], default_client_scopes def test_client_optional_client_scopes(admin: KeycloakAdmin, realm: str, client: str): @@ -2170,7 +2173,7 @@ def test_auth_flows(admin: KeycloakAdmin, realm: str): # Test copying with pytest.raises(KeycloakPostError) as err: admin.copy_authentication_flow(payload=dict(), flow_alias="bad") - assert err.match("404: b''") + assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''") res = admin.copy_authentication_flow(payload={"newName": "test-browser"}, flow_alias="browser") assert res == b"", res @@ -2193,23 +2196,26 @@ def test_auth_flows(admin: KeycloakAdmin, realm: str): assert len(res) == 8, res with pytest.raises(KeycloakGetError) as err: admin.get_authentication_flow_executions(flow_alias="bad") - assert err.match("404: b''") + assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''") exec_id = res[0]["id"] res = admin.get_authentication_flow_execution(execution_id=exec_id) - assert set(res.keys()) == { - "alternative", - "authenticator", - "authenticatorFlow", - "conditional", - "disabled", - "enabled", - "id", - "parentFlow", - "priority", - "required", - "requirement", - }, res + assert set(res.keys()).issubset( + { + "alternative", + "authenticator", + "authenticatorFlow", + "autheticatorFlow", + "conditional", + "disabled", + "enabled", + "id", + "parentFlow", + "priority", + "required", + "requirement", + } + ), res.keys() with pytest.raises(KeycloakGetError) as err: admin.get_authentication_flow_execution(execution_id="bad") assert err.match(ILLEGAL_EXECUTION_REGEX) @@ -2232,7 +2238,7 @@ def test_auth_flows(admin: KeycloakAdmin, realm: str): payload = admin.get_authentication_flow_executions(flow_alias="test-create")[0] payload["displayName"] = "test" res = admin.update_authentication_flow_executions(payload=payload, flow_alias="test-create") - assert res + assert res or (res == {}) exec_id = admin.get_authentication_flow_executions(flow_alias="test-create")[0]["id"] res = admin.delete_authentication_flow_execution(execution_id=exec_id) @@ -2278,7 +2284,9 @@ def test_auth_flows(admin: KeycloakAdmin, realm: str): assert res == dict() with pytest.raises(KeycloakDeleteError) as err: admin.delete_authentication_flow(flow_id=flow_id) - assert err.match('404: b\'{"error":"Could not find flow with id".*}\'') + assert ('b\'{"error":"Could not find flow with id"' in str(err)) or ( + 'b\'{"error":"Flow not found"' in str(err) + ) def test_authentication_configs(admin: KeycloakAdmin, realm: str): @@ -2348,7 +2356,7 @@ def test_client_scopes(admin: KeycloakAdmin, realm: str): # Test get client scopes res = admin.get_client_scopes() scope_names = {x["name"] for x in res} - assert len(res) == 10 + assert len(res) in [10, 11] assert "email" in scope_names assert "profile" in scope_names assert "offline_access" in scope_names @@ -2364,12 +2372,18 @@ def test_client_scopes(admin: KeycloakAdmin, realm: str): assert res[0] == scope # Test create client scope - res = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True) + res = admin.create_client_scope( + payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True + ) assert res - res2 = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True) + res2 = admin.create_client_scope( + payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True + ) assert res == res2 with pytest.raises(KeycloakPostError) as err: - admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=False) + admin.create_client_scope( + payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=False + ) assert err.match('409: b\'{"errorMessage":"Client Scope test-scope already exists"}\'') # Test update client scope @@ -2433,7 +2447,7 @@ def test_client_scopes(admin: KeycloakAdmin, realm: str): # Test default default scopes res_defaults = admin.get_default_default_client_scopes() - assert len(res_defaults) == 6 + assert len(res_defaults) in [6, 7] with pytest.raises(KeycloakPutError) as err: admin.add_default_default_client_scope(scope_id="does-not-exist") @@ -2441,7 +2455,7 @@ def test_client_scopes(admin: KeycloakAdmin, realm: str): res_add = admin.add_default_default_client_scope(scope_id=res) assert res_add == dict() - assert len(admin.get_default_default_client_scopes()) == 7 + assert len(admin.get_default_default_client_scopes()) in [7, 8] with pytest.raises(KeycloakDeleteError) as err: admin.delete_default_default_client_scope(scope_id="does-not-exist") @@ -2449,7 +2463,7 @@ def test_client_scopes(admin: KeycloakAdmin, realm: str): res_del = admin.delete_default_default_client_scope(scope_id=res) assert res_del == dict() - assert len(admin.get_default_default_client_scopes()) == 6 + assert len(admin.get_default_default_client_scopes()) in [6, 7] # Test default optional scopes res_defaults = admin.get_default_optional_client_scopes() @@ -4193,7 +4207,9 @@ async def test_a_clients(admin: KeycloakAdmin, realm: str): with pytest.raises(KeycloakGetError) as err: await admin.a_get_client_service_account_user(client_id=client_id) - assert err.match(UNKOWN_ERROR_REGEX) + assert ('b\'{"error":"Service account not enabled for the client' in str(err)) or err.match( + UNKOWN_ERROR_REGEX + ) # Test delete client res = await admin.a_delete_client(client_id=auth_client_id) @@ -4654,7 +4670,7 @@ async def test_a_client_default_client_scopes(admin: KeycloakAdmin, realm: str, # Test get client default scopes # keycloak default roles: web-origins, acr, profile, roles, email default_client_scopes = await admin.a_get_client_default_client_scopes(client_id) - assert len(default_client_scopes) == 5, default_client_scopes + assert len(default_client_scopes) in [6, 5], default_client_scopes # Test add a client scope to client default scopes default_client_scope = "test-client-default-scope" @@ -4674,12 +4690,12 @@ async def test_a_client_default_client_scopes(admin: KeycloakAdmin, realm: str, client_id, new_client_scope_id, new_default_client_scope_data ) default_client_scopes = await admin.a_get_client_default_client_scopes(client_id) - assert len(default_client_scopes) == 6, default_client_scopes + assert len(default_client_scopes) in [6, 7], default_client_scopes # Test remove a client default scope await admin.a_delete_client_default_client_scope(client_id, new_client_scope_id) default_client_scopes = await admin.a_get_client_default_client_scopes(client_id) - assert len(default_client_scopes) == 5, default_client_scopes + assert len(default_client_scopes) in [5, 6], default_client_scopes @pytest.mark.asyncio @@ -5200,7 +5216,7 @@ async def test_a_auth_flows(admin: KeycloakAdmin, realm: str): # Test copying with pytest.raises(KeycloakPostError) as err: await admin.a_copy_authentication_flow(payload=dict(), flow_alias="bad") - assert err.match("404: b''") + assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''") res = await admin.a_copy_authentication_flow( payload={"newName": "test-browser"}, flow_alias="browser" @@ -5227,23 +5243,26 @@ async def test_a_auth_flows(admin: KeycloakAdmin, realm: str): assert len(res) == 8, res with pytest.raises(KeycloakGetError) as err: await admin.a_get_authentication_flow_executions(flow_alias="bad") - assert err.match("404: b''") + assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''") exec_id = res[0]["id"] res = await admin.a_get_authentication_flow_execution(execution_id=exec_id) - assert set(res.keys()) == { - "alternative", - "authenticator", - "authenticatorFlow", - "conditional", - "disabled", - "enabled", - "id", - "parentFlow", - "priority", - "required", - "requirement", - }, res + assert set(res.keys()).issubset( + { + "alternative", + "authenticator", + "authenticatorFlow", + "autheticatorFlow", + "conditional", + "disabled", + "enabled", + "id", + "parentFlow", + "priority", + "required", + "requirement", + } + ), res.keys() with pytest.raises(KeycloakGetError) as err: await admin.a_get_authentication_flow_execution(execution_id="bad") assert err.match(ILLEGAL_EXECUTION_REGEX) @@ -5268,7 +5287,7 @@ async def test_a_auth_flows(admin: KeycloakAdmin, realm: str): res = await admin.a_update_authentication_flow_executions( payload=payload, flow_alias="test-create" ) - assert res + assert res or (res == {}) exec_id = (await admin.a_get_authentication_flow_executions(flow_alias="test-create"))[0]["id"] res = await admin.a_delete_authentication_flow_execution(execution_id=exec_id) @@ -5314,7 +5333,9 @@ async def test_a_auth_flows(admin: KeycloakAdmin, realm: str): assert res == dict() with pytest.raises(KeycloakDeleteError) as err: await admin.a_delete_authentication_flow(flow_id=flow_id) - assert err.match('404: b\'{"error":"Could not find flow with id".*}\'') + assert ('b\'{"error":"Could not find flow with id"' in str(err)) or ( + 'b\'{"error":"Flow not found"' in str(err) + ) @pytest.mark.asyncio @@ -5387,7 +5408,7 @@ async def test_a_client_scopes(admin: KeycloakAdmin, realm: str): # Test get client scopes res = await admin.a_get_client_scopes() scope_names = {x["name"] for x in res} - assert len(res) == 10 + assert len(res) in [10, 11] assert "email" in scope_names assert "profile" in scope_names assert "offline_access" in scope_names @@ -5403,12 +5424,18 @@ async def test_a_client_scopes(admin: KeycloakAdmin, realm: str): assert res[0] == scope # Test create client scope - res = await admin.a_create_client_scope(payload={"name": "test-scope"}, skip_exists=True) + res = await admin.a_create_client_scope( + payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True + ) assert res - res2 = await admin.a_create_client_scope(payload={"name": "test-scope"}, skip_exists=True) + res2 = await admin.a_create_client_scope( + payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True + ) assert res == res2 with pytest.raises(KeycloakPostError) as err: - await admin.a_create_client_scope(payload={"name": "test-scope"}, skip_exists=False) + await admin.a_create_client_scope( + payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=False + ) assert err.match('409: b\'{"errorMessage":"Client Scope test-scope already exists"}\'') # Test update client scope @@ -5471,7 +5498,7 @@ async def test_a_client_scopes(admin: KeycloakAdmin, realm: str): # Test default default scopes res_defaults = await admin.a_get_default_default_client_scopes() - assert len(res_defaults) == 6 + assert len(res_defaults) in [6, 7] with pytest.raises(KeycloakPutError) as err: await admin.a_add_default_default_client_scope(scope_id="does-not-exist") @@ -5479,7 +5506,7 @@ async def test_a_client_scopes(admin: KeycloakAdmin, realm: str): res_add = await admin.a_add_default_default_client_scope(scope_id=res) assert res_add == dict() - assert len(await admin.a_get_default_default_client_scopes()) == 7 + assert len(admin.get_default_default_client_scopes()) in [7, 8] with pytest.raises(KeycloakDeleteError) as err: await admin.a_delete_default_default_client_scope(scope_id="does-not-exist") @@ -5487,7 +5514,7 @@ async def test_a_client_scopes(admin: KeycloakAdmin, realm: str): res_del = await admin.a_delete_default_default_client_scope(scope_id=res) assert res_del == dict() - assert len(await admin.a_get_default_default_client_scopes()) == 6 + assert len(admin.get_default_default_client_scopes()) in [6, 7] # Test default optional scopes res_defaults = await admin.a_get_default_optional_client_scopes()