From 56a5e37fd37c15d3eb22c3f75dc29ab34cf3f75f Mon Sep 17 00:00:00 2001 From: David Hadley Date: Fri, 19 Dec 2025 10:17:23 +0000 Subject: [PATCH 01/20] feat: Proof-of-concept authentication in workflows with Authoirization Code Flow with PKCE method --- .github/workflows/_oidc_bff_code.yaml | 70 + .github/workflows/_oidc_bff_container.yaml | 53 + .github/workflows/ci.yaml | 14 + backend/Cargo.lock | 1825 ++++++++++++++--- backend/Cargo.toml | 6 +- backend/Dockerfile.auth-daemon | 7 + backend/Dockerfile.graph-proxy | 3 - backend/Dockerfile.oidc-bff | 21 + .../.devcontainer/devcontainer.json | 8 +- backend/auth-daemon/Cargo.toml | 19 +- backend/auth-daemon/src/config.rs | 32 + backend/auth-daemon/src/database.rs | 105 + backend/auth-daemon/src/error.rs | 26 + backend/auth-daemon/src/inject_token.rs | 123 ++ backend/auth-daemon/src/main.rs | 205 +- backend/auth-daemon/src/proxy.rs | 205 -- backend/auth-daemon/src/state.rs | 167 ++ backend/oidc-bff/.cargo/config.toml | 2 + backend/oidc-bff/.devcontainer/Dockerfile | 7 + .../oidc-bff/.devcontainer/devcontainer.json | 23 + .../oidc-bff/.devcontainer/docker-compose.yml | 37 + backend/oidc-bff/Cargo.toml | 40 + backend/oidc-bff/config.yaml | 11 + backend/oidc-bff/migration/Cargo.toml | 23 + backend/oidc-bff/migration/README.md | 41 + backend/oidc-bff/migration/src/lib.rs | 12 + .../src/m20220101_000001_create_table.rs | 56 + backend/oidc-bff/migration/src/main.rs | 6 + backend/oidc-bff/src/auth_proxy.rs | 69 + backend/oidc-bff/src/auth_session_data.rs | 116 ++ backend/oidc-bff/src/bin/keygen.rs | 23 + backend/oidc-bff/src/callback.rs | 113 + backend/oidc-bff/src/config.rs | 33 + backend/oidc-bff/src/counter.rs | 29 + backend/oidc-bff/src/database.rs | 51 + backend/oidc-bff/src/entity/mod.rs | 5 + backend/oidc-bff/src/entity/oidc_tokens.rs | 22 + backend/oidc-bff/src/entity/prelude.rs | 3 + backend/oidc-bff/src/error.rs | 26 + backend/oidc-bff/src/healthcheck.rs | 5 + backend/oidc-bff/src/inject_token.rs | 113 + .../oidc-bff/src/inject_token_from_session.rs | 87 + backend/oidc-bff/src/lib.rs | 1 + backend/oidc-bff/src/login.rs | 49 + backend/oidc-bff/src/main.rs | 115 ++ backend/oidc-bff/src/state.rs | 73 + charts/apps/staging-values.yaml | 4 +- .../apps/templates/dashboard-application.yaml | 2 +- charts/apps/values.yaml | 4 +- charts/dashboard/staging-values.yaml | 13 + charts/dashboard/templates/ingress.yaml | 4 +- charts/dashboard/templates/oidc-bff.yaml | 70 + charts/dashboard/templates/service.yaml | 1 + charts/dashboard/values.yaml | 24 + charts/workflows-cluster/staging-values.yaml | 7 +- .../workflows-cluster/templates/oidc-bff.yaml | 13 + ...secret-postgres-application-passwords.yaml | 19 + ...cret-postgres-argo-workflows-password.yaml | 19 + ...secret-postgres-auth-service-password.yaml | 19 + .../sealed-secret-postgres-initdb-script.yaml | 15 + .../sealed-secret-postgres-passwords.yaml | 19 + charts/workflows/staging-values.yaml | 4 + charts/workflows/templates/_helpers.tpl | 28 + charts/workflows/values.yaml | 4 + .../conventional-templates/workflow-auth.yaml | 66 + .../workflow-of-workflows.yaml | 74 + 66 files changed, 3996 insertions(+), 493 deletions(-) create mode 100644 .github/workflows/_oidc_bff_code.yaml create mode 100644 .github/workflows/_oidc_bff_container.yaml create mode 100644 backend/Dockerfile.oidc-bff create mode 100644 backend/auth-daemon/src/config.rs create mode 100644 backend/auth-daemon/src/database.rs create mode 100644 backend/auth-daemon/src/error.rs create mode 100644 backend/auth-daemon/src/inject_token.rs delete mode 100644 backend/auth-daemon/src/proxy.rs create mode 100644 backend/auth-daemon/src/state.rs create mode 100644 backend/oidc-bff/.cargo/config.toml create mode 100644 backend/oidc-bff/.devcontainer/Dockerfile create mode 100644 backend/oidc-bff/.devcontainer/devcontainer.json create mode 100644 backend/oidc-bff/.devcontainer/docker-compose.yml create mode 100644 backend/oidc-bff/Cargo.toml create mode 100644 backend/oidc-bff/config.yaml create mode 100644 backend/oidc-bff/migration/Cargo.toml create mode 100644 backend/oidc-bff/migration/README.md create mode 100644 backend/oidc-bff/migration/src/lib.rs create mode 100644 backend/oidc-bff/migration/src/m20220101_000001_create_table.rs create mode 100644 backend/oidc-bff/migration/src/main.rs create mode 100644 backend/oidc-bff/src/auth_proxy.rs create mode 100644 backend/oidc-bff/src/auth_session_data.rs create mode 100644 backend/oidc-bff/src/bin/keygen.rs create mode 100644 backend/oidc-bff/src/callback.rs create mode 100644 backend/oidc-bff/src/config.rs create mode 100644 backend/oidc-bff/src/counter.rs create mode 100644 backend/oidc-bff/src/database.rs create mode 100644 backend/oidc-bff/src/entity/mod.rs create mode 100644 backend/oidc-bff/src/entity/oidc_tokens.rs create mode 100644 backend/oidc-bff/src/entity/prelude.rs create mode 100644 backend/oidc-bff/src/error.rs create mode 100644 backend/oidc-bff/src/healthcheck.rs create mode 100644 backend/oidc-bff/src/inject_token.rs create mode 100644 backend/oidc-bff/src/inject_token_from_session.rs create mode 100644 backend/oidc-bff/src/lib.rs create mode 100644 backend/oidc-bff/src/login.rs create mode 100644 backend/oidc-bff/src/main.rs create mode 100644 backend/oidc-bff/src/state.rs create mode 100644 charts/dashboard/templates/oidc-bff.yaml create mode 100644 charts/workflows-cluster/templates/oidc-bff.yaml create mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml create mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml create mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml create mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml create mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml create mode 100644 charts/workflows/templates/_helpers.tpl create mode 100644 examples/conventional-templates/workflow-auth.yaml create mode 100644 examples/conventional-templates/workflow-of-workflows.yaml diff --git a/.github/workflows/_oidc_bff_code.yaml b/.github/workflows/_oidc_bff_code.yaml new file mode 100644 index 000000000..81af7ec8b --- /dev/null +++ b/.github/workflows/_oidc_bff_code.yaml @@ -0,0 +1,70 @@ +name: OIDC BFF Code + +on: + workflow_call: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v5 + + - name: Install stable toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1.15.2 + with: + cache: false + components: clippy,rustfmt + + - name: Cache Rust Build + uses: Swatinem/rust-cache@v2.8.1 + with: + shared-key: backend/oidc-bff + workspaces: backend + + - name: Check Formatting + working-directory: backend/oidc-bff + run: > + cargo fmt + --check + + - name: Lint with Clippy + working-directory: backend/oidc-bff + run: > + cargo clippy + --all-targets + --all-features + --no-deps + -- + --deny warnings + + - name: Check Dependencies with Cargo Deny + uses: EmbarkStudios/cargo-deny-action@v2.0.13 + with: + command: check licenses ban + manifest-path: backend/Cargo.toml + + test: + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v5 + + - name: Install stable toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1.15.2 + with: + cache: false + components: rustfmt + + - name: Cache Rust Build + uses: Swatinem/rust-cache@v2.8.1 + with: + shared-key: backend/oidc-bff + workspaces: backend + + - name: Run Tests + working-directory: backend/oidc-bff + run: > + cargo test + --all-targets + --all-features diff --git a/.github/workflows/_oidc_bff_container.yaml b/.github/workflows/_oidc_bff_container.yaml new file mode 100644 index 000000000..b848627c1 --- /dev/null +++ b/.github/workflows/_oidc_bff_container.yaml @@ -0,0 +1,53 @@ +name: OIDC BFF Container +on: + workflow_call: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout Code + uses: actions/checkout@v5 + + - name: Generate Image Name + run: echo IMAGE_REPOSITORY=ghcr.io/$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]' | tr '[_]' '[\-]')-oidc-bff >> $GITHUB_ENV + + - name: Log in to GitHub Docker Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3.6.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Version from Tag + id: tags + run: echo version=$(echo "${{ github.ref }}" | awk -F '[@v]' '{print $3}') >> $GITHUB_OUTPUT + + - name: Docker Metadata + id: meta + uses: docker/metadata-action@v5.9.0 + with: + images: ${{ env.IMAGE_REPOSITORY }} + tags: | + type=raw,value=${{ steps.tags.outputs.version }} + type=raw,value=latest + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.11.1 + + - name: Build Image + uses: docker/build-push-action@v6.18.0 + with: + context: backend + file: backend/Dockerfile.oidc-bff + target: deploy + push: true + load: ${{ !(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/oidc-bff@')) }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9c7589bd5..2e57696cf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,6 +63,20 @@ jobs: contents: read packages: write + oidc_bff_code: + # Deduplicate jobs from pull requests and branch pushes within the same repo. + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository + uses: ./.github/workflows/_oidc_bff_code.yaml + + oidc_bff_container: + # Deduplicate jobs from pull requests and branch pushes within the same repo. + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository + needs: oidc_bff_code + uses: ./.github/workflows/_oidc_bff_container.yaml + permissions: + contents: read + packages: write + supergraph_update: # Deduplicate jobs from pull requests and branch pushes within the same repo. if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 14033f8ed..d4132130c 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -12,6 +12,32 @@ dependencies = [ "regex", ] +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.12" @@ -34,6 +60,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "allocator-api2" version = "0.2.21" @@ -104,6 +136,9 @@ name = "anyhow" version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +dependencies = [ + "backtrace", +] [[package]] name = "argo-workflows-openapi" @@ -119,6 +154,12 @@ dependencies = [ "typify", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "ascii_utils" version = "0.9.3" @@ -307,6 +348,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-lock" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -361,16 +413,32 @@ version = "0.1.0" dependencies = [ "anyhow", "axum", + "axum-reverse-proxy", + "axum-test", + "base64 0.22.1", + "chrono", "clap", "dotenvy", + "env_logger", + "http-body-util", + "migration", "mockito", + "oauth2", + "oauth2-test-server", + "oidc-bff", + "openidconnect", "regex", - "reqwest 0.12.15", + "reqwest", + "rustls 0.23.35", + "sea-orm", "serde", "serde_json", + "serde_yaml", + "sodiumoxide", + "testcontainers", "thiserror 2.0.17", "tokio", - "tower-http", + "tower-http 0.6.6", "tracing", "tracing-subscriber", "url", @@ -587,13 +655,13 @@ dependencies = [ "http 1.3.1", "http-body 0.4.6", "hyper 0.14.32", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.24.2", "hyper-rustls 0.27.5", "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.28", + "rustls 0.23.35", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", @@ -713,11 +781,12 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" +checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" dependencies = [ "axum-core", + "axum-macros", "base64 0.22.1", "bytes", "form_urlencoded", @@ -725,7 +794,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "itoa", "matchit", @@ -740,7 +809,7 @@ dependencies = [ "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.28.0", "tower", "tower-layer", "tower-service", @@ -788,6 +857,72 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.107", +] + +[[package]] +name = "axum-reverse-proxy" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84bb2eec9f1a2c150ce1204d843d690db0da305f6f2848cbfd4a840c830b4f0b" +dependencies = [ + "axum", + "base64 0.21.7", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-rustls 0.27.5", + "hyper-util", + "rand 0.9.2", + "rustls 0.23.35", + "sha1", + "tokio", + "tokio-tungstenite 0.21.0", + "tower", + "tracing", + "url", +] + +[[package]] +name = "axum-test" +version = "18.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3290e73c56c5cc4701cdd7d46b9ced1b4bd61c7e9f9c769a9e9e87ff617d75d2" +dependencies = [ + "anyhow", + "axum", + "bytes", + "bytesize", + "cookie", + "expect-json", + "http 1.3.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "mime", + "pretty_assertions", + "reserve-port", + "rust-multipart-rfc7578_2", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "tokio", + "tower", + "url", +] + [[package]] name = "backon" version = "1.5.1" @@ -799,6 +934,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link 0.2.0", +] + [[package]] name = "base16ct" version = "0.1.1" @@ -839,6 +989,40 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +[[package]] +name = "bigdecimal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560f42649de9fa436b73517378a147ec21f6c997a546581df4b4b31677828934" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.107", +] + [[package]] name = "bitflags" version = "2.9.0" @@ -848,6 +1032,18 @@ dependencies = [ "serde", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -859,9 +1055,9 @@ dependencies = [ [[package]] name = "bollard" -version = "0.20.2" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" +checksum = "87a52479c9237eb04047ddb94788c41ca0d26eaff8b697ecfbb4c32f7fdc3b1b" dependencies = [ "async-stream", "base64 0.22.1", @@ -869,13 +1065,14 @@ dependencies = [ "bollard-buildkit-proto", "bollard-stubs", "bytes", + "chrono", "futures-core", "futures-util", "hex", "home", "http 1.3.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-named-pipe", "hyper-rustls 0.27.5", "hyper-util", @@ -883,16 +1080,17 @@ dependencies = [ "log", "num", "pin-project-lite", - "rand 0.9.0", - "rustls 0.23.28", + "rand 0.9.2", + "rustls 0.23.35", "rustls-native-certs 0.8.1", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_derive", "serde_json", + "serde_repr", "serde_urlencoded", "thiserror 2.0.17", - "time", "tokio", "tokio-stream", "tokio-util", @@ -917,18 +1115,42 @@ dependencies = [ [[package]] name = "bollard-stubs" -version = "1.52.1-rc.29.1.3" +version = "1.49.1-rc.28.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0a8ca8799131c1837d1282c3f81f31e76ceb0ce426e04a7fe1ccee3287c066" +checksum = "5731fe885755e92beff1950774068e0cae67ea6ec7587381536fca84f1779623" dependencies = [ "base64 0.22.1", "bollard-buildkit-proto", "bytes", + "chrono", "prost", "serde", "serde_json", "serde_repr", - "time", + "serde_with", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.107", ] [[package]] @@ -943,6 +1165,28 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -968,11 +1212,17 @@ dependencies = [ "either", ] +[[package]] +name = "bytesize" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" + [[package]] name = "cc" -version = "1.2.60" +version = "1.2.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" dependencies = [ "find-msvc-tools", "jobserver", @@ -1095,6 +1345,35 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +dependencies = [ + "cookie", + "document-features", + "idna", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1172,6 +1451,24 @@ dependencies = [ "crc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -1438,8 +1735,15 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.107", + "unicode-xid", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.10.7" @@ -1474,6 +1778,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -1518,6 +1831,15 @@ dependencies = [ "spki 0.7.3", ] +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -1535,7 +1857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", - "ed25519", + "ed25519 2.2.3", "serde", "sha2", "subtle", @@ -1604,6 +1926,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" +dependencies = [ + "serde", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1634,26 +1965,60 @@ dependencies = [ ] [[package]] -name = "equivalent" -version = "1.0.2" +name = "env_filter" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] [[package]] -name = "errno" -version = "0.3.11" +name = "env_logger" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ - "libc", - "windows-sys 0.59.0", + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", ] [[package]] -name = "etcetera" -version = "0.8.0" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ "cfg-if", "home", @@ -1702,6 +2067,35 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "expect-json" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422e7906e79941e5ac58c64dfd2da03e6ae3de62227f87606fbbe125d91080f9" +dependencies = [ + "chrono", + "email_address", + "expect-json-macros", + "num", + "regex", + "serde", + "serde_json", + "thiserror 2.0.17", + "typetag", + "uuid", +] + +[[package]] +name = "expect-json-macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bf7f5979e98460a0eb412665514594f68f366a32b85fa8d7ffb65bb1edee6a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.107", +] + [[package]] name = "fast_chemail" version = "0.9.6" @@ -1719,12 +2113,12 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ferroid" -version = "0.8.9" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb330bbd4cb7a5b9f559427f06f98a4f853a137c8298f3bd3f8ca57663e21986" +checksum = "e0e9414a6ae93ef993ce40a1e02944f13d4508e2bf6f1ced1580ce6910f08253" dependencies = [ "portable-atomic", - "rand 0.9.0", + "rand 0.9.2", "web-time", ] @@ -1756,20 +2150,21 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.27" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", "libc", "libredox", + "windows-sys 0.60.2", ] [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "flume" @@ -1794,6 +2189,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1809,6 +2219,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.31" @@ -1966,6 +2382,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "glob" version = "0.3.2" @@ -2015,9 +2437,8 @@ dependencies = [ "opentelemetry", "opentelemetry_sdk", "regex", - "reqwest 0.12.15", - "rstest", - "rustls 0.23.28", + "reqwest", + "rustls 0.23.35", "secrecy", "serde", "serde_json", @@ -2026,11 +2447,10 @@ dependencies = [ "thiserror 2.0.17", "tokio", "tokio-stream", - "tokio-tungstenite", - "tower-http", + "tokio-tungstenite 0.28.0", + "tower-http 0.6.6", "tower-service", "tracing", - "tungstenite", "url", ] @@ -2069,7 +2489,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.17", - "tungstenite", + "tungstenite 0.28.0", ] [[package]] @@ -2190,6 +2610,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] [[package]] name = "hashbrown" @@ -2211,6 +2634,16 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "hdrhistogram" +version = "7.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +dependencies = [ + "byteorder", + "num-traits", +] + [[package]] name = "headers" version = "0.4.0" @@ -2397,9 +2830,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", @@ -2425,7 +2858,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ "hex", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "pin-project-lite", "tokio", @@ -2457,16 +2890,16 @@ checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.3.1", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "log", - "rustls 0.23.28", + "rustls 0.23.35", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", "tokio-rustls 0.26.2", "tower-service", - "webpki-roots", + "webpki-roots 0.26.8", ] [[package]] @@ -2475,13 +2908,29 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "pin-project-lite", "tokio", "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.17" @@ -2495,15 +2944,32 @@ dependencies = [ "futures-util", "http 1.3.1", "http-body 1.0.1", - "hyper 1.7.0", + "hyper 1.8.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", "socket2 0.6.0", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", +] + +[[package]] +name = "hyperlocal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" +dependencies = [ + "hex", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", ] [[package]] @@ -2718,6 +3184,35 @@ dependencies = [ "serde", ] +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "inherent" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.107", +] + +[[package]] +name = "inventory" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +dependencies = [ + "rustversion", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -2726,9 +3221,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.12" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -2749,6 +3244,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2764,6 +3268,30 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jiff" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.107", +] + [[package]] name = "jobserver" version = "0.1.33" @@ -2821,9 +3349,9 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "10.3.0" +version = "10.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" +checksum = "c76e1c7d7df3e34443b3621b459b066a7b79644f059fc8b2db7070c825fd417e" dependencies = [ "aws-lc-rs", "base64 0.22.1", @@ -2876,7 +3404,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.27.5", "hyper-timeout", "hyper-util", @@ -2884,7 +3412,7 @@ dependencies = [ "k8s-openapi", "kube-core", "pem", - "rustls 0.23.28", + "rustls 0.23.35", "secrecy", "serde", "serde_json", @@ -2893,7 +3421,7 @@ dependencies = [ "tokio", "tokio-util", "tower", - "tower-http", + "tower-http 0.6.6", "tracing", ] @@ -2936,7 +3464,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aea4de4b562c5cc89ab10300bb63474ae1fa57ff5a19275f2e26401a323e3fd" dependencies = [ - "ahash", + "ahash 0.8.12", "async-broadcast", "async-stream", "backon", @@ -3017,14 +3545,25 @@ checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" dependencies = [ "bitflags", "libc", - "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.6.0", +] + +[[package]] +name = "libsodium-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "walkdir", ] [[package]] @@ -3033,6 +3572,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ + "cc", "pkg-config", "vcpkg", ] @@ -3049,6 +3589,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.12" @@ -3057,6 +3603,7 @@ checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", + "serde", ] [[package]] @@ -3105,6 +3652,14 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "migration" +version = "0.1.0" +dependencies = [ + "sea-orm-migration", + "tokio", +] + [[package]] name = "mime" version = "0.3.17" @@ -3127,6 +3682,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.3" @@ -3151,10 +3715,10 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "log", - "rand 0.9.0", + "rand 0.9.2", "regex", "serde_json", "serde_urlencoded", @@ -3162,6 +3726,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "moka" +version = "0.12.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener", + "futures-util", + "parking_lot", + "portable-atomic", + "rustc_version", + "smallvec", + "tagptr", + "uuid", +] + [[package]] name = "multer" version = "3.1.0" @@ -3179,6 +3764,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nom" version = "7.1.3" @@ -3316,7 +3918,7 @@ dependencies = [ "getrandom 0.2.15", "http 1.3.1", "rand 0.8.5", - "reqwest 0.12.15", + "reqwest", "serde", "serde_json", "serde_path_to_error", @@ -3326,57 +3928,161 @@ dependencies = [ ] [[package]] -name = "oid-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" -dependencies = [ - "asn1-rs", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openidconnect" -version = "4.0.1" +name = "oauth2-test-server" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c6709ba2ea764bbed26bce1adf3c10517113ddea6f2d4196e4851757ef2b2" +checksum = "e66b9483c4680a03f8f3a414e02d9e2b2d12702946d2fd05d58c3da4406630d2" dependencies = [ + "axum", "base64 0.21.7", "chrono", - "dyn-clone", - "ed25519-dalek", - "hmac", + "colored", + "futures", "http 1.3.1", - "itertools 0.10.5", - "log", - "oauth2", - "p256 0.13.2", - "p384", + "jsonwebtoken", + "once_cell", "rand 0.8.5", + "reqwest", "rsa", "serde", - "serde-value", "serde_json", - "serde_path_to_error", - "serde_plain", - "serde_with", "sha2", - "subtle", + "tokio", + "tower-http 0.5.2", + "tracing", + "tracing-subscriber", + "url", + "uuid", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "oidc-bff" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum", + "axum-reverse-proxy", + "base64 0.22.1", + "bytes", + "chrono", + "clap", + "dotenvy", + "http-body-util", + "hyper 1.8.1", + "migration", + "moka", + "oauth2", + "openidconnect", + "rustls 0.23.35", + "sea-orm", + "serde", + "serde_json", + "serde_yaml", + "sodiumoxide", + "thiserror 2.0.17", + "tokio", + "tower-sessions", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openidconnect" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c6709ba2ea764bbed26bce1adf3c10517113ddea6f2d4196e4851757ef2b2" +dependencies = [ + "base64 0.21.7", + "chrono", + "dyn-clone", + "ed25519-dalek", + "hmac", + "http 1.3.1", + "itertools 0.10.5", + "log", + "oauth2", + "p256 0.13.2", + "p384", + "rand 0.8.5", + "rsa", + "serde", + "serde-value", + "serde_json", + "serde_path_to_error", + "serde_plain", + "serde_with", + "sha2", + "subtle", "thiserror 1.0.69", "url", ] +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.107", +] + [[package]] name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "opentelemetry" version = "0.31.0" @@ -3453,7 +4159,7 @@ dependencies = [ "futures-util", "opentelemetry", "percent-encoding", - "rand 0.9.0", + "rand 0.9.2", "thiserror 2.0.17", "tokio", "tokio-stream", @@ -3468,6 +4174,39 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ouroboros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.107", +] + [[package]] name = "outref" version = "0.5.2" @@ -3633,6 +4372,15 @@ dependencies = [ "sha2", ] +[[package]] +name = "pgvector" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b" +dependencies = [ + "serde", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -3703,16 +4451,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] -name = "plain" -version = "0.2.3" +name = "pluralizer" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +checksum = "4b3eba432a00a1f6c16f39147847a870e94e2e9b992759b503e330efec778cbe" +dependencies = [ + "once_cell", + "regex", +] [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "powerfmt" @@ -3729,6 +4490,25 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -3747,6 +4527,28 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.107", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -3756,6 +4558,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.107", + "version_check", + "yansi", +] + [[package]] name = "prost" version = "0.14.1" @@ -3788,6 +4603,42 @@ dependencies = [ "prost", ] +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "publicsuffix" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" +dependencies = [ + "idna", + "psl-types", +] + [[package]] name = "quinn" version = "0.11.7" @@ -3800,7 +4651,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.28", + "rustls 0.23.35", "socket2 0.5.9", "thiserror 2.0.17", "tokio", @@ -3816,10 +4667,10 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" dependencies = [ "bytes", "getrandom 0.3.2", - "rand 0.9.0", + "rand 0.9.2", "ring 0.17.14", "rustc-hash", - "rustls 0.23.28", + "rustls 0.23.35", "rustls-pki-types", "slab", "thiserror 2.0.17", @@ -3857,6 +4708,12 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -3870,13 +4727,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy", ] [[package]] @@ -3928,9 +4784,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5" dependencies = [ "bitflags", ] @@ -4001,55 +4857,72 @@ dependencies = [ ] [[package]] -name = "relative-path" -version = "1.9.3" +name = "rend" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "base64 0.22.1", "bytes", + "cookie", + "cookie_store", + "encoding_rs", "futures-channel", "futures-core", "futures-util", + "h2 0.4.8", "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.27.5", + "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", - "once_cell", + "mime_guess", + "native-tls", "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.28", - "rustls-pemfile 2.2.0", + "rustls 0.23.35", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-native-tls", "tokio-rustls 0.26.2", "tokio-util", "tower", + "tower-http 0.6.6", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", - "windows-registry", + "webpki-roots 1.0.4", +] + +[[package]] +name = "reserve-port" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21918d6644020c6f6ef1993242989bf6d4952d2e025617744f184c02df51c356" +dependencies = [ + "thiserror 2.0.17", ] [[package]] @@ -4137,6 +5010,35 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rsa" version = "0.9.8" @@ -4158,34 +5060,42 @@ dependencies = [ ] [[package]] -name = "rstest" -version = "0.26.1" +name = "rust-multipart-rfc7578_2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" +checksum = "c839d037155ebc06a571e305af66ff9fd9063a6e662447051737e1ac75beea41" dependencies = [ - "futures-timer", + "bytes", + "futures-core", "futures-util", - "rstest_macros", + "http 1.3.1", + "mime", + "rand 0.9.2", + "thiserror 2.0.17", ] [[package]] -name = "rstest_macros" -version = "0.26.1" +name = "rust_decimal" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" +checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" dependencies = [ - "cfg-if", - "glob", - "proc-macro-crate", - "proc-macro2", - "quote", - "regex", - "relative-path", - "rustc_version", - "syn 2.0.107", - "unicode-ident", + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", ] +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -4250,16 +5160,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.28" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring 0.17.14", "rustls-pki-types", - "rustls-webpki 0.103.3", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] @@ -4308,11 +5218,12 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", + "zeroize", ] [[package]] @@ -4327,9 +5238,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring 0.17.14", @@ -4397,52 +5308,226 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" dependencies = [ - "dyn-clone", - "ref-cast", - "schemars_derive 1.0.4", - "serde", + "dyn-clone", + "ref-cast", + "schemars_derive 1.0.4", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.107", +] + +[[package]] +name = "schemars_derive" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.107", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.14", + "untrusted 0.9.0", +] + +[[package]] +name = "sea-bae" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" +dependencies = [ + "heck 0.4.1", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.107", +] + +[[package]] +name = "sea-orm" +version = "2.0.0-rc.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6dda57d64724c4c3e2b39ce17ca5f4084561656a3518b65b26edc5b36e4607" +dependencies = [ + "async-stream", + "async-trait", + "bigdecimal", + "chrono", + "derive_more", + "futures-util", + "itertools 0.14.0", + "log", + "ouroboros", + "pgvector", + "rust_decimal", + "sea-orm-macros", + "sea-query", + "sea-query-sqlx", + "sea-schema", + "serde", + "serde_json", + "sqlx", + "strum 0.27.2", + "thiserror 2.0.17", + "time", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "sea-orm-cli" +version = "2.0.0-rc.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63b7fcf2623bfc47e4fcca48fd35f77fd376611935862a6e316991d035ac85c" +dependencies = [ + "chrono", + "clap", + "dotenvy", + "glob", + "indoc", + "regex", + "sea-schema", + "sqlx", + "tokio", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "sea-orm-macros" +version = "2.0.0-rc.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7674a565e093a4bfffbfd6d7fd79a5dc8d75463d442ffb44d0fc3a3dcce5a6" +dependencies = [ + "heck 0.5.0", + "pluralizer", + "proc-macro2", + "quote", + "sea-bae", + "syn 2.0.107", + "unicode-ident", +] + +[[package]] +name = "sea-orm-migration" +version = "2.0.0-rc.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c77522b82141205bd99137be96b81b4540531f9ff7773b77d70f5749c39dcc" +dependencies = [ + "async-trait", + "clap", + "dotenvy", + "sea-orm", + "sea-orm-cli", + "sea-schema", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sea-query" +version = "1.0.0-rc.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ebab2b9d558deec08e43887a63ed4d96d56b32cb9d98578bd1749e2c8c7e24" +dependencies = [ + "bigdecimal", + "chrono", + "inherent", + "ordered-float 4.6.0", + "rust_decimal", + "sea-query-derive", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "sea-query-derive" +version = "1.0.0-rc.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "365d236217f5daa4f40d3c9998ff3921351b53472da50308e384388162353b3a" +dependencies = [ + "darling 0.20.11", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.107", + "thiserror 2.0.17", +] + +[[package]] +name = "sea-query-sqlx" +version = "0.8.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68873fa1776b4c25a26e7679f8ee22332978c721168ec1b0b32b6583d5a9381d" +dependencies = [ + "bigdecimal", + "chrono", + "rust_decimal", + "sea-query", "serde_json", + "sqlx", + "time", + "uuid", ] [[package]] -name = "schemars_derive" -version = "0.8.22" +name = "sea-schema" +version = "0.17.0-rc.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +checksum = "845b7ed3e7a4f4458fe7218931b54e92be0dce01fc3c310d996c7b76d9a37ea5" dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.107", + "async-trait", + "sea-query", + "sea-query-sqlx", + "sea-schema-derive", + "sqlx", ] [[package]] -name = "schemars_derive" -version = "1.0.4" +name = "sea-schema-derive" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" dependencies = [ + "heck 0.4.1", "proc-macro2", "quote", - "serde_derive_internals", "syn 2.0.107", ] [[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.1" +name = "seahash" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "sec1" @@ -4543,7 +5628,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "ordered-float", + "ordered-float 2.10.1", "serde", ] @@ -4656,9 +5741,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.18.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" +checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1" dependencies = [ "base64 0.22.1", "chrono", @@ -4675,11 +5760,11 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.18.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" +checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b" dependencies = [ - "darling 0.23.0", + "darling 0.21.3", "proc-macro2", "quote", "syn 2.0.107", @@ -4737,9 +5822,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -4790,6 +5875,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "similar" version = "2.7.0" @@ -4798,9 +5889,9 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_asn1" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", @@ -4819,9 +5910,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] @@ -4846,6 +5937,18 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "sodiumoxide" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" +dependencies = [ + "ed25519 1.5.3", + "libc", + "libsodium-sys", + "serde", +] + [[package]] name = "spin" version = "0.5.2" @@ -4901,7 +6004,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ "base64 0.22.1", + "bigdecimal", "bytes", + "chrono", "crc", "crossbeam-queue", "either", @@ -4917,7 +6022,8 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rustls 0.23.28", + "rust_decimal", + "rustls 0.23.35", "serde", "serde_json", "sha2", @@ -4928,7 +6034,8 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots", + "uuid", + "webpki-roots 0.26.8", ] [[package]] @@ -4977,9 +6084,11 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", "base64 0.22.1", + "bigdecimal", "bitflags", "byteorder", "bytes", + "chrono", "crc", "digest", "dotenvy", @@ -5000,6 +6109,7 @@ dependencies = [ "percent-encoding", "rand 0.8.5", "rsa", + "rust_decimal", "serde", "sha1", "sha2", @@ -5009,6 +6119,7 @@ dependencies = [ "thiserror 2.0.17", "time", "tracing", + "uuid", "whoami", ] @@ -5020,8 +6131,10 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64 0.22.1", + "bigdecimal", "bitflags", "byteorder", + "chrono", "crc", "dotenvy", "etcetera 0.8.0", @@ -5036,8 +6149,10 @@ dependencies = [ "log", "md-5", "memchr", + "num-bigint", "once_cell", "rand 0.8.5", + "rust_decimal", "serde", "serde_json", "sha2", @@ -5047,6 +6162,7 @@ dependencies = [ "thiserror 2.0.17", "time", "tracing", + "uuid", "whoami", ] @@ -5057,6 +6173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" dependencies = [ "atoi", + "chrono", "flume", "futures-channel", "futures-core", @@ -5073,6 +6190,7 @@ dependencies = [ "time", "tracing", "url", + "uuid", ] [[package]] @@ -5081,6 +6199,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "static_assertions_next" version = "1.1.2" @@ -5231,6 +6355,39 @@ dependencies = [ "syn 2.0.107", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "telemetry" version = "0.1.2" @@ -5265,9 +6422,9 @@ dependencies = [ [[package]] name = "testcontainers" -version = "0.27.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd36b06a2a6c0c3c81a83be1ab05fe86460d054d4d51bf513bc56b3e15bdc22" +checksum = "a347cac4368ba4f1871743adb27dc14829024d26b1763572404726b0b9943eb8" dependencies = [ "astral-tokio-tar", "async-trait", @@ -5278,7 +6435,6 @@ dependencies = [ "etcetera 0.11.0", "ferroid", "futures", - "http 1.3.1", "itertools 0.14.0", "log", "memchr", @@ -5429,6 +6585,16 @@ dependencies = [ "syn 2.0.107", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -5445,7 +6611,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.28", + "rustls 0.23.35", "tokio", ] @@ -5460,6 +6626,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.21.0", +] + [[package]] name = "tokio-tungstenite" version = "0.28.0" @@ -5469,7 +6647,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.28.0", ] [[package]] @@ -5535,7 +6713,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-timeout", "hyper-util", "percent-encoding", @@ -5593,6 +6771,39 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-cookies" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151b5a3e3c45df17466454bb74e9ecedecc955269bdedbf4d150dfa393b55a36" +dependencies = [ + "axum-core", + "cookie", + "futures-util", + "http 1.3.1", + "parking_lot", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags", + "bytes", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-http" version = "0.6.8" @@ -5626,6 +6837,57 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" +[[package]] +name = "tower-sessions" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a05911f23e8fae446005fe9b7b97e66d95b6db589dc1c4d59f6a2d4d4927d3" +dependencies = [ + "async-trait", + "http 1.3.1", + "time", + "tokio", + "tower-cookies", + "tower-layer", + "tower-service", + "tower-sessions-core", + "tower-sessions-memory-store", + "tracing", +] + +[[package]] +name = "tower-sessions-core" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8cce604865576b7751b7a6bc3058f754569a60d689328bb74c52b1d87e355b" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.22.1", + "futures", + "http 1.3.1", + "parking_lot", + "rand 0.8.5", + "serde", + "serde_json", + "thiserror 2.0.17", + "time", + "tokio", + "tracing", +] + +[[package]] +name = "tower-sessions-memory-store" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb05909f2e1420135a831dd5df9f5596d69196d0a64c3499ca474c4bd3d33242" +dependencies = [ + "async-trait", + "time", + "tokio", + "tower-sessions-core", +] + [[package]] name = "tracing" version = "0.1.41" @@ -5713,6 +6975,25 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.3.1", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", +] + [[package]] name = "tungstenite" version = "0.28.0" @@ -5724,18 +7005,48 @@ dependencies = [ "http 1.3.1", "httparse", "log", - "rand 0.9.0", + "rand 0.9.2", "sha1", "thiserror 2.0.17", "utf-8", ] +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +[[package]] +name = "typetag" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2212c8a9b9bcfca32024de14998494cf9a5dfa59ea1b829de98bac374b86bf" +dependencies = [ + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", +] + +[[package]] +name = "typetag-impl" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.107", +] + [[package]] name = "typify" version = "0.5.0" @@ -5917,9 +7228,15 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom 0.3.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] [[package]] name = "valuable" @@ -6149,7 +7466,7 @@ dependencies = [ "windows-interface", "windows-link 0.1.1", "windows-result", - "windows-strings 0.4.0", + "windows-strings", ] [[package]] @@ -6188,38 +7505,29 @@ checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ + "windows-link 0.1.1", "windows-result", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-strings", ] [[package]] name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link 0.1.1", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link 0.1.1", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link 0.1.1", ] @@ -6251,6 +7559,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + [[package]] name = "windows-sys" version = "0.61.1" @@ -6293,18 +7610,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.0", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -6321,9 +7639,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -6339,9 +7657,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -6357,9 +7675,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -6369,9 +7687,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -6387,9 +7705,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -6405,9 +7723,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -6423,9 +7741,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -6441,9 +7759,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -6466,7 +7784,7 @@ dependencies = [ "futures", "http 1.3.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "log", "once_cell", @@ -6498,6 +7816,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x509-parser" version = "0.15.1" @@ -6531,6 +7858,12 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yoke" version = "0.7.5" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index d0142e12d..a6293090b 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -2,7 +2,7 @@ members = [ "argo-workflows-openapi", "auth-daemon", - "graph-proxy", + "graph-proxy", "oidc-bff", "oidc-bff/migration", "sessionspaces", "telemetry", ] @@ -10,7 +10,6 @@ resolver = "2" [workspace.dependencies] anyhow = { version = "1.0.100" } -built = { version = "0.8.0" } clap = { version = "4.5.49", features = ["derive", "env"] } chrono = { version = "0.4.42" } derive_more = { version = "2.0.1" , features = [ @@ -49,4 +48,5 @@ opentelemetry-semantic-conventions = "0.31.0" tracing-opentelemetry = { version = "0.32.0" } axum = { version = "0.8.6" } regex = "1.12.2" -tower-http = { version = "0.6.8", features = ["cors"] } +tower-http = { version = "0.6.6", features = ["cors"] } +sea-orm = { version = "2.0.0-rc", features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros", "with-chrono" ] } diff --git a/backend/Dockerfile.auth-daemon b/backend/Dockerfile.auth-daemon index 5c1fd32c5..6ed136f50 100644 --- a/backend/Dockerfile.auth-daemon +++ b/backend/Dockerfile.auth-daemon @@ -7,6 +7,8 @@ RUN cargo install cargo-auditable COPY argo-workflows-openapi/Cargo.toml argo-workflows-openapi/Cargo.toml COPY graph-proxy/Cargo.toml graph-proxy/ COPY sessionspaces/Cargo.toml sessionspaces/ +COPY oidc-bff/Cargo.toml oidc-bff/ +COPY oidc-bff/migration/Cargo.toml oidc-bff/migration/ COPY auth-daemon/Cargo.toml auth-daemon/ COPY telemetry/build.rs telemetry/build.rs COPY telemetry/Cargo.toml telemetry/Cargo.toml @@ -18,6 +20,11 @@ RUN mkdir argo-workflows-openapi/src \ && echo "fn main() {}" > graph-proxy/src/main.rs \ && mkdir sessionspaces/src \ && echo "fn main() {}" > sessionspaces/src/main.rs \ + && mkdir oidc-bff/src \ + && touch oidc-bff/src/lib.rs \ + && echo "fn main() {}" > oidc-bff/src/main.rs \ + && mkdir oidc-bff/migration/src \ + && touch oidc-bff/migration/src/lib.rs \ && mkdir auth-daemon/src \ && echo "fn main() {}" > auth-daemon/src/main.rs \ && mkdir telemetry/src \ diff --git a/backend/Dockerfile.graph-proxy b/backend/Dockerfile.graph-proxy index b3d3aa434..7ca04f298 100644 --- a/backend/Dockerfile.graph-proxy +++ b/backend/Dockerfile.graph-proxy @@ -27,9 +27,6 @@ RUN mkdir graph-proxy/src \ RUN cargo build --release --package telemetry -RUN touch --date @0 graph-proxy/src/main.rs \ - && cargo build --release --package graph-proxy - COPY . . RUN touch graph-proxy/src/main.rs \ diff --git a/backend/Dockerfile.oidc-bff b/backend/Dockerfile.oidc-bff new file mode 100644 index 000000000..a67be847c --- /dev/null +++ b/backend/Dockerfile.oidc-bff @@ -0,0 +1,21 @@ +FROM docker.io/library/rust:1.91.0-bookworm AS build + +WORKDIR /app + +RUN cargo install cargo-auditable + +COPY Cargo.toml Cargo.lock ./ + +COPY . . + +RUN touch --date @0 oidc-bff/src/main.rs \ + && cargo build --release --package oidc-bff + +RUN touch oidc-bff/src/main.rs \ + && cargo auditable build --release --package oidc-bff + +FROM gcr.io/distroless/cc-debian12@sha256:0000f9dc0290f8eaf0ecceafbc35e803649087ea7879570fbc78372df7ac649b AS deploy + +COPY --from=build /app/target/release/oidc-bff /oidc-bff + +ENTRYPOINT ["/oidc-bff"] diff --git a/backend/auth-daemon/.devcontainer/devcontainer.json b/backend/auth-daemon/.devcontainer/devcontainer.json index 483c1588b..720464918 100644 --- a/backend/auth-daemon/.devcontainer/devcontainer.json +++ b/backend/auth-daemon/.devcontainer/devcontainer.json @@ -24,5 +24,11 @@ } }, "workspaceMount": "source=${localWorkspaceFolder}/../..,target=/workspace,type=bind", - "workspaceFolder": "/workspace/" + "workspaceFolder": "/workspace/", + "capAdd": [ + "SYS_PTRACE" + ], + "securityOpt": [ + "seccomp=unconfined" + ] } diff --git a/backend/auth-daemon/Cargo.toml b/backend/auth-daemon/Cargo.toml index eba8ac624..e2367a75c 100644 --- a/backend/auth-daemon/Cargo.toml +++ b/backend/auth-daemon/Cargo.toml @@ -6,19 +6,36 @@ license-file = "../../LICENSE" [dependencies] anyhow.workspace = true -axum = { workspace = true } +axum = { workspace = true, features = ["json"] } +axum-reverse-proxy = "1.0.3" clap = { workspace = true, features = ["env"] } dotenvy.workspace = true +openidconnect = "4.0.1" regex = { workspace = true } reqwest.workspace = true serde.workspace = true +serde_json.workspace = true +serde_yaml = "0.9.34" thiserror.workspace = true tokio = { workspace = true, features = ["full"] } tower-http = { workspace = true, features = ["cors"] } tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } url.workspace = true +oidc-bff = { path = "../oidc-bff" } +sea-orm = { workspace = true, features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", "macros"] } +chrono.workspace = true +sodiumoxide = "0.2.7" +http-body-util = "0.1.3" +oauth2 = "5.0.0" +base64 = "0.22.1" +rustls = "0.23.35" +axum-test = "18.4.1" +env_logger = "0.11.8" +oauth2-test-server = "0.1.3" +testcontainers = {version = "0.26.0", features = ["http_wait_plain"]} [dev-dependencies] mockito.workspace = true serde_json.workspace = true +migration = { version = "0.1.0", path = "../oidc-bff/migration" } diff --git a/backend/auth-daemon/src/config.rs b/backend/auth-daemon/src/config.rs new file mode 100644 index 000000000..b85d41c1a --- /dev/null +++ b/backend/auth-daemon/src/config.rs @@ -0,0 +1,32 @@ +use std::path::Path; + +use serde::{Deserialize, Serialize}; +use crate::Result; + +#[derive(Serialize, Deserialize)] +pub struct Config { + pub client_id: String, + pub client_secret: String, + pub oidc_provider_url: String, + pub graph_url: String, + pub port: u16, + pub postgres_user: String, + pub postgres_password: String, + pub postgres_database: String, + pub postgres_hostname: String, + pub postgres_port: u16, + pub encryption_public_key: String, + pub encryption_private_key: String, +} + +impl Config { + /// Load config from JSON or YAML file + pub fn from_file>(path: P) -> Result { + let content = std::fs::read_to_string(&path)?; + match path.as_ref().extension().and_then(|e| e.to_str()) { + Some("json") => Ok(serde_json::from_str(&content)?), + // otherwise assume yaml + _ => Ok(serde_yaml::from_str(&content)?), + } + } +} diff --git a/backend/auth-daemon/src/database.rs b/backend/auth-daemon/src/database.rs new file mode 100644 index 000000000..bfcd3dc22 --- /dev/null +++ b/backend/auth-daemon/src/database.rs @@ -0,0 +1,105 @@ +use chrono::{DateTime, Duration, FixedOffset, Utc}; +use oauth2::RefreshToken; +use openidconnect::{IssuerUrl, SubjectIdentifier}; +use sea_orm::{ActiveModelTrait, DatabaseConnection}; +use crate::{Result, state::TokenData}; +use sea_orm::*; +use oidc_bff::entity; +use oidc_bff::entity::oidc_tokens::ActiveModel; + +pub async fn write_token_to_database( + connection: &DatabaseConnection, + token: &TokenData, + public_key: &sodiumoxide::crypto::box_::PublicKey, +) -> Result<()> { + let encrypted_refresh_token = + sodiumoxide::crypto::sealedbox::seal(token.refresh_token.secret().as_bytes(), public_key); + let refresh_token_expires_at = Utc::now() + Duration::days(30); // TODO: offline_access tokens will expire if not used within 30 days. Keycloak returns the actual expiration date in the field "refresh_expires_in", we should use that + let token_update = entity::oidc_tokens::ActiveModel { + issuer: Set(token.issuer.to_string()), + subject: Set(token.subject.to_string()), + encrypted_refresh_token: Set(encrypted_refresh_token), + expires_at: Set(Some(convert_time(refresh_token_expires_at))), + created_at: Set(Utc::now().into()), + updated_at: Set(Utc::now().into()), + ..Default::default() + }; + entity::oidc_tokens::Entity::insert(token_update) + .on_conflict( + sea_query::OnConflict::column(entity::oidc_tokens::Column::Subject) + .update_columns([ + entity::oidc_tokens::Column::Issuer, + entity::oidc_tokens::Column::Subject, + entity::oidc_tokens::Column::EncryptedRefreshToken, + entity::oidc_tokens::Column::ExpiresAt, + entity::oidc_tokens::Column::UpdatedAt, + // deliberately do not update CreatedAt + ]) + .to_owned(), + ) + .exec(connection) + .await?; + Ok(()) +} + +fn convert_time(utc_time: DateTime) -> DateTime { + utc_time.with_timezone(&FixedOffset::east_opt(0).unwrap()) +} + + +/// Convert DB stored FixedOffset time to Utc +fn to_utc(dt: DateTime) -> DateTime { + dt.with_timezone(&Utc) +} + +pub async fn read_token_from_database( + connection: &DatabaseConnection, + subject: &SubjectIdentifier, + issuer: Option<&IssuerUrl>, + public_key: &sodiumoxide::crypto::box_::PublicKey, + secret_key: &sodiumoxide::crypto::box_::SecretKey, +) -> Result { + println!("Fetching token from database for subject {}", subject.as_str()); + // Build query: filter by Subject (and Issuer if provided) + let mut query = entity::oidc_tokens::Entity::find() + .filter(entity::oidc_tokens::Column::Subject.eq(subject.as_str())); + + if let Some(iss) = issuer { + query = query.filter(entity::oidc_tokens::Column::Issuer.eq(iss.as_str())); + } + + let row = query.one(connection).await? + .ok_or_else(|| anyhow::anyhow!("No token row found for subject='{}' issuer={:?}", subject.as_str(), issuer))?; + + // Decrypt sealed box + let ciphertext = row.encrypted_refresh_token; + let decrypted = sodiumoxide::crypto::sealedbox::open(&ciphertext, public_key, secret_key) + .map_err(|_| anyhow::anyhow!("Unable to decrypt refresh token (sealedbox::open failed)"))?; + + let expires_at_utc = match row.expires_at { + Some(dt) => to_utc(dt), + None => { + // If not stored, decide on a policy: here we treat as "no expiry" + // You can choose to error instead. + Utc::now() + } + }; + + if expires_at_utc < Utc::now() { + Err(anyhow::anyhow!("Stored refresh token has expired at {}", expires_at_utc))?; + } + + let issuer = IssuerUrl::new(row.issuer)?; + let subject = SubjectIdentifier::new(row.subject); + let refresh_token = RefreshToken::new(String::from_utf8(decrypted)?); + let token = TokenData::new( + issuer, + subject, + None, + Utc::now(), + refresh_token + + ); + println!("Fetching token from database for subject {}: success", token.subject.as_str()); + Ok(token) +} diff --git a/backend/auth-daemon/src/error.rs b/backend/auth-daemon/src/error.rs new file mode 100644 index 000000000..a944ebb41 --- /dev/null +++ b/backend/auth-daemon/src/error.rs @@ -0,0 +1,26 @@ +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; + +#[derive(Debug)] +pub struct Error(anyhow::Error); + +impl IntoResponse for Error { + fn into_response(self) -> Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Something went wrong: {}", self.0), + ) + .into_response() + } +} + +impl From for Error +where + E: Into, +{ + fn from(err: E) -> Self { + Self(err.into()) + } +} diff --git a/backend/auth-daemon/src/inject_token.rs b/backend/auth-daemon/src/inject_token.rs new file mode 100644 index 000000000..63fee226d --- /dev/null +++ b/backend/auth-daemon/src/inject_token.rs @@ -0,0 +1,123 @@ +use crate::{database::write_token_to_database, state::{RouterState, TokenData}}; +use http_body_util::BodyExt; +use openidconnect::{ + ClientId, ClientSecret, IssuerUrl, TokenResponse, + core::{CoreClient, CoreProviderMetadata}, + reqwest, +}; +use serde_json::Value; +use std::sync::Arc; +use axum::response::IntoResponse; + +use axum::{ + body::Body, + extract::{Request, State}, + http::{self, HeaderValue, StatusCode}, + middleware, response::Response, +}; + +use crate::Result; + +pub async fn inject_token( + State(state): State>, + req: Request, + next: middleware::Next, +) -> Result { + let token: Option = state.token.read().await.clone(); + if let Some(mut token) = token { + println!("Injecting token"); + if (token.access_token_is_expired()) { + println!("Access token is expired, refreshing"); + token = refresh_token_and_write_to_database(&state, &token).await?; + } + let mut req = clone_request(req).await?; + prepare_headers(&mut req.0, &token); + let response = next.clone().run(req.0).await; + let response = response_as_json(response).await?; + println!("DEBUG response json: {:?}", response); + if !is_good_response(&response) { + println!("Query failed, refreshing token and trying again"); + token = refresh_token_and_write_to_database(&state, &token).await?; + prepare_headers(&mut req.1, &token); + Ok(next.run(req.1).await) + } else { + Ok(axum::Json(response).into_response()) + } + } else { + println!("No token to inject"); + Ok(next.run(req).await) + } +} + +fn is_good_response(response: &Value) -> bool { + + if let Some(object) = response.as_object() { + if let Some(errors) = object.get("errors") { + return errors.as_array().map(|it| it.len() == 0).unwrap_or(false); + } else { + return true; + } + } + false +} + +async fn response_as_json(response: Response) -> Result { + + if !response.status().is_success() { + Err(anyhow::anyhow!("HTTP error: {}", response.status()))?; + } + + + let collected = response.into_body().collect().await + .map_err(|e| anyhow::anyhow!("collect body error: {}", e))?; + let bytes = collected.to_bytes(); + + let json: Value = serde_json::from_slice(&bytes) + .map_err(|e| anyhow::anyhow!("JSON parse error: {}", e))?; + Ok(json) +} + +async fn set_token(state: &RouterState, new_token: TokenData) { + let mut guard = state.token.write().await; + *guard = Some(new_token); +} + +async fn clone_request(req: Request) -> Result<(Request, Request)> { + // TODO: an inefficient method of cloning a request, improve this + let (parts, body) = req.into_parts(); + let bytes = http_body_util::BodyExt::collect(body).await?.to_bytes(); + let req1 = Request::from_parts(parts.clone(), Body::from(bytes.clone())); + let req2 = Request::from_parts(parts, Body::from(bytes)); + Ok((req1, req2)) +} + +fn prepare_headers(req: &mut Request, token: &TokenData) { + if let Some(access_token) = &token.access_token { + let value = format!("Bearer {}", access_token.secret()); + println!("DEBUG injecting token:{:?}", value); + req.headers_mut().insert( + http::header::AUTHORIZATION, + HeaderValue::from_str(&value).unwrap(), + ); + req.headers_mut().remove(http::header::COOKIE); +} +} + +async fn refresh_token_and_write_to_database( + state: &RouterState, + token: &TokenData, +) -> Result { + let token = refresh_token(state, token).await?; + write_token_to_database(&state.database_connection, &token, &state.public_key).await?; + Ok(token) +} + +async fn refresh_token(state: &RouterState, token: &TokenData) -> Result { + let token_response = state + .oidc_client + .exchange_refresh_token(&token.refresh_token)? + .request_async(&state.http_client) + .await?; + let token = token.update_tokens(&token_response); + Ok(token) +} diff --git a/backend/auth-daemon/src/main.rs b/backend/auth-daemon/src/main.rs index 7feae4e43..86ed0c2e1 100644 --- a/backend/auth-daemon/src/main.rs +++ b/backend/auth-daemon/src/main.rs @@ -1,11 +1,10 @@ #![forbid(unsafe_code)] #![doc = include_str!("../README.md")] -mod proxy; -use proxy::proxy; - mod healthcheck; use healthcheck::healthcheck; +use openidconnect::SubjectIdentifier; +use serde::{Deserialize, Serialize}; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -14,9 +13,7 @@ use std::{ }; use axum::{ - Router, - http::Method, - routing::{get, post}, + Router, http::Method, middleware, routing::{get, post} }; use clap::Parser; use regex::Regex; @@ -27,29 +24,45 @@ use tracing::{debug, info}; use tracing_subscriber::EnvFilter; use url::Url; +use crate::{config::Config, state::RouterState}; +mod config; +mod state; +mod error; + +use axum_reverse_proxy::ReverseProxy; +mod inject_token; +mod database; + + +type Result = std::result::Result; + +#[derive(Parser, Debug)] +#[command(author, version, about)] +struct ServeArgs { + /// Path to config file (JSON or YAML) + #[arg( + short, + long, + env = "WORKFLOWS_AUTH_DAEMON_CONFIG", + default_value = "config.yaml" + )] + config: String, + #[arg( + env = "WORKFLOWS_AUTH_DAEMON_SUBJECT", + )] + subject: String, +} + #[derive(Debug, Parser)] #[allow(clippy::large_enum_variant)] enum Cli { /// Starts a webserver - Serve(RouterState), + Serve(ServeArgs), } -#[derive(Debug, Parser)] -struct RouterState { - #[arg(short, long, env = "AUTH_DOMAIN")] - auth_domain: Url, - #[arg(short, long, env = "CLIENT_ID")] - client_id: String, - #[arg(short, long, env = "GRAPH_URL")] - graph_url: Url, - #[arg(short, long, env = "TOKEN")] - token: String, - #[arg(long, env = "PORT", default_value = "80")] - port: u16, -} #[tokio::main] -async fn main() -> anyhow::Result<()> { +async fn main() -> Result<()> { dotenvy::dotenv().ok(); let args = Cli::parse(); tracing_subscriber::fmt() @@ -58,8 +71,9 @@ async fn main() -> anyhow::Result<()> { match args { Cli::Serve(args) => { - let requested_port = args.port; - let router_state = Arc::new(args); + let config = Config::from_file(args.config)?; + let requested_port = config.port; + let router_state = Arc::new(RouterState::new(config, &SubjectIdentifier::new(args.subject)).await?); let router = setup_router(router_state, None)?; serve(router, IpAddr::V4(Ipv4Addr::UNSPECIFIED), requested_port).await?; @@ -71,6 +85,11 @@ async fn main() -> anyhow::Result<()> { fn setup_router(state: Arc, cors_allow: Option>) -> anyhow::Result { debug!("Setting up the router"); + + rustls::crypto::ring::default_provider() + .install_default() + .expect("Failed to install rust TLS cryptography"); + let cors_origin = if let Some(cors_allow) = cors_allow { info!("Allowing CORS Origin(s) matching: {:?}", cors_allow); AllowOrigin::predicate(move |origin, _| { @@ -85,8 +104,16 @@ fn setup_router(state: Arc, cors_allow: Option>) -> anyh AllowOrigin::default() }; - Ok(Router::new() - .route("/", post(proxy)) + let proxy: Router> = + ReverseProxy::new("/", state.config.graph_url.as_str()).into(); + let proxy = proxy; + + + Ok(proxy + .layer(middleware::from_fn_with_state( + state.clone(), + inject_token::inject_token, + )) .with_state(state) .layer( CorsLayer::new() @@ -113,3 +140,131 @@ async fn shutdown_signal() { println!("Shutting down"); process::exit(0); } + +#[cfg(test)] +mod tests { + use std::sync::Arc; + use std::time::Duration; + + use mockito::Matcher; + use openidconnect::SubjectIdentifier; + use sea_orm::ActiveValue::Set; + use sea_orm::{Database, DatabaseConnection, EntityTrait}; + use serde_json::json; + use testcontainers::core::wait::HttpWaitStrategy; + use testcontainers::{GenericImage, ImageExt}; + use testcontainers::{ + core::{IntoContainerPort, WaitFor}, + runners::AsyncRunner, +}; + + use tokio::time::sleep; + use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; + + use crate::{config::Config, state::RouterState}; + use crate::{Result, setup_router}; + + async fn test_database(issuer_url: &str, refresh_token: &str) -> Result { + let db = Database::connect("sqlite::memory:").await?; + use migration::{Migrator, MigratorTrait}; + Migrator::up(&db, None).await?; + + let now: chrono::DateTime = chrono::Utc::now().into(); + let expires_at = now + Duration::from_secs(600); + + let public_key = sodiumoxide::crypto::box_::PublicKey::from_slice(&BASE64.decode("ZpJ703xR7atXbGXI20FkQk3J1qjLxodTP6yk92yPVGM=")?).expect("valid key"); + let encrypted_refresh_token = sodiumoxide::crypto::sealedbox::seal(refresh_token.as_bytes(), &public_key); + + oidc_bff::entity::oidc_tokens::Entity::insert(oidc_bff::entity::oidc_tokens::ActiveModel { + issuer: Set(issuer_url.into()), + subject: Set("test-subject".into()), + encrypted_refresh_token: Set(encrypted_refresh_token.into()), + expires_at: Set(expires_at.into()), + created_at: Set(now.clone().into()), + updated_at: Set(now.into()), + ..Default::default() + }).exec(&db) + .await?; + + Ok(db) + } + + + #[tokio::test] + async fn test() -> Result<()> { + + let _ = env_logger::try_init(); + + let mut graphql_server = mockito::Server::new_async().await; + let graphql_server_url = graphql_server.url(); + let graphql_mock = graphql_server.mock("POST", "/") + .match_header("Authorization", Matcher::Regex("Bearer .+".into())) + .with_status(200) + .with_body("{\"name\": \"workflow-name\"}") + .expect(1) + .create_async() + .await; + + let wait_strategy = HttpWaitStrategy::new("default/.well-known/openid-configuration").with_expected_status_code(200u16); + let oidc_container = GenericImage::new("ghcr.io/navikt/mock-oauth2-server", "3.0.1") + .with_wait_for(WaitFor::http(wait_strategy)) + .with_env_var("SERVER_PORT", "8080").with_startup_timeout(Duration::from_secs(60)).start().await.expect("failed to start mock OIDC server"); + let port = oidc_container.get_host_port_ipv4(8080).await?; + + let mock_admin_url = format!("http://localhost:{}/default/token", port); + let params = [ + ("grant_type", "refresh_token"), + ("scope", "openid offline_access"), + ("subject", "test-subject"), + ("refresh_token", "test-refresh-token"), + ("client_id", "test-client"), + ]; + + let res: serde_json::Value = reqwest::Client::new() + .post(mock_admin_url) + .timeout(Duration::from_secs(10)) + .form(¶ms) + .send() + .await? + .json() + .await?; + + // println!("RESPONSE: {:?}", res.to_string()); + + let refresh_token = res["refresh_token"].as_str().expect("no refresh token"); + + let issuer_url = format!("http://localhost:{}/default", port); + + let db = test_database(&issuer_url, &refresh_token).await?; + + let config = Config{ + client_id: "test-client".into(), + client_secret: "".into(), + oidc_provider_url: issuer_url.into(), + graph_url: graphql_server_url.into(), + port: 6000, + postgres_user: "auth_user".into(), + postgres_password: "password".into(), + postgres_database: "auth_service".into(), + postgres_hostname: "database-hostname".into(), + postgres_port: 5432, + encryption_public_key: "ZpJ703xR7atXbGXI20FkQk3J1qjLxodTP6yk92yPVGM=".into(), + encryption_private_key: "yxjSYB/nvdAzktd83diOtADvp3RX/0Kx5V3FgK7YlXk=".into() }; + + let router_state = Arc::new(RouterState::with_database(config, &SubjectIdentifier::new("test-subject".into()), db).await?); + let router = setup_router(router_state, None)?; + let test_server = axum_test::TestServer::new(router)?; + + // + let response = test_server.post("/").content_type("application/json").json(&json!( + {"query": "mutation{ submitWorkflowTemplate(name: \"template-name\", visit: {proposalCode: \"xy\", proposalNumber: 1234, number: 5}, parameters: {}){ name } }" } + )).await; + + response.assert_status_ok(); + graphql_mock.assert_async().await; + + oidc_container.stop_with_timeout(Some(60)).await?; + + Ok(()) + } +} \ No newline at end of file diff --git a/backend/auth-daemon/src/proxy.rs b/backend/auth-daemon/src/proxy.rs deleted file mode 100644 index a4bae2d23..000000000 --- a/backend/auth-daemon/src/proxy.rs +++ /dev/null @@ -1,205 +0,0 @@ -use std::sync::Arc; - -use axum::{Json, extract::State, http::StatusCode, response::IntoResponse}; -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use tracing::info; -use url::Url; - -use crate::RouterState; - -pub async fn proxy( - State(router_state): State>, - Json(query): Json, -) -> Result { - let form = vec![ - ("grant_type", "refresh_token"), - ("client_id", &router_state.client_id), - ("refresh_token", &router_state.token), - ]; - - let auth_domain = match router_state.auth_domain.as_str().ends_with("/") { - true => format!("{}protocol/openid-connect/token", router_state.auth_domain), - false => format!("{}/protocol/openid-connect/token", router_state.auth_domain), - }; - info!("Auth domain: {}", auth_domain); - - let client = Client::new(); - - info!("Fetching access token"); - let res = client - .post(auth_domain) - .form(&form) - .send() - .await - .map_err(|_err| ProxyError::AuthQuery(router_state.auth_domain.clone()))?; - - if !res.status().is_success() { - let status = res.status(); - let body = res - .text() - .await - .unwrap_or_else(|_| "No message".to_string()); - return Err(ProxyError::KeycloakError(status, body)); - } - - info!("Decoding access token"); - let auth_data: AuthResponse = res.json().await?; - let graph_payload = GraphPayload::from(query.query); - - info!("Querying graph"); - let graph_request = client - .post(router_state.graph_url.clone()) - .bearer_auth(auth_data.access_token) - .json(&graph_payload) - .send() - .await?; - - info!("Decoding graph response"); - let graph_response: String = graph_request.text().await?; - - Ok(graph_response.to_string()) -} - -#[derive(Deserialize, Serialize)] -pub struct UserQuery { - query: String, -} - -#[derive(Deserialize)] -struct AuthResponse { - access_token: String, -} - -#[derive(Serialize)] -struct GraphPayload { - query: String, -} - -impl From for GraphPayload { - fn from(value: String) -> Self { - GraphPayload { query: value } - } -} - -#[derive(Debug, thiserror::Error)] -pub enum ProxyError { - #[error("Could not reach auth service at {0}")] - AuthQuery(Url), - #[error("Could not deserialise response: {0}")] - Deserialization(#[from] reqwest::Error), - #[error("Error on token exchange: status: {0}, message {1}")] - KeycloakError(StatusCode, String), -} - -impl IntoResponse for ProxyError { - fn into_response(self) -> axum::response::Response { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Something went wrong: {}", self), - ) - .into_response() - } -} - -#[cfg(test)] -mod tests { - use std::{str::FromStr, sync::Arc}; - - use axum::http::StatusCode; - use mockito::Server; - use url::Url; - - use crate::{ - RouterState, - proxy::{ProxyError, UserQuery, proxy}, - }; - - #[tokio::test] - async fn base_test() { - let client = "client"; - let token = "token"; - let port = 3000; - - let query = UserQuery { - query: "test-query".into(), - }; - let query_body = serde_json::to_string(&query).unwrap(); - - let mut auth = Server::new_async().await; - let mut graph = Server::new_async().await; - - auth.mock("POST", "/protocol/openid-connect/token") - .with_status(200) - .with_body(r#"{"access_token": "some-token"}"#) - .create_async() - .await; - - graph - .mock("POST", "/") - .with_status(200) - .with_header("content-type", "application/json") - .with_body(query_body) - .create_async() - .await; - - let router_state = RouterState { - auth_domain: Url::from_str(&auth.url()).unwrap(), - client_id: client.into(), - graph_url: Url::from_str(&graph.url()).unwrap(), - token: token.into(), - port, - }; - - let resp = proxy( - axum::extract::State(Arc::new(router_state)), - axum::Json(query), - ) - .await; - assert!(resp.is_ok()); - let result = resp.unwrap(); - assert_eq!(r#"{"query":"test-query"}"#, result); - } - - #[tokio::test] - async fn invalid_auth() { - let client = "client"; - let token = "token"; - let port = 3000; - - let query = UserQuery { - query: "test-query".into(), - }; - - let mut auth = Server::new_async().await; - - auth.mock("POST", "/protocol/openid-connect/token") - .with_status(401) - .with_body("Unauthorized") - .create_async() - .await; - - let router_state = RouterState { - auth_domain: Url::from_str(&auth.url()).unwrap(), - client_id: client.into(), - graph_url: Url::from_str("https://example.com").unwrap(), - token: token.into(), - port, - }; - - let resp = proxy( - axum::extract::State(Arc::new(router_state)), - axum::Json(query), - ) - .await; - assert!(resp.is_err()); - - match resp { - Err(ProxyError::KeycloakError(status, message)) => { - assert_eq!(status, StatusCode::UNAUTHORIZED); - assert_eq!(message, "Unauthorized"); - } - other => panic!("Expected Unauthorized error, got {:?}", other), - } - } -} diff --git a/backend/auth-daemon/src/state.rs b/backend/auth-daemon/src/state.rs new file mode 100644 index 000000000..bc60d5ad9 --- /dev/null +++ b/backend/auth-daemon/src/state.rs @@ -0,0 +1,167 @@ + +use chrono::{DateTime, Utc}; +use openidconnect::core::{CoreClient, CoreProviderMetadata}; +use sodiumoxide::crypto::box_::{PublicKey, SecretKey}; +use std::time::Duration; +use openidconnect::{AccessToken, IssuerUrl, RefreshToken, SubjectIdentifier}; +use serde::{Deserialize, Serialize}; +use tokio::sync::RwLock; +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use oauth2::{ClientId, ClientSecret, EndpointMaybeSet, EndpointNotSet, EndpointSet, reqwest}; +use sea_orm::{Database, DatabaseConnection}; + +use crate::config::Config; +use crate::Result; +use crate::database::read_token_from_database; +use anyhow::anyhow; + +pub struct RouterState { + pub config: Config, + pub token: RwLock>, + pub http_client: reqwest::Client, + pub oidc_client: openidconnect::core::CoreClient< + EndpointSet, + EndpointNotSet, + EndpointNotSet, + EndpointNotSet, + EndpointMaybeSet, + EndpointMaybeSet, + >, + pub database_connection: DatabaseConnection, + pub public_key: PublicKey, +} + +impl RouterState { + + pub async fn new(config: Config, subject: impl Into<&SubjectIdentifier>) -> Result { + let database_url = format!( + "postgres://{}:{}@{}:{}/{}", + config.postgres_user, + config.postgres_password, + config.postgres_hostname, + config.postgres_port, + config.postgres_database + ); + let database_connection = Database::connect(&database_url).await?; + Self::with_database(config, subject, database_connection).await + } + + pub async fn with_database(config: Config, subject: impl Into<&SubjectIdentifier>, database_connection: impl Into) -> Result { + + let http_client = reqwest::ClientBuilder::new() + // Following redirects opens the client up to SSRF vulnerabilities. + .redirect(reqwest::redirect::Policy::none()) + .build()?; + + // Use OpenID Connect Discovery to fetch the provider metadata. + let provider_metadata = CoreProviderMetadata::discover_async( + IssuerUrl::new(config.oidc_provider_url.to_string())?, + &http_client, + ) + .await?; + + let oidc_client = CoreClient::from_provider_metadata( + provider_metadata, + ClientId::new(config.client_id.to_string()), + if config.client_secret.is_empty() { + None + } else { + Some(ClientSecret::new(config.client_secret.to_string())) + }, + ); + + let public_key = PublicKey::from_slice(&BASE64.decode(&config.encryption_public_key)?) + .ok_or(anyhow!("Invalid public key"))?; + + let private_key = SecretKey::from_slice(&BASE64.decode(&config.encryption_private_key)?) + .ok_or(anyhow!("Invalid public key"))?; + + let subject = subject.into(); + let database_connection = database_connection.into(); + let token = read_token_from_database(&database_connection, subject, None, &public_key, &private_key).await?; + + Ok(Self {config, token: RwLock::new(Some(token)), + http_client, + oidc_client, + database_connection, + public_key, + }) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TokenData { + pub issuer: IssuerUrl, + pub subject: SubjectIdentifier, + pub access_token: Option, + pub access_token_expires_at: DateTime, + pub refresh_token: RefreshToken, +} + +impl TokenData { + + pub fn new( + issuer: IssuerUrl, + subject: SubjectIdentifier, + access_token: Option, + access_token_expires_at: DateTime, + refresh_token: RefreshToken, + ) -> Self { + Self { + issuer, + subject, + access_token, + access_token_expires_at, + refresh_token, + } + } + + pub fn from_token_response( + token_response: &T, + issuer: IssuerUrl, + subject: SubjectIdentifier, + ) -> Result { + let access_token = token_response.access_token().clone(); + let refresh_token = token_response + .refresh_token() + .ok_or_else(|| anyhow!("Token Response did not return a refresh token"))? + .clone(); + let access_token_expires_at = Utc::now() + + token_response + .expires_in() + .unwrap_or_else(|| Duration::from_secs(60)); + Ok(Self::new( + issuer, + subject, + Some(access_token), + access_token_expires_at, + refresh_token, + )) + } + + pub fn update_tokens_mut(&mut self, token_response: &T) { + let access_token = token_response.access_token().clone(); + let refresh_token = token_response.refresh_token(); + let access_token_expires_at = Utc::now() + + token_response + .expires_in() + .unwrap_or_else(|| Duration::from_secs(60)); + if let Some(refresh_token) = refresh_token { + self.refresh_token = refresh_token.clone(); + } + self.access_token = Some(access_token); + self.access_token_expires_at = access_token_expires_at; + } + + pub fn update_tokens(&self, token_response: &T) -> Self { + let mut clone = self.clone(); + clone.update_tokens_mut(token_response); + clone + } + + pub fn access_token_is_expired(&self) -> bool { + self.access_token_expires_at <= Utc::now() || self.access_token.is_none() + } +} + + diff --git a/backend/oidc-bff/.cargo/config.toml b/backend/oidc-bff/.cargo/config.toml new file mode 100644 index 000000000..f4d28a316 --- /dev/null +++ b/backend/oidc-bff/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "link-arg=-fuse-ld=lld"] diff --git a/backend/oidc-bff/.devcontainer/Dockerfile b/backend/oidc-bff/.devcontainer/Dockerfile new file mode 100644 index 000000000..8575a669f --- /dev/null +++ b/backend/oidc-bff/.devcontainer/Dockerfile @@ -0,0 +1,7 @@ +FROM mcr.microsoft.com/devcontainers/rust:2-bookworm + +# Include lld linker to improve build times either by using environment variable +# RUSTFLAGS="-C link-arg=-fuse-ld=lld" or with Cargo's configuration file (i.e see .cargo/config.toml). +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install clang lld libssl-dev pkg-config postgresql-client \ + && apt-get autoremove -y && apt-get clean -y diff --git a/backend/oidc-bff/.devcontainer/devcontainer.json b/backend/oidc-bff/.devcontainer/devcontainer.json new file mode 100644 index 000000000..5ba89e0c5 --- /dev/null +++ b/backend/oidc-bff/.devcontainer/devcontainer.json @@ -0,0 +1,23 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/rust-postgres +{ + "name": "Rust and PostgreSQL", + "dockerComposeFile": "docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [5432], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "cargo install sea-orm-cli" + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/backend/oidc-bff/.devcontainer/docker-compose.yml b/backend/oidc-bff/.devcontainer/docker-compose.yml new file mode 100644 index 000000000..5c16f9cfe --- /dev/null +++ b/backend/oidc-bff/.devcontainer/docker-compose.yml @@ -0,0 +1,37 @@ +version: '3.8' + +volumes: + postgres-data: + +services: + app: + build: + context: . + dockerfile: Dockerfile + env_file: + # Ensure that the variables in .env match the same variables in devcontainer.json + - .env + + volumes: + - ../..:/workspaces:cached + + # Overrides default command so things don't shut down after the process ends. + command: sleep infinity + + # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. + network_mode: service:db + + # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. + # (Adding the "ports" property to this file will not forward from a Codespace.) + + db: + image: postgres:14.1 + restart: unless-stopped + volumes: + - postgres-data:/var/lib/postgresql/data + env_file: + # Ensure that the variables in .env match the same variables in devcontainer.json + - .env + + # Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally. + # (Adding the "ports" property to this file will not forward from a Codespace.) \ No newline at end of file diff --git a/backend/oidc-bff/Cargo.toml b/backend/oidc-bff/Cargo.toml new file mode 100644 index 000000000..359686b18 --- /dev/null +++ b/backend/oidc-bff/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "oidc-bff" +version = "0.1.0" +edition = "2024" +default-run = "oidc-bff" + +[lib] +name = "oidc_bff" # the library name as used in code: `use oidc_bff::...` +path = "src/lib.rs" + + +[[bin]] +name = "keygen" +path = "src/bin/keygen.rs" +publish = false + +[dependencies] +anyhow = { workspace = true, features = ["backtrace"] } +axum = { workspace = true, features = ["macros"] } +axum-reverse-proxy = "1.0.3" +bytes = "1.11.0" +chrono.workspace = true +clap.workspace = true +dotenvy.workspace = true +http-body-util = "0.1.3" +hyper = "1.8.1" +moka = { version = "0.12.11", features = ["future"] } +oauth2 = "5.0.0" +openidconnect = { version = "4.0.1", features = ["timing-resistant-secret-traits"]} +rustls = { version = "0.23.35", features = ["ring"] } +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +tokio = { workspace = true, features = ["full"] } +tower-sessions = "0.14.0" +sea-orm = {workspace=true} +migration = { version = "0.1.0", path = "migration" } +sodiumoxide = "0.2.7" +base64 = "0.22.1" +serde_yaml = "0.9.34" diff --git a/backend/oidc-bff/config.yaml b/backend/oidc-bff/config.yaml new file mode 100644 index 000000000..9b860a1c2 --- /dev/null +++ b/backend/oidc-bff/config.yaml @@ -0,0 +1,11 @@ +client_id: "workflows-ui-dev" +client_secret: "" +oidc_provider_url: "https://authn.diamond.ac.uk/realms/master" +port: 5173 +postgres_user: "postgres" +postgres_password: "postgres" +postgres_database: "postgres" +postgres_hostname: "localhost" +postgres_port: 5432 +encryption_public_key: "/8MLLEwz7CkTkUv9y1pq6Gcv2Aomlhpq7shhv95Lil0=" +encryption_private_key: "7f3saJVP6ISBaarRJ5KyNF0IFezCFDEmC556ygO3kQk=" \ No newline at end of file diff --git a/backend/oidc-bff/migration/Cargo.toml b/backend/oidc-bff/migration/Cargo.toml new file mode 100644 index 000000000..7d06f07ec --- /dev/null +++ b/backend/oidc-bff/migration/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "migration" +version = "0.1.0" +edition = "2024" +rust-version = "1.85.0" +publish = false + +[lib] +name = "migration" +path = "src/lib.rs" + +[dependencies] +tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] } + +[dependencies.sea-orm-migration] +version = "2.0.0-rc" +features = [ + # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. + # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. + # e.g. + "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature + "sqlx-postgres", # `DATABASE_DRIVER` feature +] diff --git a/backend/oidc-bff/migration/README.md b/backend/oidc-bff/migration/README.md new file mode 100644 index 000000000..3b438d89e --- /dev/null +++ b/backend/oidc-bff/migration/README.md @@ -0,0 +1,41 @@ +# Running Migrator CLI + +- Generate a new migration file + ```sh + cargo run -- generate MIGRATION_NAME + ``` +- Apply all pending migrations + ```sh + cargo run + ``` + ```sh + cargo run -- up + ``` +- Apply first 10 pending migrations + ```sh + cargo run -- up -n 10 + ``` +- Rollback last applied migrations + ```sh + cargo run -- down + ``` +- Rollback last 10 applied migrations + ```sh + cargo run -- down -n 10 + ``` +- Drop all tables from the database, then reapply all migrations + ```sh + cargo run -- fresh + ``` +- Rollback all applied migrations, then reapply all migrations + ```sh + cargo run -- refresh + ``` +- Rollback all applied migrations + ```sh + cargo run -- reset + ``` +- Check the status of all migrations + ```sh + cargo run -- status + ``` diff --git a/backend/oidc-bff/migration/src/lib.rs b/backend/oidc-bff/migration/src/lib.rs new file mode 100644 index 000000000..2c605afb9 --- /dev/null +++ b/backend/oidc-bff/migration/src/lib.rs @@ -0,0 +1,12 @@ +pub use sea_orm_migration::prelude::*; + +mod m20220101_000001_create_table; + +pub struct Migrator; + +#[async_trait::async_trait] +impl MigratorTrait for Migrator { + fn migrations() -> Vec> { + vec![Box::new(m20220101_000001_create_table::Migration)] + } +} diff --git a/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs b/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs new file mode 100644 index 000000000..c47c5dbbb --- /dev/null +++ b/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs @@ -0,0 +1,56 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(OidcTokens::Table) + .if_not_exists() + .col(ColumnDef::new(OidcTokens::Issuer).text().not_null()) + .col(ColumnDef::new(OidcTokens::Subject).text().not_null()) + .col( + ColumnDef::new(OidcTokens::EncryptedRefreshToken) + .binary() + .not_null(), + ) + .col(ColumnDef::new(OidcTokens::ExpiresAt).timestamp_with_time_zone()) + .col( + ColumnDef::new(OidcTokens::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(Expr::current_timestamp()), + ) + .col( + ColumnDef::new(OidcTokens::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(Expr::current_timestamp()), + ) + .primary_key(Index::create().col(OidcTokens::Subject).primary()) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(OidcTokens::Table).to_owned()) + .await + } +} + +#[derive(Iden)] +enum OidcTokens { + Table, + Issuer, + Subject, + EncryptedRefreshToken, + ExpiresAt, + CreatedAt, + UpdatedAt, +} diff --git a/backend/oidc-bff/migration/src/main.rs b/backend/oidc-bff/migration/src/main.rs new file mode 100644 index 000000000..f054deaf8 --- /dev/null +++ b/backend/oidc-bff/migration/src/main.rs @@ -0,0 +1,6 @@ +use sea_orm_migration::prelude::*; + +#[tokio::main] +async fn main() { + cli::run_cli(migration::Migrator).await; +} diff --git a/backend/oidc-bff/src/auth_proxy.rs b/backend/oidc-bff/src/auth_proxy.rs new file mode 100644 index 000000000..155f74bbd --- /dev/null +++ b/backend/oidc-bff/src/auth_proxy.rs @@ -0,0 +1,69 @@ +#[derive(Parser, Debug)] +#[command(author, version, about)] +struct Args { + /// Path to config file (JSON or YAML) + #[arg( + short, + long, + env = "WORKFLOWS_AUTH_PROXY_CONFIG", + default_value = "config.yaml" + )] + config: String, +} + + +#[tokio::main] +async fn main() -> Result<()> { + dotenvy::dotenv().ok(); + let args: Args = Args::try_parse()?; + let config = Config::from_file(args.config)?; + let port = config.port; + let appstate = Arc::new(AppState::new(config).await?); + + rustls::crypto::ring::default_provider() + .install_default() + .expect("Failed to install rust TLS cryptography"); + + let router = create_router(appstate); + serve(router, port).await +} + +fn create_router(state: Arc) -> Router { + let proxy: Router<()> = + ReverseProxy::new("/", "https://staging.workflows.diamond.ac.uk/graphql").into(); + let proxy = proxy; + + Router::new() + .nest_service("/api", proxy) + .layer(middleware::from_fn_with_state( + state.clone(), + inject_token_from_session::inject_token_from_session, + )) + .route("/healthcheck", get(healthcheck::healthcheck)) + .layer(session_layer) + .with_state(state) +} + +async fn serve(router: Router, port: u16) -> Result<()> { + let listener = + tokio::net::TcpListener::bind(SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port)).await?; + let service = router.into_make_service(); + axum::serve(listener, service).await?; + Ok(()) +} + +async fn logout() {} + +async fn debug(State(state): State>, session: Session) -> Result { + let auth_session_data: Option = + session.get(LoginSessionData::SESSION_KEY).await?; + + let token_session_data: Option = + session.get(TokenSessionData::SESSION_KEY).await?; + + Ok(Json(( + state.config.clone(), + auth_session_data, + token_session_data, + ))) +} diff --git a/backend/oidc-bff/src/auth_session_data.rs b/backend/oidc-bff/src/auth_session_data.rs new file mode 100644 index 000000000..62f9aff45 --- /dev/null +++ b/backend/oidc-bff/src/auth_session_data.rs @@ -0,0 +1,116 @@ +use std::time::Duration; + +use crate::Result; +use anyhow::anyhow; +use chrono::{DateTime, Utc}; +use openidconnect::{ + AccessToken, CsrfToken, EmptyAdditionalClaims, IssuerUrl, Nonce, PkceCodeVerifier, + RefreshToken, SubjectIdentifier, TokenResponse, + core::{CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm}, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct LoginSessionData { + pub csrf_token: CsrfToken, + pub pcke_verifier: PkceCodeVerifier, + pub nonce: Nonce, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TokenSessionData { + pub issuer: IssuerUrl, + pub subject: SubjectIdentifier, + pub access_token: AccessToken, + pub access_token_expires_at: DateTime, + pub refresh_token: RefreshToken, +} + +impl TokenSessionData { + pub const SESSION_KEY: &str = "token_session_data"; + + pub fn new( + issuer: IssuerUrl, + subject: SubjectIdentifier, + access_token: AccessToken, + access_token_expires_at: DateTime, + refresh_token: RefreshToken, + ) -> Self { + Self { + issuer, + subject, + access_token, + access_token_expires_at, + refresh_token, + } + } + + pub fn from_token_response( + token_response: &T, + issuer: IssuerUrl, + subject: SubjectIdentifier, + ) -> Result { + let access_token = token_response.access_token().clone(); + let refresh_token = token_response + .refresh_token() + .ok_or_else(|| anyhow!("Token Response did not return a refresh token"))? + .clone(); + let access_token_expires_at = Utc::now() + + token_response + .expires_in() + .unwrap_or_else(|| Duration::from_secs(60)); + Ok(Self::new( + issuer, + subject, + access_token, + access_token_expires_at, + refresh_token, + )) + } + + pub fn update_tokens_mut(&mut self, token_response: &T) { + let access_token = token_response.access_token().clone(); + let refresh_token = token_response.refresh_token(); + let access_token_expires_at = Utc::now() + + token_response + .expires_in() + .unwrap_or_else(|| Duration::from_secs(60)); + if let Some(refresh_token) = refresh_token { + self.refresh_token = refresh_token.clone(); + } + self.access_token = access_token; + self.access_token_expires_at = access_token_expires_at; + } + + pub fn update_tokens(&self, token_response: &T) -> Self { + let mut clone = self.clone(); + clone.update_tokens_mut(token_response); + clone + } + + pub fn access_token_is_expired(&self) -> bool { + self.access_token_expires_at <= Utc::now() + } +} + +impl Clone for LoginSessionData { + fn clone(&self) -> Self { + Self { + csrf_token: self.csrf_token.clone(), + pcke_verifier: PkceCodeVerifier::new(self.pcke_verifier.secret().clone()), + nonce: self.nonce.clone(), + } + } +} + +impl LoginSessionData { + pub const SESSION_KEY: &str = "auth_session_data"; + + pub fn new(csrf_token: CsrfToken, pcke_verifier: PkceCodeVerifier, nonce: Nonce) -> Self { + Self { + csrf_token, + pcke_verifier, + nonce, + } + } +} diff --git a/backend/oidc-bff/src/bin/keygen.rs b/backend/oidc-bff/src/bin/keygen.rs new file mode 100644 index 000000000..a49b24626 --- /dev/null +++ b/backend/oidc-bff/src/bin/keygen.rs @@ -0,0 +1,23 @@ +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use sodiumoxide::crypto::box_::gen_keypair; + +fn main() { + // Initialize sodiumoxide (required before using crypto functions) + if sodiumoxide::init().is_err() { + eprintln!("Failed to initialize libsodium"); + std::process::exit(1); + } + + // Generate a new sealed-box keypair + let (public_key, secret_key) = gen_keypair(); + + // Base64 encode for easy storage in environment variables + let public_b64 = BASE64.encode(public_key.0); + let secret_b64 = BASE64.encode(secret_key.0); + + println!("Public Key:"); + println!("{}", public_b64); + println!(); + println!("Private Key:"); + println!("{}", secret_b64); +} diff --git a/backend/oidc-bff/src/callback.rs b/backend/oidc-bff/src/callback.rs new file mode 100644 index 000000000..0ef31f138 --- /dev/null +++ b/backend/oidc-bff/src/callback.rs @@ -0,0 +1,113 @@ +use std::borrow::Cow; +use std::sync::Arc; + +use axum::debug_handler; +use axum::extract::{Query, State}; +use openidconnect::core::{CoreClient, CoreProviderMetadata}; +use openidconnect::{ + AccessTokenHash, AuthorizationCode, ClientId, ClientSecret, CsrfToken, IssuerUrl, + OAuth2TokenResponse, RedirectUrl, TokenResponse, reqwest, +}; +use serde::{Deserialize, Serialize}; +use tower_sessions::Session; + +use crate::Result; +use crate::auth_session_data::{LoginSessionData, TokenSessionData}; +use crate::database::write_token_to_database; +use crate::state::AppState; + +#[derive(Serialize, Deserialize)] +pub struct CallbackQuery { + pub code: String, + pub state: String, +} +use anyhow::anyhow; + +#[debug_handler] +pub async fn callback( + State(state): State>, + Query(params): Query, + session: Session, +) -> Result { + // Retrieve data from the users session + let auth_session_data: LoginSessionData = session + .remove(LoginSessionData::SESSION_KEY) + .await? + .ok_or(anyhow!("session expired"))?; + + // Once the user has been redirected to the redirect URL, you'll have access to the + // authorization code. For security reasons, your code should verify that the `state` + // parameter returned by the server matches `csrf_state`. + + if auth_session_data.csrf_token != CsrfToken::new(params.state) { + return Err(anyhow!("invalid state").into()); + } + let redirect_url = Cow::Owned(RedirectUrl::new( + // "http://localhost:5173/auth/callback".to_string(), + "https://staging.workflows.diamond.ac.uk/auth/callback".to_string(), + )?); + // Now you can exchange it for an access token and ID token. + let token_response = state + .oidc_client + .exchange_code(AuthorizationCode::new(params.code.to_string()))? + // Set the PKCE code verifier. + .set_pkce_verifier(auth_session_data.pcke_verifier) + .set_redirect_uri(redirect_url) + .request_async(&state.http_client) + .await?; + + // Extract the ID token claims after verifying its authenticity and nonce. + let id_token = token_response + .id_token() + .ok_or_else(|| anyhow!("Server did not return an ID token"))?; + let id_token_verifier = state.oidc_client.id_token_verifier(); + let claims = id_token.claims(&id_token_verifier, &auth_session_data.nonce)?; + + // Verify the access token hash to ensure that the access token hasn't been substituted for + // another user's. + if let Some(expected_access_token_hash) = claims.access_token_hash() { + let actual_access_token_hash = AccessTokenHash::from_token( + token_response.access_token(), + id_token.signing_alg()?, + id_token.signing_key(&id_token_verifier)?, + )?; + if actual_access_token_hash != *expected_access_token_hash { + return Err(anyhow!("Invalid access token").into()); + } + } + + // The authenticated user's identity is now available. See the IdTokenClaims struct for a + // complete listing of the available claims. + let response = format!( + "User {} with e-mail address {} has authenticated successfully", + claims.subject().as_str(), + claims + .email() + .map(|email| email.as_str()) + .unwrap_or(""), + ); + + // If available, we can use the user info endpoint to request additional information. + + // // The user_info request uses the AccessToken returned in the token response. To parse custom + // // claims, use UserInfoClaims directly (with the desired type parameters) rather than using the + // // CoreUserInfoClaims type alias. + // let userinfo: CoreUserInfoClaims = client + // .user_info(token_response.access_token().to_owned(), None)? + // .request_async(&http_client) + // .await + // .map_err(|err| anyhow!("Failed requesting user info: {}", err))?; + + // See the OAuth2TokenResponse trait for a listing of other available fields such as + // access_token() and refresh_token(). + let token_data = TokenSessionData::from_token_response( + &token_response, + claims.issuer().clone(), + claims.subject().clone(), + )?; + write_token_to_database(&state.database_connection, &token_data, &state.public_key).await?; + session + .insert(TokenSessionData::SESSION_KEY, token_data) + .await?; + Ok(response) +} diff --git a/backend/oidc-bff/src/config.rs b/backend/oidc-bff/src/config.rs new file mode 100644 index 000000000..2b7e63bb5 --- /dev/null +++ b/backend/oidc-bff/src/config.rs @@ -0,0 +1,33 @@ +use std::path::Path; + +use crate::Result; +use anyhow::anyhow; +use serde::Deserialize; +use serde::Serialize; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub client_id: String, + pub client_secret: String, + pub oidc_provider_url: String, + pub port: u16, + pub postgres_user: String, + pub postgres_password: String, + pub postgres_database: String, + pub postgres_hostname: String, + pub postgres_port: u16, + pub encryption_public_key: String, + pub encryption_private_key: String, +} + +impl Config { + /// Load config from JSON or YAML file + pub fn from_file>(path: P) -> Result { + let content = std::fs::read_to_string(&path)?; + match path.as_ref().extension().and_then(|e| e.to_str()) { + Some("json") => Ok(serde_json::from_str(&content)?), + // otherwise assume yaml + _ => Ok(serde_yaml::from_str(&content)?), + } + } +} diff --git a/backend/oidc-bff/src/counter.rs b/backend/oidc-bff/src/counter.rs new file mode 100644 index 000000000..16886ff5a --- /dev/null +++ b/backend/oidc-bff/src/counter.rs @@ -0,0 +1,29 @@ +use axum::response::IntoResponse; +use serde::{Deserialize, Serialize}; +use tower_sessions::Session; + +use crate::auth_session_data::LoginSessionData; + +const COUNTER_KEY: &str = "counter"; + +#[derive(Default, Deserialize, Serialize)] +struct Counter(usize); + +pub async fn counter_write(session: Session) -> impl IntoResponse { + let counter: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default(); + let old = counter.0; + session.insert(COUNTER_KEY, counter.0 + 1).await.unwrap(); + let new: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default(); + format!("Current count: {}\nNew count: {}", old, new.0) +} + +pub async fn counter_read(session: Session) -> impl IntoResponse { + let counter: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default(); + let auth_session_data = session + .get::(LoginSessionData::SESSION_KEY) + .await; + format!( + "Reading current count: {}, auth_session_data={:?}", + counter.0, auth_session_data + ) +} diff --git a/backend/oidc-bff/src/database.rs b/backend/oidc-bff/src/database.rs new file mode 100644 index 000000000..3bf6da87b --- /dev/null +++ b/backend/oidc-bff/src/database.rs @@ -0,0 +1,51 @@ +use chrono::{DateTime, Duration, FixedOffset, Utc}; +//use sea_orm::{ActiveModelTrait, DatabaseConnection, Query}; +use crate::{Result, auth_session_data::TokenSessionData}; +use sea_orm::*; +use oidc_bff::entity; + +pub async fn migrate_database(connection: &DatabaseConnection) -> Result<()> { + use migration::{Migrator, MigratorTrait}; + + Migrator::up(connection, None).await?; + Ok(()) +} + +pub async fn write_token_to_database( + connection: &DatabaseConnection, + token: &TokenSessionData, + public_key: &sodiumoxide::crypto::box_::PublicKey, +) -> Result<()> { + let encrypted_refresh_token = + sodiumoxide::crypto::sealedbox::seal(token.refresh_token.secret().as_bytes(), public_key); + let refresh_token_expires_at = Utc::now() + Duration::days(30); // TODO: offline_access tokens will expire if not used within 30 days. Keycloak returns the actual expiration date in the field "refresh_expires_in", we should use that + let token_update = entity::oidc_tokens::ActiveModel { + issuer: Set(token.issuer.to_string()), + subject: Set(token.subject.to_string()), + encrypted_refresh_token: Set(encrypted_refresh_token), + expires_at: Set(Some(convert_time(refresh_token_expires_at))), + created_at: Set(Utc::now().into()), + updated_at: Set(Utc::now().into()), + ..Default::default() + }; + entity::oidc_tokens::Entity::insert(token_update) + .on_conflict( + sea_query::OnConflict::column(entity::oidc_tokens::Column::Subject) + .update_columns([ + entity::oidc_tokens::Column::Issuer, + entity::oidc_tokens::Column::Subject, + entity::oidc_tokens::Column::EncryptedRefreshToken, + entity::oidc_tokens::Column::ExpiresAt, + entity::oidc_tokens::Column::UpdatedAt, + // deliberately do not update CreatedAt + ]) + .to_owned(), + ) + .exec(connection) + .await?; + Ok(()) +} + +fn convert_time(utc_time: DateTime) -> DateTime { + utc_time.with_timezone(&FixedOffset::east_opt(0).unwrap()) +} diff --git a/backend/oidc-bff/src/entity/mod.rs b/backend/oidc-bff/src/entity/mod.rs new file mode 100644 index 000000000..889654a14 --- /dev/null +++ b/backend/oidc-bff/src/entity/mod.rs @@ -0,0 +1,5 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 + +pub mod prelude; + +pub mod oidc_tokens; diff --git a/backend/oidc-bff/src/entity/oidc_tokens.rs b/backend/oidc-bff/src/entity/oidc_tokens.rs new file mode 100644 index 000000000..23ee74526 --- /dev/null +++ b/backend/oidc-bff/src/entity/oidc_tokens.rs @@ -0,0 +1,22 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "oidc_tokens")] +pub struct Model { + #[sea_orm(column_type = "Text")] + pub issuer: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub subject: String, + #[sea_orm(column_type = "VarBinary(StringLen::None)")] + pub encrypted_refresh_token: Vec, + pub expires_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/backend/oidc-bff/src/entity/prelude.rs b/backend/oidc-bff/src/entity/prelude.rs new file mode 100644 index 000000000..b303a78d8 --- /dev/null +++ b/backend/oidc-bff/src/entity/prelude.rs @@ -0,0 +1,3 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 + +pub use super::oidc_tokens::Entity as OidcTokens; diff --git a/backend/oidc-bff/src/error.rs b/backend/oidc-bff/src/error.rs new file mode 100644 index 000000000..a944ebb41 --- /dev/null +++ b/backend/oidc-bff/src/error.rs @@ -0,0 +1,26 @@ +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; + +#[derive(Debug)] +pub struct Error(anyhow::Error); + +impl IntoResponse for Error { + fn into_response(self) -> Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Something went wrong: {}", self.0), + ) + .into_response() + } +} + +impl From for Error +where + E: Into, +{ + fn from(err: E) -> Self { + Self(err.into()) + } +} diff --git a/backend/oidc-bff/src/healthcheck.rs b/backend/oidc-bff/src/healthcheck.rs new file mode 100644 index 000000000..c9be25c8a --- /dev/null +++ b/backend/oidc-bff/src/healthcheck.rs @@ -0,0 +1,5 @@ +use axum::http::StatusCode; + +pub async fn healthcheck() -> StatusCode { + StatusCode::ACCEPTED +} diff --git a/backend/oidc-bff/src/inject_token.rs b/backend/oidc-bff/src/inject_token.rs new file mode 100644 index 000000000..a919f526f --- /dev/null +++ b/backend/oidc-bff/src/inject_token.rs @@ -0,0 +1,113 @@ +use crate::{database::write_token_to_database, state::AppState}; +use openidconnect::{ + ClientId, ClientSecret, IssuerUrl, TokenResponse, + core::{CoreClient, CoreProviderMetadata}, + reqwest, +}; +use std::sync::Arc; +use tower_sessions::Session; + +use axum::{ + body::Body, + extract::{Request, State}, + http::{self, HeaderValue, StatusCode}, + middleware, +}; + +use crate::Result; + +use crate::auth_session_data::TokenSessionData; + +pub async fn inject_token_from_session( + State(state): State>, + session: Session, + req: Request, + next: middleware::Next, +) -> Result { + inject_token(state, session, req, next).await +} + +trait TokenStore { + async fn get(&self) -> Result>; + async fn insert(&self, token: TokenSessionData) -> Result<()>; +} + +impl TokenStore for Session { + async fn get(&self) -> Result> { + Ok(self.get(TokenSessionData::SESSION_KEY).await?) + } + + async fn insert(&self, token: TokenSessionData) -> Result<()> { + Ok(self + .insert(TokenSessionData::SESSION_KEY, token.clone()) + .await?) + } +} + +async fn inject_token( + state: State>, + store: impl TokenStore, + req: Request, + next: middleware::Next, +) -> Result { +// Read token from session + let token: Option = store.get().await?; + if let Some(mut token) = token { + if (token.access_token_is_expired()) { + token = refresh_token_and_update_session(&state, &token, &store).await?; + } + let mut req = clone_request(req).await?; + prepare_headers(&mut req.0, &token); + let response = next.clone().run(req.0).await; + if response.status() == StatusCode::UNAUTHORIZED { + token = refresh_token_and_update_session(&state, &token, &store).await?; + prepare_headers(&mut req.1, &token); + Ok(next.run(req.1).await) + } else { + Ok(response) + } + } else { + Ok(next.run(req).await) + } +} + +async fn clone_request(req: Request) -> Result<(Request, Request)> { + // TODO: an inefficient method of cloning a request, improve this + let (parts, body) = req.into_parts(); + let bytes = http_body_util::BodyExt::collect(body).await?.to_bytes(); + let req1 = Request::from_parts(parts.clone(), Body::from(bytes.clone())); + let req2 = Request::from_parts(parts, Body::from(bytes)); + Ok((req1, req2)) +} + +fn prepare_headers(req: &mut Request, token: &TokenSessionData) { + let value = format!("Bearer {}", token.access_token.secret()); + req.headers_mut().insert( + http::header::AUTHORIZATION, + HeaderValue::from_str(&value).unwrap(), + ); + req.headers_mut().remove(http::header::COOKIE); +} + +async fn refresh_token_and_update_session( + state: &AppState, + token: &TokenSessionData, + session: &impl TokenStore, +) -> Result { + let token = refresh_token(state, token).await?; + write_token_to_database(&state.database_connection, &token, &state.public_key).await?; + session + .insert(token.clone()) + .await?; + Ok(token) +} + +async fn refresh_token(state: &AppState, token: &TokenSessionData) -> Result { + let token_response = state + .oidc_client + .exchange_refresh_token(&token.refresh_token)? + .request_async(&state.http_client) + .await?; + let token = token.update_tokens(&token_response); + Ok(token) +} diff --git a/backend/oidc-bff/src/inject_token_from_session.rs b/backend/oidc-bff/src/inject_token_from_session.rs new file mode 100644 index 000000000..1efec50ef --- /dev/null +++ b/backend/oidc-bff/src/inject_token_from_session.rs @@ -0,0 +1,87 @@ +use crate::{database::write_token_to_database, state::AppState}; +use openidconnect::{ + ClientId, ClientSecret, IssuerUrl, TokenResponse, + core::{CoreClient, CoreProviderMetadata}, + reqwest, +}; +use std::sync::Arc; +use tower_sessions::Session; + +use axum::{ + body::Body, + extract::{Request, State}, + http::{self, HeaderValue, StatusCode}, + middleware, +}; + +use crate::Result; + +use crate::auth_session_data::TokenSessionData; + +pub async fn inject_token_from_session( + State(state): State>, + session: Session, + req: Request, + next: middleware::Next, +) -> Result { + // Read token from session + let token: Option = session.get(TokenSessionData::SESSION_KEY).await?; + if let Some(mut token) = token { + if (token.access_token_is_expired()) { + token = refresh_token_and_update_session(&state, &token, &session).await?; + } + let mut req = clone_request(req).await?; + prepare_headers(&mut req.0, &token); + let response = next.clone().run(req.0).await; + if response.status() == StatusCode::UNAUTHORIZED { + token = refresh_token_and_update_session(&state, &token, &session).await?; + prepare_headers(&mut req.1, &token); + Ok(next.run(req.1).await) + } else { + Ok(response) + } + } else { + Ok(next.run(req).await) + } +} + +async fn clone_request(req: Request) -> Result<(Request, Request)> { + // TODO: an inefficient method of cloning a request, improve this + let (parts, body) = req.into_parts(); + let bytes = http_body_util::BodyExt::collect(body).await?.to_bytes(); + let req1 = Request::from_parts(parts.clone(), Body::from(bytes.clone())); + let req2 = Request::from_parts(parts, Body::from(bytes)); + Ok((req1, req2)) +} + +fn prepare_headers(req: &mut Request, token: &TokenSessionData) { + let value = format!("Bearer {}", token.access_token.secret()); + req.headers_mut().insert( + http::header::AUTHORIZATION, + HeaderValue::from_str(&value).unwrap(), + ); + req.headers_mut().remove(http::header::COOKIE); +} + +async fn refresh_token_and_update_session( + state: &AppState, + token: &TokenSessionData, + session: &Session, +) -> Result { + let token = refresh_token(state, token).await?; + write_token_to_database(&state.database_connection, &token, &state.public_key).await?; + session + .insert(TokenSessionData::SESSION_KEY, token.clone()) + .await?; + Ok(token) +} + +async fn refresh_token(state: &AppState, token: &TokenSessionData) -> Result { + let token_response = state + .oidc_client + .exchange_refresh_token(&token.refresh_token)? + .request_async(&state.http_client) + .await?; + let token = token.update_tokens(&token_response); + Ok(token) +} diff --git a/backend/oidc-bff/src/lib.rs b/backend/oidc-bff/src/lib.rs new file mode 100644 index 000000000..bccca666a --- /dev/null +++ b/backend/oidc-bff/src/lib.rs @@ -0,0 +1 @@ +pub mod entity; \ No newline at end of file diff --git a/backend/oidc-bff/src/login.rs b/backend/oidc-bff/src/login.rs new file mode 100644 index 000000000..703866c83 --- /dev/null +++ b/backend/oidc-bff/src/login.rs @@ -0,0 +1,49 @@ +use std::sync::Arc; + +use axum::extract::State; +use axum::response::Redirect; +use openidconnect::core::{CoreAuthenticationFlow, CoreClient, CoreProviderMetadata}; +use openidconnect::reqwest; +use openidconnect::{ + ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce, PkceCodeChallenge, RedirectUrl, Scope, +}; +use tower_sessions::Session; + +use crate::Result; +use crate::auth_session_data::LoginSessionData; +use crate::state::AppState; + +#[axum::debug_handler] +pub async fn login(State(state): State>, session: Session) -> Result { + // Set the URL the user will be redirected to after the authorization process. + // .set_redirect_uri(RedirectUrl::new("https://localhost/callback".to_string())?); + let oidc_client = state.oidc_client.clone().set_redirect_uri(RedirectUrl::new( + // "http://localhost:5173/auth/callback".to_string(), + "https://staging.workflows.diamond.ac.uk/auth/callback".to_string(), + )?); + // .set_redirect_uri(RedirectUrl::new("https://workflows.diamond.ac.uk".to_string())?) + // Generate a PKCE challenge. + let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); + + // Generate the full authorization URL. + let (auth_url, csrf_token, nonce) = oidc_client + .authorize_url( + CoreAuthenticationFlow::AuthorizationCode, + CsrfToken::new_random, + Nonce::new_random, + ) + // Set the desired scopes. + .add_scope(Scope::new("openid".to_string())) + .add_scope(Scope::new("offline_access".to_string())) + // Set the PKCE code challenge. + .set_pkce_challenge(pkce_challenge) + .url(); + + // Store data in the users session + let auth_session_data = LoginSessionData::new(csrf_token, pkce_verifier, nonce); + session + .insert(LoginSessionData::SESSION_KEY, auth_session_data) + .await?; + + Ok(Redirect::temporary(auth_url.as_str())) +} diff --git a/backend/oidc-bff/src/main.rs b/backend/oidc-bff/src/main.rs new file mode 100644 index 000000000..1faacd719 --- /dev/null +++ b/backend/oidc-bff/src/main.rs @@ -0,0 +1,115 @@ +mod healthcheck; +mod config; +mod login; +mod auth_session_data; +mod state; +mod callback; +mod counter; +mod database; +mod error; + +use clap::Parser; +use config::Config; +use tower_sessions::{MemoryStore, Session, SessionManagerLayer}; +use std::{ + net::{Ipv4Addr, SocketAddr}, + sync::Arc, +}; +use state::AppState; + +type Result = std::result::Result; + +use axum::{ + Json, Router, + extract::State, + middleware, + response::IntoResponse, + routing::{get, post}, +}; +use axum_reverse_proxy::ReverseProxy; + +use crate::auth_session_data::{LoginSessionData, TokenSessionData}; +mod inject_token_from_session; + +#[derive(Parser, Debug)] +#[command(author, version, about)] +struct Args { + /// Path to config file (JSON or YAML) + #[arg( + short, + long, + env = "WORKFLOWS_OIDC_BFF_CONFIG", + default_value = "config.yaml" + )] + config: String, +} + +#[tokio::main] +async fn main() -> Result<()> { + dotenvy::dotenv().ok(); + let args: Args = Args::try_parse()?; + let config = Config::from_file(args.config)?; + let port = config.port; + let appstate = Arc::new(AppState::new(config).await?); + + database::migrate_database(&appstate.database_connection).await?; + + rustls::crypto::ring::default_provider() + .install_default() + .expect("Failed to install rust TLS cryptography"); + + let router = create_router(appstate); + serve(router, port).await +} + +fn create_router(state: Arc) -> Router { + let session_store = MemoryStore::default(); + let session_layer = SessionManagerLayer::new(session_store) + .with_secure(false) + // .with_expiry(Expiry::OnInactivity(Duration::seconds(600))) + ; + + let proxy: Router<()> = + ReverseProxy::new("/", "https://staging.workflows.diamond.ac.uk/graphql").into(); + let proxy = proxy; + + Router::new() + .fallback_service(proxy) + .layer(middleware::from_fn_with_state( + state.clone(), + inject_token_from_session::inject_token_from_session, + )) + .route("/auth/login", get(login::login)) + .route("/read", get(counter::counter_read)) + .route("/write", get(counter::counter_write)) + .route("/auth/callback", get(callback::callback)) + .route("/auth/logout", post(logout)) + // .route("/debug", get(debug)) + .route("/healthcheck", get(healthcheck::healthcheck)) + .layer(session_layer) + .with_state(state) +} + +async fn serve(router: Router, port: u16) -> Result<()> { + let listener = + tokio::net::TcpListener::bind(SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port)).await?; + let service = router.into_make_service(); + axum::serve(listener, service).await?; + Ok(()) +} + +async fn logout() {} + +async fn debug(State(state): State>, session: Session) -> Result { + let auth_session_data: Option = + session.get(LoginSessionData::SESSION_KEY).await?; + + let token_session_data: Option = + session.get(TokenSessionData::SESSION_KEY).await?; + + Ok(Json(( + state.config.clone(), + auth_session_data, + token_session_data, + ))) +} diff --git a/backend/oidc-bff/src/state.rs b/backend/oidc-bff/src/state.rs new file mode 100644 index 000000000..3143ee68f --- /dev/null +++ b/backend/oidc-bff/src/state.rs @@ -0,0 +1,73 @@ +use crate::Result; +use crate::config::Config; +use anyhow::anyhow; +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use oauth2::{ClientId, ClientSecret, EndpointMaybeSet, EndpointNotSet, EndpointSet, reqwest}; +use openidconnect::IssuerUrl; +use openidconnect::core::{CoreClient, CoreProviderMetadata}; +use sea_orm::Database; +use sea_orm::DatabaseConnection; +use serde::{Deserialize, Serialize}; +use sodiumoxide::crypto::box_::PublicKey; +#[derive(Debug, Clone)] +pub struct AppState { + pub config: Config, + pub http_client: reqwest::Client, + pub oidc_client: openidconnect::core::CoreClient< + EndpointSet, + EndpointNotSet, + EndpointNotSet, + EndpointNotSet, + EndpointMaybeSet, + EndpointMaybeSet, + >, + pub database_connection: DatabaseConnection, + pub public_key: PublicKey, +} + +impl AppState { + pub async fn new(config: Config) -> Result { + let http_client = reqwest::ClientBuilder::new() + // Following redirects opens the client up to SSRF vulnerabilities. + .redirect(reqwest::redirect::Policy::none()) + .build()?; + + // Use OpenID Connect Discovery to fetch the provider metadata. + let provider_metadata = CoreProviderMetadata::discover_async( + IssuerUrl::new(config.oidc_provider_url.to_string())?, + &http_client, + ) + .await?; + + let oidc_client = CoreClient::from_provider_metadata( + provider_metadata, + ClientId::new(config.client_id.to_string()), + if config.client_secret.is_empty() { + None + } else { + Some(ClientSecret::new(config.client_secret.to_string())) + }, + ); + + let database_url = format!( + "postgres://{}:{}@{}:{}/{}", + config.postgres_user, + config.postgres_password, + config.postgres_hostname, + config.postgres_port, + config.postgres_database + ); + let database_connection = Database::connect(&database_url).await?; + + let public_key = PublicKey::from_slice(&BASE64.decode(&config.encryption_public_key)?) + .ok_or(anyhow!("Invalid public key"))?; + + Ok(AppState { + config, + http_client, + oidc_client, + database_connection, + public_key, + }) + } +} diff --git a/charts/apps/staging-values.yaml b/charts/apps/staging-values.yaml index b7f56df52..f67852efe 100644 --- a/charts/apps/staging-values.yaml +++ b/charts/apps/staging-values.yaml @@ -57,7 +57,7 @@ sealedsecrets: workflows: enabled: true - targetRevision: HEAD + targetRevision: drh/bff-pkce-dev extraValueFiles: - staging-values.yaml @@ -69,7 +69,7 @@ graphProxy: dashboard: enabled: true - targetRevision: HEAD + targetRevision: drh/bff-pkce-dev extraValueFiles: - staging-values.yaml diff --git a/charts/apps/templates/dashboard-application.yaml b/charts/apps/templates/dashboard-application.yaml index 330003ac9..fbb55e805 100644 --- a/charts/apps/templates/dashboard-application.yaml +++ b/charts/apps/templates/dashboard-application.yaml @@ -8,7 +8,7 @@ metadata: argocd.argoproj.io/sync-wave: "2" spec: destination: - namespace: dashboard + namespace: workflows server: {{ .Values.destination.server }} project: default source: diff --git a/charts/apps/values.yaml b/charts/apps/values.yaml index 263114ecc..9d11c6847 100644 --- a/charts/apps/values.yaml +++ b/charts/apps/values.yaml @@ -122,7 +122,7 @@ sealedsecrets: workflows: enabled: true - targetRevision: HEAD + targetRevision: drh/bff-pkce-dev extraValuesFiles: [] valuesObject: {} @@ -134,7 +134,7 @@ graphProxy: dashboard: enabled: true - targetRevision: HEAD + targetRevision: drh/bff-pkce-dev extraValuesFiles: [] valuesObject: {} diff --git a/charts/dashboard/staging-values.yaml b/charts/dashboard/staging-values.yaml index 2f952f502..0a60ca559 100644 --- a/charts/dashboard/staging-values.yaml +++ b/charts/dashboard/staging-values.yaml @@ -13,6 +13,19 @@ ingress: paths: - path: / pathType: Prefix + service: + name: dashboard + port: 80 + - path: /api + pathType: Prefix + service: + name: oidc-bff + port: 80 + - path: /auth + pathType: Prefix + service: + name: oidc-bff + port: 80 tls: true secretName: dashboard-tls-cert diff --git a/charts/dashboard/templates/ingress.yaml b/charts/dashboard/templates/ingress.yaml index e4d34abb5..3ebbb7419 100644 --- a/charts/dashboard/templates/ingress.yaml +++ b/charts/dashboard/templates/ingress.yaml @@ -32,9 +32,9 @@ spec: {{- end }} backend: service: - name: {{ include "common.names.fullname" $ }} + name: {{ .service.name }} port: - number: {{ $.Values.service.port }} + number: {{ .service.port }} {{- end }} {{- end }} {{- end }} diff --git a/charts/dashboard/templates/oidc-bff.yaml b/charts/dashboard/templates/oidc-bff.yaml new file mode 100644 index 000000000..eeffd75c4 --- /dev/null +++ b/charts/dashboard/templates/oidc-bff.yaml @@ -0,0 +1,70 @@ +apiVersion: v1 +kind: Service +metadata: + name: oidc-bff + namespace: {{ .Release.Namespace }} +spec: + type: ClusterIP + selector: + app: oidc-bff + ports: + - name: oidc-bff + port: 80 + targetPort: 80 + protocol: TCP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: oidc-bff +spec: + replicas: 1 + selector: + matchLabels: + app: oidc-bff + template: + metadata: + labels: + app: oidc-bff + spec: + imagePullSecrets: {{ include "common.images.renderPullSecrets" (dict "images" (list $.Values.oidcBff.image) "context" $ ) }} + containers: + - name: oidc-bff + image: {{ include "common.images.image" ( dict "imageRoot" $.Values.oidcBff.image "global" $.Values.global "chart" $.Chart ) }} + imagePullPolicy: {{ $.Values.oidcBff.image.pullPolicy }} + ports: + - containerPort: 80 + livenessProbe: + httpGet: + path: /healthcheck + port: 80 + initialDelaySeconds: 3 + periodSeconds: 3 + readinessProbe: + httpGet: + path: /healthcheck + port: 80 + initialDelaySeconds: 5 + periodSeconds: 5 + startupProbe: + httpGet: + path: /healthcheck + port: 80 + failureThreshold: 3 + periodSeconds: 5 + env: + - name: WORKFLOWS_OIDC_BFF_CONFIG + value: "/etc/oidc-bff/config.yaml" + - name: RUST_BACKTRACE + value: "1" + volumeMounts: + - name: oidc-bff-config + mountPath: /etc/oidc-bff + readOnly: true + volumes: + - name: oidc-bff-config + secret: + secretName: {{ .Values.oidcBff.configuration.secretName | default "oidc-bff-config" }} + items: + - key: config.yaml + path: config.yaml diff --git a/charts/dashboard/templates/service.yaml b/charts/dashboard/templates/service.yaml index cbc43766e..1a6eeabf2 100644 --- a/charts/dashboard/templates/service.yaml +++ b/charts/dashboard/templates/service.yaml @@ -20,3 +20,4 @@ spec: targetPort: dashboard protocol: TCP {{- end }} + diff --git a/charts/dashboard/values.yaml b/charts/dashboard/values.yaml index b05d4e025..de0c45912 100644 --- a/charts/dashboard/values.yaml +++ b/charts/dashboard/values.yaml @@ -44,6 +44,19 @@ ingress: paths: - path: / pathType: Prefix + service: + name: dashboard + port: 80 + - path: /api + pathType: Prefix + service: + name: oidc-bff + port: 80 + - path: /auth + pathType: Prefix + service: + name: oidc-bff + port: 80 tls: false annotations: nginx.ingress.kubernetes.io/force-ssl-redirect: "true" @@ -55,3 +68,14 @@ serviceAccount: create: true name: "" annotations: [] + +oidcBff: + image: + registry: ghcr.io + repository: diamondlightsource/workflows-oidc-bff + tag: "davehadley" + digest: "sha256:e259494171d5115d060dd9f3d9da971312d39e9afabd91478c0b7a49c7c5f6d3" + pullPolicy: IfNotPresent + pullSecrets: [] + configuration: + secretName: oidc-bff-config diff --git a/charts/workflows-cluster/staging-values.yaml b/charts/workflows-cluster/staging-values.yaml index d30c54d38..bd4dd4715 100644 --- a/charts/workflows-cluster/staging-values.yaml +++ b/charts/workflows-cluster/staging-values.yaml @@ -56,7 +56,7 @@ vcluster: - staging-values.yaml path: charts/apps repoURL: https://github.com/DiamondLightSource/workflows.git - targetRevision: HEAD + targetRevision: drh/bff-pkce-dev syncPolicy: automated: prune: true @@ -68,13 +68,15 @@ vcluster: byName: "/letsencrypt-argo-cd-staging-workflows-diamond-ac-uk": "argocd/argo-cd-tls-cert" "/letsencrypt-argo-workflows-staging-workflows-diamond-ac-uk": "workflows/workflows-tls-cert" - "/letsencrypt-staging-workflows-diamond-ac-uk": "dashboard/dashboard-tls-cert" + "/letsencrypt-staging-workflows-diamond-ac-uk": "workflows/dashboard-tls-cert" "/argo-server-sso": "workflows/argo-server-sso" "/sessionspaces-ispyb": "kube-system/sessionspaces-ispyb" "/artifact-s3-secret": "graph-proxy/artifact-s3-secret" "/s3-artifact": "workflows/artifact-s3" + "/oidc-bff-config": "workflows/oidc-bff-config" "/postgres-passwords": "workflows/postgres-passwords" "/postgres-argo-workflows-password": "workflows/postgres-argo-workflows-password" + "/postgres-auth-service-password": "workflows/postgres-auth-service-password" "/postgres-application-passwords": "workflows/postgres-application-passwords" "/postgres-initdb-script": "workflows/postgres-initdb-script" @@ -110,6 +112,7 @@ authenticationConfiguration: - issuer: url: https://authn.diamond.ac.uk/realms/master audiences: + - workflows-dashboard-staging - workflows-cluster-staging - graph audienceMatchPolicy: MatchAny diff --git a/charts/workflows-cluster/templates/oidc-bff.yaml b/charts/workflows-cluster/templates/oidc-bff.yaml new file mode 100644 index 000000000..8afd7be74 --- /dev/null +++ b/charts/workflows-cluster/templates/oidc-bff.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + name: oidc-bff-config + namespace: workflows +spec: + encryptedData: + config.yaml: AgBmJplbabGvBLH9zqvt3YANVjBPUaARwJu/H0pBx/k5FpCSASfP0vKx7/XL4JCg01+awygBW8a8t7bBChs6yXTcatXGWKeVE1eX2go9XPmwGM9OKR8cLoFlufQx++0N6HhMAOuonCsbM33X9RbmfYm5Azxontmk9+W6nQqT+7UkcpPheC2f0tFKyJVvIVbrUOsJmls1TgmQUFZIj5dWtOrgChhC6rSbogMWF2WtFpT4RRlCKZUXMggFPTw82fjytCVxDXaxnjwD2Wzj33dY9gxy10iGp/MUQefZ2AM3iMqcgu2u0ENe5dCO8bKVcaemytRuKRiK6DUbKq2pa5gATUG9pDUhbW3g9Aa7sQyjvOSun+G4S+1+n9+EMTaYcv79eVkAnl07XHe6p5T3Bsl42iZdL8gMahtFwYH31yybWFI57Q66zyIFj7oTzr8zvyYwyYj/VpAA6gMKxAF2eBXwNOhKd7LnUjI7iitBiDxIBfNQImkfcfDaAQSm84JPZW1YJl6jolvJTQAckjLMrrzDKR4X953Qv9BsPZBjS16MVg3hkZR9Db3XdP2lSQngsT/WMDSJ44X0fxNHU6Hamv2hanvYw1kCJCeESYfA+aWtAcsZtjX2axRfiuWHTxVZ5nUcTsCuxbIpla/iS7jG5i81BZu79ilEKj2rJjm6of1y5dWehZm93DQjQK++jgU8Bil9UARvrLG2hsrodpl0FTSYUMAyF2Lct3FYp9yr5juMKWNqXeK4z/2E/fX3DbQUK0vNCpUXvhwTPq0KOtlnTBbQHJanHjROI5IMe2Mtmoypzne/K/pWJSGz7b6+n5jBGZJjaOeH77+f/mAFu5M3K/KL2yxEjU55BuHnzXhHgDQxErwM61NJQx5OhJI0zLcVln593N0c8J73Ei7I5yaEYo/AVorADwv0tjWztUgCplE/4GHAgbV9Fats2dmZw90FnBpZALDOJZInujrxGze+//rex6s8tzk2xEUXIZMZvPOKiIUhp65+m1PX2aQwNOjO/v3GJUHdnvjpCk8PXAAq9l8rlyOTE1QimBwaLzIA8CI4vh/iD+dUh+TpWbs4wopJyA9jBUMCRhZLNvXuHG4bXygZc5b2OJ8Az+qMU1LpTcrLa1g7/qQHOhMv4EyoqbluMLFY8RtaeT59GtBmwvvVCkCoLDQazCxvkHRr0f/vTiKE7sG/CQ+rlDxL4DqGJsgcQYJYWYbBaykr1nOBsoxeIUBKFzJY7o8PP9LwBlf7PmKpQFhcT+xyIdOZJFSVDtiqVr+jWwTJm+iE+3WI/M/QYwmhuLcRf8M= + template: + metadata: + name: oidc-bff-config + namespace: workflows diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml new file mode 100644 index 000000000..a7d121aaf --- /dev/null +++ b/charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + creationTimestamp: null + name: postgres-application-passwords + namespace: workflows +spec: + encryptedData: + passwords: AgAaHsA0p6ZAyHb0lUl2rtGkv6OG7f6b6d95MPjsI5sogEAzz0YL8nuSx8x7HHbtqT03dd7MmHV9gawNo0CGhGQjGFwLrtFhI67EcufAE6/5q7hX6DQAxm5/ZTZPvFffOuLMCS/PAJzZAYcBKW0Adhk8qCmcQ+Ps4G4GKcCY6kD4/BuoDvaGodvie2it16ejPHEeZ8cMzfYN+/NMRQ+6q2dmwqb/Gf5kc6HJMbynaSkQotD2OFbnkzvYUdAcjpxLMsw4Ia5kP2Hz11mgwV1LqrGW70nDHFmojN4q/+PR+VrNd7FYN1ZgwoIbIoKPbF/E1chSmwGGU8CqwJxXATS+jYz1m7X5RR2PgL0fFdMHXB5jiXoGdZqTQKyt6okXxvF1fMthmZw5VrZBiTeE9pQnDCZEHq4rAXKuoWDjsrruMGATI/4JPive+snWDgpTEzHa40k+HXIj1/lHqiQfAQaRyLS5a89j+g20berJ8R/q6oYZhVEG4noKnntRcfKeT+DaeOeRoQ5M9Jn3AUfqke3R3sJJvYFTo0mU1F6fXq9YrOJRz3cQzPEGDqladBH8D9KHcl5dKs2PzZaAbpUlvT8YVadVWTtMm46etqBpAOE7rPYRQzhrmRHdRXOrN862p5qyhZLXgIvJASWheVaBbwIGK2PKpFSk1juzkZ9sAOFTkLD7BNJYn3rq6RFPl7CYjQ8ecNOQGGYPRIDDfAmmqHujiarAJXXqvyB8tjeSXqAd50ThkZGf7dO/zRUGAyI8a1KO3wYU + usernames: AgBTq5CHMVyTx6l2Ihqz4EE64Dm7G2wXSAQEnZr+4BA4nwU1bz+1xVNCen8AN7t8iPA5gO+8SyPIXKj9ZhqtjO+ltY2vjvIY2QXEQXOjDozfo+Q9TxgQ3jyKN3mr4hv2OxgVx+Obz8mD0rNPDO0cqI3SwUZQleDV/87dL09leUCIWFnNxHbhaLhuDNdPKTdw7ORSplHmTa35j1x9u5xOiwfOzUYshOYRcccqNzvKsp6Ptj2QWZkqiALn0FIkWC4uZ9KN0eQxv9w/ZLr/ixY5TI7tbBW5oiNYR6iQ0IK2xAOCl4tbTk/S8qkQBVbwxbvKrsNnR2FQR9hs8iimr1HDY1gFt2nt+3qY0Cle88Bngy0Yt/o7J7pZTV1rgr3SzpogcmIu/LCA1wln4OnMlhv/U+oMsoxVL/FssJupjFbX+5UiVzMpYYZ7CTLqiGnn29A+0VCp1bNaTTTYx1R5DGZc9JQj5+XkGCitCicf0GrSRs7nEjk/O/1aILE6CISpvqvXbMncjJysgVr8CdUoKwsdqhleRQ01llmhVj20LYhoGtMPe23DejGIrItlNlphp9dT4Sl0qvLPf3pmOaladabwCF0NXub9q4zpN5sM6p88xISHUIyD0Qh7T7WJ1wk0RBDC+onfZmWK8iZsP4XT2ZpbruwMJWriF9GlH+NSZhzwbym+QOBLV7x8jFebTF8P5lEUVf6oaGIa5dCQHAy0N3H0UzXE1U+XSBvo6eg= + template: + metadata: + creationTimestamp: null + labels: + argocd.argoproj.io/instance: workflows + name: postgres-application-passwords + namespace: workflows + type: Opaque diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml new file mode 100644 index 000000000..7d76405fb --- /dev/null +++ b/charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + creationTimestamp: null + name: postgres-argo-workflows-password + namespace: workflows +spec: + encryptedData: + password: AgABMdb+f+AyfmSgwm9NHvG13yK7Js3krlaH2nWoQAnupq1zZW7fFsmCnna1FW67RDzY0ZPOCc0T7yyWsEzVWuupBQWliRh9FaROQZ21wt6GWeQZD65tf0lqu9pLORwhMbaW8oSTTx/GAY2ojyz1YX0npsYfEdfh32YAEgpfrqZN8GAjdhqQUwGhsrhMIcxS4vilO8pk98Q6G+9hajduPNl766qW+IMyRnK1iZQdSU3i7r4neiLCaMh+cLpdbYfIYwG+LlChGWmHfYIucIH0pMb7bkCWzIdtQRobbcwK+atcD+nAEEl6IicyhEU+b/qHrGjCNvUQ5jq7JFYy6Ri0lKzFSpwVH4MkdzZWUpttsqo3EnKayQB8ZXZH5hTrpspifhhiI0D3s90relTAhn7UNz5fwbRtdTBpevhQzp5IZVuAMuvDdzcISh3LoBe7Vr/UUVHGOMLVyqzGY9z80VO95tJV+iDO2TNpEE3gNl4Gaxm9Dr3zDBmDyo8uKUuLYE38lVzB4EJmgo/vuE8OIdKdZGK905PIGQ6O5AidZbL3nEUvIHXoGrYiE0pZjyF4uVJpu65Dw5A3GDH6W6l5iK/sCTcL9LQdPX7o/AOfUWyNJbD4O6FAau3d1m5gie5kVVT8zzMhVH+BUxwT1JvRTxL3J6nazKlo0Xcoq4UdDai+I/dFg3di7aHo9obyWvcLAYPRMvhY3357PaxOsDAYkvaEbwPoFGTPIPLz8/o= + username: AgCfSEt91Uw44NHBeRVfIZOuu7zVlZFu80R9VifqNnxN2A/ggpIaHVqozXsStTeb/Qkl/axG2feP6hC2ilHVti20XHzDD98tTeo5p5j9yfStudLL/rIYZnNsO12uVUjKDPbOTrxgxtjJkRdDlO3Zd1Aqrsk11xZieeu9RaGBqY1qRVUkZb2bIM9kege/3wL8eTO9jF2ogMEybEtCBoOridBdmLMCPncYHt36NcPXi/8cpJOgj2icEFAQJT6MKlkdigiREMDXLByscJO0EseonIyiLdK/1WgRx/nUUMoqyt7CTqTej41cUZCM9ufjLC8VuM8OCtAHVKu4OOf76ya3wGp2OBf7ajBUQe0NbZ3+ckyrSgodQv92jemKCPkW2GeN2+t+M3/kTn9xQ0lc+TPpRR7JnlbHNYvCXLLtrtGG3AzkeyZJZ4FKBaIL5V5dS6ywSLvMsPlmjci1jfCswsHOE9uCVt456v968cvGFOpOXneHTALc46r/vjvJ58Nrtkayik3glhRsS7kPH26AJ2HhOOu6FwIp//+Emd2W3fw7MEWizu9tNCPJMUm9HrO7I59db74Cb7hZoBpzhNyzi7mfwQJCGCDU/ahlbYSWiknc2EDE0mCNZTIpyTPVYv7gc66yyroZSq4KHnaQl6pKLOCl3pHLa9xP6nuZfGqN5gaf+YCu6Qi05Ktq0IEHqIKNs/AXZE3iXVHzamhyUwFBqwnpDA== + template: + metadata: + creationTimestamp: null + labels: + argocd.argoproj.io/instance: workflows + name: postgres-argo-workflows-password + namespace: workflows + type: Opaque diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml new file mode 100644 index 000000000..d5fb5f767 --- /dev/null +++ b/charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + creationTimestamp: null + name: postgres-auth-service-password + namespace: workflows +spec: + encryptedData: + password: AgDHejDxPArV97Etg07L0oUlMDTIFlluz3cqYfMfJe/MBoPWLN8wxWq/Vpmy/0+LAW5aj9sIPnsXCE0Pfq4tXdr7sLdhNHOA0Efy2m5WLcoyTzbTU4/f/beXIGsabDFVvgEvIrEYIu2TOJj1mTLFmESWbYG4Z822oXdKEdmAE4Zvf8wmSkGLfOoFXYueNBaQ7N2BNIeA1+8pywuHMmoyeTOyxk6J743vRiPqEK940H+BT5bhuZz370FJVeXnKq+SBgsckqVZ42Rp7VW2qW1+j+tAku6AHcRhCxV0KLPjf08oQrzcY60blBvW4AUiwLrSghK88DfswBENQKtYlYO9nt5mV7ZaBD1dnSetCM867fRiSyTXXN0PJAXZjgAqkdQ5W8cBA5wImD0cF+wsZShZyVEO2qYGL5THrUATjHkSF2zGfhLSGHIlJlmsC527Yo2J0SovqjY4g3qTI8VxdugOax7yj/W8y2iwUxjokTvtwplIjM0nXNxwF7KqkbIOgxiW3IdtMyI7PQxTgO69jnch4odnzCgFToE7lOs/uVo1lNH+iU7a0o/o/5ksL8MqjX56zU1BYuGOtq+eGL9B3t7jnN91SkJzO9glRzuo15wRARKMdJ2Et2tqkfw6qQlCVnpvj8r4xApUnsMbvyrR6odP2jg5Sr2mgYnoN2krb6jjJwiBFeC3FZcJVctBUa60ZPpRiftXvUCpjhU4qMaABrk66k2xZZTD346wcMg= + username: AgBRyZIlJrZnf0VtwQE1iqJbwxwcE9d638Ii21F75xCj1eVGne0t1oCysZpi9ZLOjhPYTWZADBW8VwYM6OchzMRcTAO3M4tsALsb2tsf8id9zMl7He1NIeprLeKr3hNQQ4Ktcf+CNrStr/f/b5Ei3Po8aA1Aq3VOiuBd+C+0P/nHJWcEGl0hbw3GEytjILHl7JwjMg40B6j2Diq3Z3o7fry17iJ98V0ta1kyQBpAZdlmPr+mSXpllpl915dhepE86//k9c+2ZIN7+WmLln4MYmznakbcZpiN5QAhuxnJO69G8wYcwSsJdI0B4fOy3iNMc/zNCWLbd3pgmz0h5hvumU1XZ42ftujTvhDb6eagBWPMWr7gguNSjWw6zwgtCPSVt+lzRBEu9MUBAY1TA3Zk5MvMXAYPTlix0vN6lPZweB2u1C/f/GqAV7BzTDMzxj58Fa/r/B1PEkOvgZygZ16TojXOQlkcMT7DfPf9Yf4YWL59i1RBzUvw2lgDB1glZ4GqMcxYHTfTR6j4feQJzmvVh2FgP0kthsxAXhO0a/sZ4EHfxVeN51PKA3BPuFdX56HLAkYvj2Osmuy+fVC8UGsDW9ik5fndzhaqxap/9qzLYUtU2AtEI3tPKvJhpM0QQvFockUgY6J31y1IivOo+gGGS1DCnRVnNDPHXETE2DBidSwBSThTiuV8+7LMrCyoAvaFEBFhENcrbtX5Eb8= + template: + metadata: + creationTimestamp: null + labels: + argocd.argoproj.io/instance: workflows + name: postgres-auth-service-password + namespace: workflows + type: Opaque diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml new file mode 100644 index 000000000..cc0fa322d --- /dev/null +++ b/charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + creationTimestamp: null + name: postgres-initdb-script + namespace: workflows +spec: + encryptedData: + init.sql: AgB4hcgbt4yJhii5v3cJ5WZBuGOcRBS4PaZeT8kjHSc9gNAfxyCPM0EtwBaVZMfE2dinj3nk+2GDsoVsoYaKl8XXz7Ey0xfdPfypLLGmTaAUGFWFRL9ygrJV8T1wZB6rI33erTgO/NQCu35umLYq8xyFkIZolrZEOFP6hHShBMbz51yIjRdwvTVkYItfiEOKmHmHs4psyWvsK+KL58zhB/7PZZ7Twi4+rdBmB+wV0NMy6lpq41mQNz12tLVQUlvM0KKyUApow1FVXuBbeZkKgTSKEgHYOtrmrWwoqAl2qK1hf4B0jRocZAv1WCOcevbTb+IFqRdAUiOHDHc5TnCuSUNiffmTwyRXlvLgvoJLElFUaamsEESgzAS7+qkwzSeyrZ3F+qmeXXCIfnKUL0kzCo9kMgXGqOjJ6gibo4wFSL4QUctv6GT4rAGIqyUyLvrCoU0QhNpPfhZkXQf5FUz/n0wHD1qbisPLEyqsCGcZR45RClrhncza1RLWb/xWhHAsVUTeolrSZXpZOnEYOsjuIF2Gyf8029HMMQMhgguThhBho93MwhA7BUnbSbuMrQlQ+R7TryxlplOsWZfPGBEs1M/YYCVXs4+PRHPvttYps9KHcpvN+WlObE+IIxtVbozVaVEBz26j9xZezC7hFXYTifRXEpgRExfRtNtRIpel/xYpkAoQsBbJ+Xsi23Vrp/uyjU2ogXJoziGHaWs8/YKnvD5bA4AXnNAm3zLokCeXJ1ei3O8iFZ5R2vxXUSvDFC4oOxLMj+nB89xR7/0z7L5BxMe8v7gtOZ1q1qd543LgNvuysSOb8CT24bc3gc9Ueqk8nFZTg+R2L6avDUJuzPXRS0zl8cCfxZ/GEEkzPsVYTY6wTJm3GJ6wnf3Mwyzk+dTBViPhjzj96XMMAqEzWVHKpfQkxjmeUfoRynK7/quQvsWl2tLGZofDHGKAAB6ZdVirGHTqCqqidgVz8QNIz9ECybDJQpilwzWxHUHTCu0YoBidXwjR25BOI0Q= + template: + metadata: + creationTimestamp: null + name: postgres-initdb-script + namespace: workflows diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml new file mode 100644 index 000000000..9d51b149f --- /dev/null +++ b/charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + creationTimestamp: null + name: postgres-passwords + namespace: workflows +spec: + encryptedData: + password: AgBD1UtI2bqrlgkSPQVTOE0L7baaX/42Bq0w9209GiA7FztZkaOxGsOroAW0cCKifbbK9E4BlTPyFu6X1onw8OSowpmZ8bih5amuroYECugw/g669kfh//G7nKi44o26XoI9CajDJUVb+LkXHZFEJ8Xb9xnclxdR4U4klCriIow1cUnCkif2ELa1MMZ+mVvAIdsArIehymNfCpCRZzNu35u38Yf0EYAOCeh5W0LT5cyKp1pql8AGAGbpSSzojJxWpx8N0lA8toeKjOmVegKK2jS7q+4IfF8In2UU8E/DtcMTUbvorYwLPVKtDA7AlHTH8qU1+tosjTHQa5s8U0XvAGKuboiy7vPVDpypMo+tP5LKab9cdFkJumT+PFoIyJkacJnzs2TEzGAAi+PAgr/6yUBgsFejtV0yjFXNbh0vPhVdDQaqt+ylm451bTQo1FxgS6sOFYHnUo4Cj7+0vnMu8f994GZilaqdkY20aRWn/6pg66K1d/koDXB0hDJncx5xsZ1Zgx8Bo1B7rm0v7cyDmFaFEv4BSdcU9XMor98tRMOMQgdHaKBkyz4T/eViwmfoGI/9VA1PaqvO5cEZgkQ6Rn5LqvmkvNanKtrgn+BTsvlximUskQq0NklDl84EUEvieT4OmzNIAWiVTVImZ3/erVQFau7sILc8U+s5H6srGJO45wtFx4r+eKMGC/ZK4Ie128vVWn8e5JFDZ8UAJChyeV4aCzQw1Uw2soQ= + repmgr-password: AgDGDte8on0ZOp1Ts++H8D0ZtVDS6LrTZj6XQ1pdER1WoACEjuzg/VhEmqMBP52Rla1lU6agGbZph65tdS6cbf2c2pUSvTnh2agVncdADMjSZonG1dh5wW0fQj9k0WxB+40gv2iWlW3jsaOhYPSCaI38vSL4yjnTr0IVxTIRDBF3Lst+P4jSTgQxUaHzDy7OtRTsGMJDky/BCDFR4fh4MAJxFCoDLnPPG8FBsVVoPz4UeeOMNdq4Yj4/BH677G1PCbsJGGbbSOPn4zr1Fh0q9pJ4ge+vE82bhoqBkb++v2jYtjyCgicS0Tj+KaA6y87/6RTveOpDyooetomwa3JwVawzPWY2wMFB6NrPGeie97wMiYGTFZzcnVZycqfAp5LuSrWdqx+lvJEg2UOyXXHiT3v4qTJxvsDbONuVkHB/ogYi2o66ZBaAUObzFi5G4LHZg5qzxkTroO3T7OTZTSnqAPoyApHHo/t0uSPAWbv+wyqBaZQJxV4cQ7Eyf3wni7UKIXLK139D7Ah2/BrxCM0l4pL8gmFnCjkGKgJiDgG3C+rQXZc+lbjdw4XaLjdTh/T5fg5q1ve0ZErFIa+ugyoLmU17hFlIIbDKaw3nIQJP/abOkx08lLlAZLNuDhGj/HQR7gzEgiLXYWHpBWgUFYRrlAcF2pnq774QL7mnuHbDTZERu5eiC0TPI1FqpYWqujeIB/RIZw9caAzdB9fPJMvbeYQCIdY4uTbQlrs= + template: + metadata: + creationTimestamp: null + labels: + argocd.argoproj.io/instance: workflows + name: postgres-passwords + namespace: workflows + type: Opaque diff --git a/charts/workflows/staging-values.yaml b/charts/workflows/staging-values.yaml index e9b0f5afc..441057ab4 100644 --- a/charts/workflows/staging-values.yaml +++ b/charts/workflows/staging-values.yaml @@ -19,6 +19,10 @@ oauth2-proxy: - aud emailClaim: email userIDClaim: fedid + extraAudiences: + - workflows-dashboard-staging + - workflows-cluster-staging + - graph ingress: hosts: - argo-workflows.staging.workflows.diamond.ac.uk diff --git a/charts/workflows/templates/_helpers.tpl b/charts/workflows/templates/_helpers.tpl new file mode 100644 index 000000000..55fb510b0 --- /dev/null +++ b/charts/workflows/templates/_helpers.tpl @@ -0,0 +1,28 @@ +{{/* +Create a new password for the argo_workflows user in postgres +*/}} +{{- define "workflows.argoWorkflowsPostgresPassword" }} +{{- $existing := (lookup "v1" "Secret" .Release.Namespace "postgres-argo-workflows-password") }} + {{- if $existing }} + {{- index $existing.data "password" | b64dec }} + {{- else }} + {{- if not (index .Release "argoWorkflowsPostgresPassword" ) -}} + {{- $_ := set .Release "argoWorkflowsPostgresPassword" (randAlphaNum 24) }} + {{- end }} + {{- index .Release "argoWorkflowsPostgresPassword" }} + {{- end }} +{{- end }} +{{/* +Create a new password for the auth_user in postgres +*/}} +{{- define "workflows.authServicePostgresPassword" }} +{{- $existing := (lookup "v1" "Secret" .Release.Namespace "postgres-auth-service-password") }} + {{- if $existing }} + {{- index $existing.data "password" | b64dec }} + {{- else }} + {{- if not (index .Release "authServicePostgresPassword" ) -}} + {{- $_ := set .Release "authServicePostgresPassword" (randAlphaNum 24) }} + {{- end }} + {{- index .Release "authServicePostgresPassword" }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/workflows/values.yaml b/charts/workflows/values.yaml index 313e79987..5310f1e0c 100644 --- a/charts/workflows/values.yaml +++ b/charts/workflows/values.yaml @@ -180,6 +180,10 @@ oauth2-proxy: - aud emailClaim: email userIDClaim: fedid + extraAudiences: + - workflows-dashboard-staging + - workflows-cluster-staging + - graph extraArgs: - --cookie-refresh=55s extraVolumes: diff --git a/examples/conventional-templates/workflow-auth.yaml b/examples/conventional-templates/workflow-auth.yaml new file mode 100644 index 000000000..5220f6fe1 --- /dev/null +++ b/examples/conventional-templates/workflow-auth.yaml @@ -0,0 +1,66 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ClusterWorkflowTemplate +metadata: + name: workflow-of-workflows + labels: + workflows.diamond.ac.uk/science-group: workflows-examples + annotations: + workflows.argoproj.io/title: Workflow Of Workflows +spec: + entrypoint: entry + templates: + - name: entry + dag: + tasks: + - name: start-auth + template: auth + - name: delay + template: wait + dependencies: [start-auth] + - name: conditional-steps-workflow + templateRef: + name: conditional-steps + template: workflow-entry + clusterScope: true + dependencies: [delay] + + - name: wait + script: + image: docker.io/library/bash:5.3 + command: [bash] + source: | + echo "Waiting for initial access token to expire..." + sleep 60 + + - name: auth + daemon: true + retryStrategy: + limit: 10 + container: + image: ghcr.io/diamondlightsource/workflows-auth-daemon:0.1.0 + readinessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 1 + env: + - name: PORT + value: "8080" + - name: AUTH_DOMAIN + value: https://authn.diamond.ac.uk/realms/master + - name: CLIENT_ID + value: workflows-cluster-staging + # value: workflows-cluster + - name: LOG_LEVEL + value: debug + - name: GRAPH_URL + value: https://staging.workflows.diamond.ac.uk/graphql + # value: https://workflows.diamond.ac.uk/graphql + - name: TOKEN + valueFrom: + secretKeyRef: + name: token + key: token + args: + - serve diff --git a/examples/conventional-templates/workflow-of-workflows.yaml b/examples/conventional-templates/workflow-of-workflows.yaml new file mode 100644 index 000000000..fa46aee55 --- /dev/null +++ b/examples/conventional-templates/workflow-of-workflows.yaml @@ -0,0 +1,74 @@ +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + name: workflow-of-workflows-1 + labels: + workflows.diamond.ac.uk/science-group: workflows-examples + annotations: + workflows.argoproj.io/title: Workflow Of Workflows +spec: + entrypoint: entry + templates: + - name: entry + steps: + - - name: auth + template: auth + + - - name: test + template: curl + arguments: + parameters: + - name: cmd + value: | + curl --request POST http://{{steps.auth.ip}}:6000 -H "Content-Type: application/json" -d '{"query": "mutation{ submitWorkflowTemplate(name: \"conditional-steps\", visit: {proposalCode: \"bi\", proposalNumber: 22491, number: 1}, parameters: {}){ name } }" }' + + - name: auth + daemon: true + retryStrategy: + limit: 10 + inputs: + artifacts: + - name: auth-config + path: /etc/workflows-auth-daemon/config.yaml + raw: + data: | + client_id: "workflows-dashboard-staging" + client_secret: "" + oidc_provider_url: "https://authn.diamond.ac.uk/realms/master" + port: 6000 + postgres_user: "auth_user" + postgres_password: "redacted" + postgres_database: "auth_service" + postgres_hostname: "workflows-postgresql-ha-pgpool.workflows.svc.cluster.local" + postgres_port: 5432 + encryption_public_key: "redacted" + encryption_private_key: "redacted" + graph_url: "https://staging.workflows.diamond.ac.uk/graphql" + + container: + image: ghcr.io/diamondlightsource/workflows-auth-daemon@sha256:728e9b59d3e6734c7ffc30cfa0dc73057268c13875441b4f2d2188b543834c41 + readinessProbe: + httpGet: + path: /healthz + port: 6000 + initialDelaySeconds: 5 + periodSeconds: 1 + env: + - name: WORKFLOWS_AUTH_DAEMON_CONFIG + value: /etc/workflows-auth-daemon/config.yaml + - name: WORKFLOWS_AUTH_DAEMON_SUBJECT + value: d4cd0e39-c80a-434d-81d2-0ed81be969e2 + - name: RUST_BACKTRACE + value: "1" + args: + - serve + + - name: curl + inputs: + parameters: + - name: cmd + container: + image: curlimages/curl:8.15.0 + command: ["/bin/sh", "-c"] + args: ["{{inputs.parameters.cmd}}"] + From 0745071fc6eb1b10e653c0bf70d0535d0d20fdab Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Wed, 28 Jan 2026 09:02:23 +0000 Subject: [PATCH 02/20] feat(backend): add logout function and routes --- backend/oidc-bff/src/database.rs | 14 ++++++++++++++ backend/oidc-bff/src/main.rs | 29 ++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/backend/oidc-bff/src/database.rs b/backend/oidc-bff/src/database.rs index 3bf6da87b..cfe20faf3 100644 --- a/backend/oidc-bff/src/database.rs +++ b/backend/oidc-bff/src/database.rs @@ -3,6 +3,7 @@ use chrono::{DateTime, Duration, FixedOffset, Utc}; use crate::{Result, auth_session_data::TokenSessionData}; use sea_orm::*; use oidc_bff::entity; +use openidconnect::SubjectIdentifier; pub async fn migrate_database(connection: &DatabaseConnection) -> Result<()> { use migration::{Migrator, MigratorTrait}; @@ -11,6 +12,19 @@ pub async fn migrate_database(connection: &DatabaseConnection) -> Result<()> { Ok(()) } +/// Delete a user's token from the database by subject identifier. +/// This is called during logout to revoke workflow access. +pub async fn delete_token_from_database( + connection: &DatabaseConnection, + subject: &SubjectIdentifier, +) -> Result<()> { + entity::oidc_tokens::Entity::delete_many() + .filter(entity::oidc_tokens::Column::Subject.eq(subject.as_str())) + .exec(connection) + .await?; + Ok(()) +} + pub async fn write_token_to_database( connection: &DatabaseConnection, token: &TokenSessionData, diff --git a/backend/oidc-bff/src/main.rs b/backend/oidc-bff/src/main.rs index 1faacd719..b7a68991f 100644 --- a/backend/oidc-bff/src/main.rs +++ b/backend/oidc-bff/src/main.rs @@ -22,6 +22,7 @@ type Result = std::result::Result; use axum::{ Json, Router, extract::State, + http::StatusCode, middleware, response::IntoResponse, routing::{get, post}, @@ -35,6 +36,7 @@ mod inject_token_from_session; #[command(author, version, about)] struct Args { /// Path to config file (JSON or YAML) + //TODO: Change this from env variable to hardcoded #[arg( short, long, @@ -98,7 +100,32 @@ async fn serve(router: Router, port: u16) -> Result<()> { Ok(()) } -async fn logout() {} +/// Logout handler that: +/// 1. Retrieves the user's token from the session (to get subject ID) +/// 2. Deletes the token from the database (so workflows can't use it) +/// 3. Clears the session (so browser requests are no longer authenticated) +async fn logout( + State(state): State>, + session: Session, +) -> Result { + // Get the token data to find the subject for database deletion + let token_session_data: Option = + session.get(TokenSessionData::SESSION_KEY).await?; + + // If we have token data, delete it from the database + if let Some(token_data) = token_session_data { + database::delete_token_from_database( + &state.database_connection, + &token_data.subject, + ) + .await?; + } + + // Clear the entire session (removes both login and token data) + session.flush().await?; + + Ok(axum::http::StatusCode::OK) +} async fn debug(State(state): State>, session: Session) -> Result { let auth_session_data: Option = From d412913ebbd8bf54f00a3a30db4343a15301080a Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Wed, 18 Feb 2026 14:30:34 +0000 Subject: [PATCH 03/20] feat(backend): fixed oidc-bff devcontainer --- backend/oidc-bff/.devcontainer/devcontainer.json | 8 ++++++-- backend/oidc-bff/.devcontainer/docker-compose.yml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/oidc-bff/.devcontainer/devcontainer.json b/backend/oidc-bff/.devcontainer/devcontainer.json index 5ba89e0c5..7937ba1c8 100644 --- a/backend/oidc-bff/.devcontainer/devcontainer.json +++ b/backend/oidc-bff/.devcontainer/devcontainer.json @@ -4,13 +4,17 @@ "name": "Rust and PostgreSQL", "dockerComposeFile": "docker-compose.yml", "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "workspaceFolder": "/workspace", + + // Run as vscode user and sync UID with host user for proper file permissions + "remoteUser": "vscode", + "updateRemoteUserUID": true, // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [5432], + "forwardPorts": [5432], // Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "cargo install sea-orm-cli" diff --git a/backend/oidc-bff/.devcontainer/docker-compose.yml b/backend/oidc-bff/.devcontainer/docker-compose.yml index 5c16f9cfe..9de487c90 100644 --- a/backend/oidc-bff/.devcontainer/docker-compose.yml +++ b/backend/oidc-bff/.devcontainer/docker-compose.yml @@ -13,7 +13,7 @@ services: - .env volumes: - - ../..:/workspaces:cached + - ../../..:/workspace:cached # Overrides default command so things don't shut down after the process ends. command: sleep infinity From 270a32bd2a9778c52f0526f019aac00f33aa8bc8 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Thu, 12 Mar 2026 09:53:33 +0000 Subject: [PATCH 04/20] fix(backend): removed duplicate code --- backend/auth-daemon/src/database.rs | 3 +- backend/auth-daemon/src/inject_token.rs | 17 +-- backend/auth-daemon/src/main.rs | 7 +- backend/auth-daemon/src/state.rs | 44 +++---- .../src/m20220101_000001_create_table.rs | 2 +- backend/oidc-bff/src/auth_proxy.rs | 69 ----------- backend/oidc-bff/src/auth_session_data.rs | 5 +- backend/oidc-bff/src/callback.rs | 5 +- backend/oidc-bff/src/config.rs | 1 - backend/oidc-bff/src/counter.rs | 29 ----- backend/oidc-bff/src/inject_token.rs | 113 ------------------ .../oidc-bff/src/inject_token_from_session.rs | 12 +- backend/oidc-bff/src/login.rs | 5 +- backend/oidc-bff/src/main.rs | 34 ++---- backend/oidc-bff/src/state.rs | 5 +- 15 files changed, 59 insertions(+), 292 deletions(-) delete mode 100644 backend/oidc-bff/src/auth_proxy.rs delete mode 100644 backend/oidc-bff/src/counter.rs delete mode 100644 backend/oidc-bff/src/inject_token.rs diff --git a/backend/auth-daemon/src/database.rs b/backend/auth-daemon/src/database.rs index bfcd3dc22..b191bf1ff 100644 --- a/backend/auth-daemon/src/database.rs +++ b/backend/auth-daemon/src/database.rs @@ -1,11 +1,10 @@ use chrono::{DateTime, Duration, FixedOffset, Utc}; use oauth2::RefreshToken; use openidconnect::{IssuerUrl, SubjectIdentifier}; -use sea_orm::{ActiveModelTrait, DatabaseConnection}; +use sea_orm::DatabaseConnection; use crate::{Result, state::TokenData}; use sea_orm::*; use oidc_bff::entity; -use oidc_bff::entity::oidc_tokens::ActiveModel; pub async fn write_token_to_database( connection: &DatabaseConnection, diff --git a/backend/auth-daemon/src/inject_token.rs b/backend/auth-daemon/src/inject_token.rs index 63fee226d..852fe25a2 100644 --- a/backend/auth-daemon/src/inject_token.rs +++ b/backend/auth-daemon/src/inject_token.rs @@ -1,10 +1,5 @@ use crate::{database::write_token_to_database, state::{RouterState, TokenData}}; use http_body_util::BodyExt; -use openidconnect::{ - ClientId, ClientSecret, IssuerUrl, TokenResponse, - core::{CoreClient, CoreProviderMetadata}, - reqwest, -}; use serde_json::Value; use std::sync::Arc; use axum::response::IntoResponse; @@ -12,7 +7,7 @@ use axum::response::IntoResponse; use axum::{ body::Body, extract::{Request, State}, - http::{self, HeaderValue, StatusCode}, + http::{self, HeaderValue}, middleware, response::Response, }; @@ -26,7 +21,7 @@ pub async fn inject_token( let token: Option = state.token.read().await.clone(); if let Some(mut token) = token { println!("Injecting token"); - if (token.access_token_is_expired()) { + if token.access_token_is_expired() { println!("Access token is expired, refreshing"); token = refresh_token_and_write_to_database(&state, &token).await?; } @@ -77,10 +72,10 @@ async fn response_as_json(response: Response) -> Result { Ok(json) } -async fn set_token(state: &RouterState, new_token: TokenData) { - let mut guard = state.token.write().await; - *guard = Some(new_token); -} +// async fn set_token(state: &RouterState, new_token: TokenData) { +// let mut guard = state.token.write().await; +// *guard = Some(new_token); +// } async fn clone_request(req: Request) -> Result<(Request, Request)> { // TODO: an inefficient method of cloning a request, improve this diff --git a/backend/auth-daemon/src/main.rs b/backend/auth-daemon/src/main.rs index 86ed0c2e1..ab31b911a 100644 --- a/backend/auth-daemon/src/main.rs +++ b/backend/auth-daemon/src/main.rs @@ -4,7 +4,6 @@ mod healthcheck; use healthcheck::healthcheck; use openidconnect::SubjectIdentifier; -use serde::{Deserialize, Serialize}; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -13,7 +12,7 @@ use std::{ }; use axum::{ - Router, http::Method, middleware, routing::{get, post} + Router, http::Method, middleware, routing::get, }; use clap::Parser; use regex::Regex; @@ -22,7 +21,6 @@ use tokio::signal::unix::{SignalKind, signal}; use tower_http::cors::{AllowOrigin, CorsLayer}; use tracing::{debug, info}; use tracing_subscriber::EnvFilter; -use url::Url; use crate::{config::Config, state::RouterState}; mod config; @@ -154,11 +152,10 @@ mod tests { use testcontainers::core::wait::HttpWaitStrategy; use testcontainers::{GenericImage, ImageExt}; use testcontainers::{ - core::{IntoContainerPort, WaitFor}, + core::WaitFor, runners::AsyncRunner, }; - use tokio::time::sleep; use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use crate::{config::Config, state::RouterState}; diff --git a/backend/auth-daemon/src/state.rs b/backend/auth-daemon/src/state.rs index bc60d5ad9..6353889d5 100644 --- a/backend/auth-daemon/src/state.rs +++ b/backend/auth-daemon/src/state.rs @@ -116,28 +116,28 @@ impl TokenData { } } - pub fn from_token_response( - token_response: &T, - issuer: IssuerUrl, - subject: SubjectIdentifier, - ) -> Result { - let access_token = token_response.access_token().clone(); - let refresh_token = token_response - .refresh_token() - .ok_or_else(|| anyhow!("Token Response did not return a refresh token"))? - .clone(); - let access_token_expires_at = Utc::now() - + token_response - .expires_in() - .unwrap_or_else(|| Duration::from_secs(60)); - Ok(Self::new( - issuer, - subject, - Some(access_token), - access_token_expires_at, - refresh_token, - )) - } + // pub fn from_token_response( + // token_response: &T, + // issuer: IssuerUrl, + // subject: SubjectIdentifier, + // ) -> Result { + // let access_token = token_response.access_token().clone(); + // let refresh_token = token_response + // .refresh_token() + // .ok_or_else(|| anyhow!("Token Response did not return a refresh token"))? + // .clone(); + // let access_token_expires_at = Utc::now() + // + token_response + // .expires_in() + // .unwrap_or_else(|| Duration::from_secs(60)); + // Ok(Self::new( + // issuer, + // subject, + // Some(access_token), + // access_token_expires_at, + // refresh_token, + // )) + // } pub fn update_tokens_mut(&mut self, token_response: &T) { let access_token = token_response.access_token().clone(); diff --git a/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs b/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs index c47c5dbbb..3891ba5a2 100644 --- a/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs +++ b/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs @@ -1,4 +1,4 @@ -use sea_orm_migration::{prelude::*, schema::*}; +use sea_orm_migration::prelude::*; #[derive(DeriveMigrationName)] pub struct Migration; diff --git a/backend/oidc-bff/src/auth_proxy.rs b/backend/oidc-bff/src/auth_proxy.rs deleted file mode 100644 index 155f74bbd..000000000 --- a/backend/oidc-bff/src/auth_proxy.rs +++ /dev/null @@ -1,69 +0,0 @@ -#[derive(Parser, Debug)] -#[command(author, version, about)] -struct Args { - /// Path to config file (JSON or YAML) - #[arg( - short, - long, - env = "WORKFLOWS_AUTH_PROXY_CONFIG", - default_value = "config.yaml" - )] - config: String, -} - - -#[tokio::main] -async fn main() -> Result<()> { - dotenvy::dotenv().ok(); - let args: Args = Args::try_parse()?; - let config = Config::from_file(args.config)?; - let port = config.port; - let appstate = Arc::new(AppState::new(config).await?); - - rustls::crypto::ring::default_provider() - .install_default() - .expect("Failed to install rust TLS cryptography"); - - let router = create_router(appstate); - serve(router, port).await -} - -fn create_router(state: Arc) -> Router { - let proxy: Router<()> = - ReverseProxy::new("/", "https://staging.workflows.diamond.ac.uk/graphql").into(); - let proxy = proxy; - - Router::new() - .nest_service("/api", proxy) - .layer(middleware::from_fn_with_state( - state.clone(), - inject_token_from_session::inject_token_from_session, - )) - .route("/healthcheck", get(healthcheck::healthcheck)) - .layer(session_layer) - .with_state(state) -} - -async fn serve(router: Router, port: u16) -> Result<()> { - let listener = - tokio::net::TcpListener::bind(SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port)).await?; - let service = router.into_make_service(); - axum::serve(listener, service).await?; - Ok(()) -} - -async fn logout() {} - -async fn debug(State(state): State>, session: Session) -> Result { - let auth_session_data: Option = - session.get(LoginSessionData::SESSION_KEY).await?; - - let token_session_data: Option = - session.get(TokenSessionData::SESSION_KEY).await?; - - Ok(Json(( - state.config.clone(), - auth_session_data, - token_session_data, - ))) -} diff --git a/backend/oidc-bff/src/auth_session_data.rs b/backend/oidc-bff/src/auth_session_data.rs index 62f9aff45..a3efc4a7b 100644 --- a/backend/oidc-bff/src/auth_session_data.rs +++ b/backend/oidc-bff/src/auth_session_data.rs @@ -4,9 +4,8 @@ use crate::Result; use anyhow::anyhow; use chrono::{DateTime, Utc}; use openidconnect::{ - AccessToken, CsrfToken, EmptyAdditionalClaims, IssuerUrl, Nonce, PkceCodeVerifier, - RefreshToken, SubjectIdentifier, TokenResponse, - core::{CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm}, + AccessToken, CsrfToken, IssuerUrl, Nonce, PkceCodeVerifier, + RefreshToken, SubjectIdentifier, }; use serde::{Deserialize, Serialize}; diff --git a/backend/oidc-bff/src/callback.rs b/backend/oidc-bff/src/callback.rs index 0ef31f138..c3b405c44 100644 --- a/backend/oidc-bff/src/callback.rs +++ b/backend/oidc-bff/src/callback.rs @@ -3,10 +3,9 @@ use std::sync::Arc; use axum::debug_handler; use axum::extract::{Query, State}; -use openidconnect::core::{CoreClient, CoreProviderMetadata}; use openidconnect::{ - AccessTokenHash, AuthorizationCode, ClientId, ClientSecret, CsrfToken, IssuerUrl, - OAuth2TokenResponse, RedirectUrl, TokenResponse, reqwest, + AccessTokenHash, AuthorizationCode,CsrfToken, + OAuth2TokenResponse, RedirectUrl, TokenResponse, }; use serde::{Deserialize, Serialize}; use tower_sessions::Session; diff --git a/backend/oidc-bff/src/config.rs b/backend/oidc-bff/src/config.rs index 2b7e63bb5..f2c58a390 100644 --- a/backend/oidc-bff/src/config.rs +++ b/backend/oidc-bff/src/config.rs @@ -1,7 +1,6 @@ use std::path::Path; use crate::Result; -use anyhow::anyhow; use serde::Deserialize; use serde::Serialize; diff --git a/backend/oidc-bff/src/counter.rs b/backend/oidc-bff/src/counter.rs deleted file mode 100644 index 16886ff5a..000000000 --- a/backend/oidc-bff/src/counter.rs +++ /dev/null @@ -1,29 +0,0 @@ -use axum::response::IntoResponse; -use serde::{Deserialize, Serialize}; -use tower_sessions::Session; - -use crate::auth_session_data::LoginSessionData; - -const COUNTER_KEY: &str = "counter"; - -#[derive(Default, Deserialize, Serialize)] -struct Counter(usize); - -pub async fn counter_write(session: Session) -> impl IntoResponse { - let counter: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default(); - let old = counter.0; - session.insert(COUNTER_KEY, counter.0 + 1).await.unwrap(); - let new: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default(); - format!("Current count: {}\nNew count: {}", old, new.0) -} - -pub async fn counter_read(session: Session) -> impl IntoResponse { - let counter: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default(); - let auth_session_data = session - .get::(LoginSessionData::SESSION_KEY) - .await; - format!( - "Reading current count: {}, auth_session_data={:?}", - counter.0, auth_session_data - ) -} diff --git a/backend/oidc-bff/src/inject_token.rs b/backend/oidc-bff/src/inject_token.rs deleted file mode 100644 index a919f526f..000000000 --- a/backend/oidc-bff/src/inject_token.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::{database::write_token_to_database, state::AppState}; -use openidconnect::{ - ClientId, ClientSecret, IssuerUrl, TokenResponse, - core::{CoreClient, CoreProviderMetadata}, - reqwest, -}; -use std::sync::Arc; -use tower_sessions::Session; - -use axum::{ - body::Body, - extract::{Request, State}, - http::{self, HeaderValue, StatusCode}, - middleware, -}; - -use crate::Result; - -use crate::auth_session_data::TokenSessionData; - -pub async fn inject_token_from_session( - State(state): State>, - session: Session, - req: Request, - next: middleware::Next, -) -> Result { - inject_token(state, session, req, next).await -} - -trait TokenStore { - async fn get(&self) -> Result>; - async fn insert(&self, token: TokenSessionData) -> Result<()>; -} - -impl TokenStore for Session { - async fn get(&self) -> Result> { - Ok(self.get(TokenSessionData::SESSION_KEY).await?) - } - - async fn insert(&self, token: TokenSessionData) -> Result<()> { - Ok(self - .insert(TokenSessionData::SESSION_KEY, token.clone()) - .await?) - } -} - -async fn inject_token( - state: State>, - store: impl TokenStore, - req: Request, - next: middleware::Next, -) -> Result { -// Read token from session - let token: Option = store.get().await?; - if let Some(mut token) = token { - if (token.access_token_is_expired()) { - token = refresh_token_and_update_session(&state, &token, &store).await?; - } - let mut req = clone_request(req).await?; - prepare_headers(&mut req.0, &token); - let response = next.clone().run(req.0).await; - if response.status() == StatusCode::UNAUTHORIZED { - token = refresh_token_and_update_session(&state, &token, &store).await?; - prepare_headers(&mut req.1, &token); - Ok(next.run(req.1).await) - } else { - Ok(response) - } - } else { - Ok(next.run(req).await) - } -} - -async fn clone_request(req: Request) -> Result<(Request, Request)> { - // TODO: an inefficient method of cloning a request, improve this - let (parts, body) = req.into_parts(); - let bytes = http_body_util::BodyExt::collect(body).await?.to_bytes(); - let req1 = Request::from_parts(parts.clone(), Body::from(bytes.clone())); - let req2 = Request::from_parts(parts, Body::from(bytes)); - Ok((req1, req2)) -} - -fn prepare_headers(req: &mut Request, token: &TokenSessionData) { - let value = format!("Bearer {}", token.access_token.secret()); - req.headers_mut().insert( - http::header::AUTHORIZATION, - HeaderValue::from_str(&value).unwrap(), - ); - req.headers_mut().remove(http::header::COOKIE); -} - -async fn refresh_token_and_update_session( - state: &AppState, - token: &TokenSessionData, - session: &impl TokenStore, -) -> Result { - let token = refresh_token(state, token).await?; - write_token_to_database(&state.database_connection, &token, &state.public_key).await?; - session - .insert(token.clone()) - .await?; - Ok(token) -} - -async fn refresh_token(state: &AppState, token: &TokenSessionData) -> Result { - let token_response = state - .oidc_client - .exchange_refresh_token(&token.refresh_token)? - .request_async(&state.http_client) - .await?; - let token = token.update_tokens(&token_response); - Ok(token) -} diff --git a/backend/oidc-bff/src/inject_token_from_session.rs b/backend/oidc-bff/src/inject_token_from_session.rs index 1efec50ef..2a1a9bc3a 100644 --- a/backend/oidc-bff/src/inject_token_from_session.rs +++ b/backend/oidc-bff/src/inject_token_from_session.rs @@ -1,9 +1,9 @@ use crate::{database::write_token_to_database, state::AppState}; -use openidconnect::{ - ClientId, ClientSecret, IssuerUrl, TokenResponse, - core::{CoreClient, CoreProviderMetadata}, - reqwest, -}; +// use openidconnect::{ +// ClientId, ClientSecret, IssuerUrl, TokenResponse, +// core::{CoreClient, CoreProviderMetadata}, +// reqwest, +// }; use std::sync::Arc; use tower_sessions::Session; @@ -27,7 +27,7 @@ pub async fn inject_token_from_session( // Read token from session let token: Option = session.get(TokenSessionData::SESSION_KEY).await?; if let Some(mut token) = token { - if (token.access_token_is_expired()) { + if token.access_token_is_expired() { token = refresh_token_and_update_session(&state, &token, &session).await?; } let mut req = clone_request(req).await?; diff --git a/backend/oidc-bff/src/login.rs b/backend/oidc-bff/src/login.rs index 703866c83..7ed99fb98 100644 --- a/backend/oidc-bff/src/login.rs +++ b/backend/oidc-bff/src/login.rs @@ -2,10 +2,9 @@ use std::sync::Arc; use axum::extract::State; use axum::response::Redirect; -use openidconnect::core::{CoreAuthenticationFlow, CoreClient, CoreProviderMetadata}; -use openidconnect::reqwest; +use openidconnect::core::CoreAuthenticationFlow; use openidconnect::{ - ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce, PkceCodeChallenge, RedirectUrl, Scope, + CsrfToken, Nonce, PkceCodeChallenge, RedirectUrl, Scope, }; use tower_sessions::Session; diff --git a/backend/oidc-bff/src/main.rs b/backend/oidc-bff/src/main.rs index b7a68991f..d302328fb 100644 --- a/backend/oidc-bff/src/main.rs +++ b/backend/oidc-bff/src/main.rs @@ -4,7 +4,6 @@ mod login; mod auth_session_data; mod state; mod callback; -mod counter; mod database; mod error; @@ -12,24 +11,23 @@ use clap::Parser; use config::Config; use tower_sessions::{MemoryStore, Session, SessionManagerLayer}; use std::{ - net::{Ipv4Addr, SocketAddr}, - sync::Arc, + net::{Ipv4Addr, SocketAddr}, process, sync::Arc, }; use state::AppState; type Result = std::result::Result; use axum::{ - Json, Router, + Router, extract::State, - http::StatusCode, middleware, response::IntoResponse, routing::{get, post}, }; use axum_reverse_proxy::ReverseProxy; +use tokio::signal::unix::{signal, Signal, SignalKind}; -use crate::auth_session_data::{LoginSessionData, TokenSessionData}; +use crate::auth_session_data::TokenSessionData; mod inject_token_from_session; #[derive(Parser, Debug)] @@ -82,8 +80,6 @@ fn create_router(state: Arc) -> Router { inject_token_from_session::inject_token_from_session, )) .route("/auth/login", get(login::login)) - .route("/read", get(counter::counter_read)) - .route("/write", get(counter::counter_write)) .route("/auth/callback", get(callback::callback)) .route("/auth/logout", post(logout)) // .route("/debug", get(debug)) @@ -96,7 +92,9 @@ async fn serve(router: Router, port: u16) -> Result<()> { let listener = tokio::net::TcpListener::bind(SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port)).await?; let service = router.into_make_service(); - axum::serve(listener, service).await?; + axum::serve(listener, service) + .with_graceful_shutdown(shutdown_signal()) + .await?; Ok(()) } @@ -127,16 +125,10 @@ async fn logout( Ok(axum::http::StatusCode::OK) } -async fn debug(State(state): State>, session: Session) -> Result { - let auth_session_data: Option = - session.get(LoginSessionData::SESSION_KEY).await?; - - let token_session_data: Option = - session.get(TokenSessionData::SESSION_KEY).await?; - - Ok(Json(( - state.config.clone(), - auth_session_data, - token_session_data, - ))) +async fn shutdown_signal() { + let mut sigterm: Signal = signal(SignalKind::terminate()).expect("Failed to listen for SIGTERM"); + sigterm.recv().await; + println!("Shutting Down"); + process::exit(0); } + diff --git a/backend/oidc-bff/src/state.rs b/backend/oidc-bff/src/state.rs index 3143ee68f..d91d22719 100644 --- a/backend/oidc-bff/src/state.rs +++ b/backend/oidc-bff/src/state.rs @@ -7,11 +7,10 @@ use openidconnect::IssuerUrl; use openidconnect::core::{CoreClient, CoreProviderMetadata}; use sea_orm::Database; use sea_orm::DatabaseConnection; -use serde::{Deserialize, Serialize}; use sodiumoxide::crypto::box_::PublicKey; #[derive(Debug, Clone)] pub struct AppState { - pub config: Config, + // pub config: Config, pub http_client: reqwest::Client, pub oidc_client: openidconnect::core::CoreClient< EndpointSet, @@ -63,7 +62,7 @@ impl AppState { .ok_or(anyhow!("Invalid public key"))?; Ok(AppState { - config, + // config, http_client, oidc_client, database_connection, From 08d103273342cf017e83c1fed4f1c3ea03ea7cb8 Mon Sep 17 00:00:00 2001 From: David Hadley Date: Mon, 2 Feb 2026 13:02:46 +0000 Subject: [PATCH 05/20] fix(charts): remove secret duplication --- .../charts/secrets/templates/postgres.yaml | 53 ++----------- charts/workflows-cluster/staging-values.yaml | 2 - ...secret-postgres-application-passwords.yaml | 19 ----- ...cret-postgres-argo-workflows-password.yaml | 19 ----- ...secret-postgres-auth-service-password.yaml | 19 ----- .../sealed-secret-postgres-initdb-script.yaml | 15 ---- .../sealed-secret-postgres-passwords.yaml | 19 ----- charts/workflows-cluster/values.yaml | 3 +- .../templates/postgres-secrets-policy.yaml | 78 +++++++++++++++++++ .../chainsaw-test.yaml | 56 +++++++++++++ 10 files changed, 141 insertions(+), 142 deletions(-) delete mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml delete mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml delete mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml delete mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml delete mode 100644 charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml create mode 100644 charts/workflows/templates/postgres-secrets-policy.yaml create mode 100644 charts/workflows/test-policy/generate-postgres-secrets/chainsaw-test.yaml diff --git a/charts/workflows-cluster/charts/secrets/templates/postgres.yaml b/charts/workflows-cluster/charts/secrets/templates/postgres.yaml index 10829e6fc..40bed9883 100644 --- a/charts/workflows-cluster/charts/secrets/templates/postgres.yaml +++ b/charts/workflows-cluster/charts/secrets/templates/postgres.yaml @@ -19,21 +19,6 @@ spec: --- apiVersion: bitnami.com/v1alpha1 kind: SealedSecret -metadata: - name: postgres-application-passwords - namespace: workflows -spec: - encryptedData: - passwords: AgBOXtZFarHamd7CeDEGIUoRmWf84aV8H7JgT63LCQFJ0v5y0VpRbPRhO6Tg7o3odbLr0QYb07DM9vXr4TeE7TdB+A0ipMnebpDB9yE/NIqd611vfhQhJUE4bBSTMGOaf7smwXnaBIGmNxUZFwNi3qWQyn3SxGEv4Vs7GM3WRe1iOXR7Tb/JfqPBWk7j/Cg4hf/VayZCNuDaJCZaUguYuhNMzX1w3HZwhfhK7ghbo0ICJibWxc86KZz1rsWtGrM0bRyrAWJtX7lrxkVH27xxeX2JJq1Q7VlA3npXGKM0HvP1JzVt7yH2vUNN4fDHl95E1VJYyl5s+bFLGMJpvKw5IGO+y7ZhyV5VY+BxQhu74RDrBZKmLhIJGMSKq3aybSS/AoZyO0byOywELba9n2FjA6bdoU0zaS3gvqHFmiruyY2tfpvGkwcuZCpt4DlIYixpWL5if+EJN17HzX/0+d3GjLYKbyNh3dJX2IiEX9W54MUA9frGY5ebYOjSihZoLMnfZ6fu6wPKkKbFMsXNOD2JW+vAnGdVzcD58jWEtXhepajmyf6QZdxwf/71eLm19lxiyACJheq7k6nHfgZqqWVtAs38sECK3bWtB7gj5G1wqoibzEh6lQFzEXtLeh5dPX0EZd3UMKYAvozNcpbLf4EaIq/nrV9bjFrKF2ON35BjJXVktHgVcQ1ug4wyG8tI0T6xKD3WlQ+2vVg80HqPY9gh91BkDXnzXYdr/qI= - usernames: AgDLzslNMyB760Z9D7vcjdVlWMaCc7M3rDlIM4QoAYWjd80Z5S+hGEAwlVSJyvfyi1+iq7PPKtmXXnWq/IQtkAJfUoykp0OO6K82IJsjDyhZLxyb5aSJGcEBHmiXsxCVQjzXSVyw54TW86XuBkLxK3MD2HrkwdGpCu/zcgYl88R7AOEtYC2cNoLHuBDYB/mAq/5BawRLTWI2fh030bYTeg8UAToBR9PvNf4+fIFap9i4zwLs/hw2Q1HJQDKL8Nq9qG5tcpAdwsBwjLt2zwF7lbFNrHyEn6onjvFOFyeysc/r7rBZJ9Kb9oLOxb8PBC1kLwOs9/d0a8wdnjpmH5YKXXjrCYOoduHxgA/t0ZmWlldF7cjAJjTzNpr6bHE6xWEIvcUS96XOY+3Q+r829D0UitOgbEw7tirNAzuyndTprqnaSYFPZThHBT478fQ6/DYZ1e4ak7ISdFc9f6xbbHeXv/vuKScYWgI3PgI1nt8f1xZtbUE5V9iWw5KXxPka5vH85UYN/4xjdwkCs2DZpWogbio2blbHRzl9TwXuA2eWgLTF+0ep99CIH0erg48UD+a/zM0GrHBcM/Oa/FqTDSdHhfr/4WRQb2AgdxfjcrlGUjIz15O7UwUQUAtZCGMPS+1feyM7TyTYEBt3IDIzo+c+nwp7ySgl3LOIZST5xNoqOpdd0ZtGPoyZYssGysXKArqng9Z3HgZ+wMjeIMXwya2qAg== - template: - metadata: - name: postgres-application-passwords - namespace: workflows - type: Opaque ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret metadata: name: postgres-argo-workflows-password namespace: workflows @@ -46,20 +31,6 @@ spec: name: postgres-argo-workflows-password namespace: workflows type: Opaque ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret -metadata: - name: postgres-initdb-script - namespace: workflows -spec: - encryptedData: - init.sql: AgDMErBkqZWkq8ZF3SEN4kikTy5zpeItfyXsr6232UtYA20beCOIRq4RIkTn7dE1uXKGtI2mIatZmmxw7H5zYZd9F1eic5QxNi8tMMHcWYkwzJxIw1t59IE9yyNoP38EVJqPglD+ep7JBPU3QCfqlFN5PUp660mL/iTgHNQHNTYd88/zbS8xVmlKJVBFPTGk/1nvWCzhJ5ffvPIG+faJj1DUDO3WctBQ8GKoIngAnjjU8PlU18OKMDH41NIUIgQq3UweNp0vf0DXMDJphmRQ4pNp3TAAor9SOFwvp0jhX499uJPedeMQ6ch8jjmvwj4jlZUa7ZtauRdkMFbz0n8CyxMRxvqJKQW8YxONnhz4ugbx7Ww4TZxFm+H7CQ+2LRES3OlrSn8y094+aLfLRvf83p8Vhuxy7s42Ap+pzwvw0hL8GFS+rNr/8l26B+alc/ztCkaLbZ7KiCtDmYQvj4ZFCV0DqpdhJEiL0AiVPIUcEwEJwuH5IWLflBsQB01gGssDCIcO3ZcdnRetgv1gmltEslO+g0CN+sNoiZ8nRW8FZ0ykyhL74oiG1wS+aaS4r2aZ9RDBAMrQgM3Dr9IbhUZJWwsMab3KmKCgs69PYHvv9Kdk1mWWvE/CIITE0cFjJPEljsm447sEoyVwTxK8ON460aoOcGCzl2AU7qORrrGQncw82xxf6JynVGrmuFidpuBp3nfeLs8TbD8QbQFntYAzWZgFthtP46qvYK4p62ju5TmvN1jY82GxisuHiOjpQ288axrStXojVTasAOZhqOZLLS9SEZlc8KmGZ9E3sNqyTSTiFIRCrRnC5A1/baLjXo0Z4SQh2LtaGKpwlMCUPpnRniDMtN763nuKNKcX - template: - metadata: - name: postgres-initdb-script - namespace: workflows - type: Opaque {{- else if eq .Values.cluster "pollux" }} --- apiVersion: bitnami.com/v1alpha1 @@ -81,21 +52,6 @@ spec: --- apiVersion: bitnami.com/v1alpha1 kind: SealedSecret -metadata: - name: postgres-application-passwords - namespace: workflows -spec: - encryptedData: - passwords: AgC9QwtIoYwQ/KgnuEcXh/SJwST61+evmyIHd8gtZVKViPEPmflRVuuZ3e4wvgTlhAjOcZNL8AFEth2EV75pJA1BvVhl4/o4FD2mtXrK6nI/bX7KQ1MBmuQ0JeM/NCGUiC8y4W6WeaIw7yOQPgiKRlmqmNbInVP6pyYsWRNAI9UnVVAUvefvx5DGkJ+woEe9NKj3DpIKJ9BYLEySF2OKjO4PUBnCeEdkYIU+SYQ/rZjxevrA7cId9SiOfW8WUJB4dwZS+B3wRR9uS6pas1DlejomQv3QruIBNOsnsJj2ojkkWpZCIaIWDsROGSJy+HOl/u5vKjGERdmVCd/F21bX+vVy8sFU6sbR1h6cN2AzEB8LADmd++iqI0smeP1BUIPnV1Yhs+nXOlGuxWeO0CxGqn0Pi9SBSao2Lz4txAmfU7ZPnnE2NT3Pxp5IzEPKpskLWC6lzgRc/2/5JQZ81BJXMvaK64xqirAVJZDVuDNEzl6JTfAzK5P5hREsge6fOo8iupxRo/ESa7kCzlCBiNoR4hvaIZmvCqtbKhUtf0Hb1HdxGFU6TMgU6KQlz/m0xvQr77XQtZ9OAVbCnNl8YcNoN0QHHGemBjVeoOSb892y+zN+4uAtOaWyaYV/90oisH6fsao8vxA4dNL77dXzLt3I0guF1h0jAwBykRj8Xly9WJ1v1MI6AzN1eNWBaJJbJQqM5tXX9JZ8UVtAHpxOOFIKDXm4NMpTbFEcGpE= - usernames: AgBNaSYptjeYMUcQWA/B4rgEdUhB/4w3Lbw4WC9CiYbm4pc2sLTw2Tz7aytAK5vNWIAh13j3ZAq0CjMREJ6uu55JxhsK8YGus1rV8l8iqt4rGLcW9lbqA0Sz6wV7SCLqbdGIgUmILiNHPWKBhoBdyWiafgni8II33DY4AMtgt//+B5DVp8ttO3PfT5MIzvmWbzkGz/OC0BuRhrfefEKg6y9DcDDseeVli6hRAXee+rJ0DLXDzrwkWWzI5wRb0ndsZPltLYz8BgLW7+aHshU0HRl5iNU/A8VrvN3600uWDY48oReMqytkyvbP08JcXhwA/fcczqZiufsTZvwd/TFrd6L2h1dbO45O7aVahfOasY9AGj/kdBpRp+4jVqr/BfIJu2hFFqB6sCiCRck/7FUtx6R1xk87r1qTmcfTso9Bj8/XL99hIDwObTRC2cWQw4oLbwLEdzirjpPnHc3sDlnYDUQy0PpX7KRsJaZkqvLO+WhnmIuzFahWzCNTHTS5DIM16xVncNdx54ZQU1iUBuNcFrJuvVVVvfgXYqv8DS2MpUc4wn036ZWZILL9UjHv9xLtGeykfflFlnGJpa6SQRuJUISrTr0/Dz+aKimzQxraqLXzbpcO5i3n4gLwA+TOFURxaywN5ip5Ic4dnkut4MCwcDbbNSOSuPj7gSf6ElncDXuxWOQ8wDe9m6p8zBvRP0sE7fX7bEtkM9QwxJuk9Tcz5g== - template: - metadata: - name: postgres-application-passwords - namespace: workflows - type: Opaque ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret metadata: name: postgres-argo-workflows-password namespace: workflows @@ -112,14 +68,17 @@ spec: apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: - name: postgres-initdb-script + name: postgres-auth-service-password namespace: workflows spec: encryptedData: - init.sql: AgCMAUcfIwMH/y8FT+D0BXHm1mi/nvns0v4Shcn0Wq9Jg2wYh2SqSd2nFMU4pNZuONu/HEwiAtGQHy3Ev7bw971itFoDRSsAUpV16wdYGF7ic30D9NWFuvmjjqhIdx/SeT+MplRKSLIKvoyCrNEjra9xNdVoOi3cm0nT4w9UChEre4SfJMiMLZQX2tmfQTKASdJsx5XvV1YhIftb9ZWKbjfYDRCxLOI/mTV6aMluGEaHkQSH9/m24asuyax6gcZOpzLpIKKivLhj8NMBWAzY2YUFqxrZ/D6W6Ycr/iMhogHr2vnCCSWM8xlNPf6XBqqfipCn9URdCtC9glSnppXJpldB+m9iorTluvNQc/pro524VIWA/ANs92WqZqSVHt4b9E9gTX5FVeEYI4HCar/jAHK2FqWWaBXwAq54UfhTAQaJO/WbCUyzWHc+VAZld+RhxXpv+WKJjlq4qHREiDCUIYfRLPBM0+eQLQeNdG35LIFkIRYVQosClzyV7HlvFLqx3lUOi6zEYq3p4d9AlVsI78PjYrORlKnIhYWbV4kTnxfFaZvu9NO1toVnQFhwDavtBjI2iN+0ndpE4GLHc3TrKB7fLgh1vMJE5ZfbVTQqxihePNYyfFLsaCINu2bxR/32qYKVzH+4B/jpvv98Q1EcKPOvPh1t6eBgP1z10JNDEN3fzTjoHMb9kVxHfJHNjS8/gONdr1R8FN0OFXy9ZTrTP17rw7m1nkVAvkFiW0fw3z+bj9EP/iWCfmMsDqDRAEsecVK0TaQKX66EYXuI+/Vtfoi1+K+reVFCV0vB4ip1h9HfjWuSisx8swgrnA52BDpYcJ9YZV0DPwWPjReBlLiY6cOtlkuV8R15So+L + password: AgDHejDxPArV97Etg07L0oUlMDTIFlluz3cqYfMfJe/MBoPWLN8wxWq/Vpmy/0+LAW5aj9sIPnsXCE0Pfq4tXdr7sLdhNHOA0Efy2m5WLcoyTzbTU4/f/beXIGsabDFVvgEvIrEYIu2TOJj1mTLFmESWbYG4Z822oXdKEdmAE4Zvf8wmSkGLfOoFXYueNBaQ7N2BNIeA1+8pywuHMmoyeTOyxk6J743vRiPqEK940H+BT5bhuZz370FJVeXnKq+SBgsckqVZ42Rp7VW2qW1+j+tAku6AHcRhCxV0KLPjf08oQrzcY60blBvW4AUiwLrSghK88DfswBENQKtYlYO9nt5mV7ZaBD1dnSetCM867fRiSyTXXN0PJAXZjgAqkdQ5W8cBA5wImD0cF+wsZShZyVEO2qYGL5THrUATjHkSF2zGfhLSGHIlJlmsC527Yo2J0SovqjY4g3qTI8VxdugOax7yj/W8y2iwUxjokTvtwplIjM0nXNxwF7KqkbIOgxiW3IdtMyI7PQxTgO69jnch4odnzCgFToE7lOs/uVo1lNH+iU7a0o/o/5ksL8MqjX56zU1BYuGOtq+eGL9B3t7jnN91SkJzO9glRzuo15wRARKMdJ2Et2tqkfw6qQlCVnpvj8r4xApUnsMbvyrR6odP2jg5Sr2mgYnoN2krb6jjJwiBFeC3FZcJVctBUa60ZPpRiftXvUCpjhU4qMaABrk66k2xZZTD346wcMg= + username: AgBRyZIlJrZnf0VtwQE1iqJbwxwcE9d638Ii21F75xCj1eVGne0t1oCysZpi9ZLOjhPYTWZADBW8VwYM6OchzMRcTAO3M4tsALsb2tsf8id9zMl7He1NIeprLeKr3hNQQ4Ktcf+CNrStr/f/b5Ei3Po8aA1Aq3VOiuBd+C+0P/nHJWcEGl0hbw3GEytjILHl7JwjMg40B6j2Diq3Z3o7fry17iJ98V0ta1kyQBpAZdlmPr+mSXpllpl915dhepE86//k9c+2ZIN7+WmLln4MYmznakbcZpiN5QAhuxnJO69G8wYcwSsJdI0B4fOy3iNMc/zNCWLbd3pgmz0h5hvumU1XZ42ftujTvhDb6eagBWPMWr7gguNSjWw6zwgtCPSVt+lzRBEu9MUBAY1TA3Zk5MvMXAYPTlix0vN6lPZweB2u1C/f/GqAV7BzTDMzxj58Fa/r/B1PEkOvgZygZ16TojXOQlkcMT7DfPf9Yf4YWL59i1RBzUvw2lgDB1glZ4GqMcxYHTfTR6j4feQJzmvVh2FgP0kthsxAXhO0a/sZ4EHfxVeN51PKA3BPuFdX56HLAkYvj2Osmuy+fVC8UGsDW9ik5fndzhaqxap/9qzLYUtU2AtEI3tPKvJhpM0QQvFockUgY6J31y1IivOo+gGGS1DCnRVnNDPHXETE2DBidSwBSThTiuV8+7LMrCyoAvaFEBFhENcrbtX5Eb8= template: metadata: - name: postgres-initdb-script + labels: + argocd.argoproj.io/instance: workflows + name: postgres-auth-service-password namespace: workflows type: Opaque {{ else }} diff --git a/charts/workflows-cluster/staging-values.yaml b/charts/workflows-cluster/staging-values.yaml index bd4dd4715..cb0dfead1 100644 --- a/charts/workflows-cluster/staging-values.yaml +++ b/charts/workflows-cluster/staging-values.yaml @@ -77,8 +77,6 @@ vcluster: "/postgres-passwords": "workflows/postgres-passwords" "/postgres-argo-workflows-password": "workflows/postgres-argo-workflows-password" "/postgres-auth-service-password": "workflows/postgres-auth-service-password" - "/postgres-application-passwords": "workflows/postgres-application-passwords" - "/postgres-initdb-script": "workflows/postgres-initdb-script" ingress: secretName: letsencrypt-kubernetes-staging-workflows-diamond-ac-uk diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml deleted file mode 100644 index a7d121aaf..000000000 --- a/charts/workflows-cluster/templates/sealed-secret-postgres-application-passwords.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret -metadata: - creationTimestamp: null - name: postgres-application-passwords - namespace: workflows -spec: - encryptedData: - passwords: AgAaHsA0p6ZAyHb0lUl2rtGkv6OG7f6b6d95MPjsI5sogEAzz0YL8nuSx8x7HHbtqT03dd7MmHV9gawNo0CGhGQjGFwLrtFhI67EcufAE6/5q7hX6DQAxm5/ZTZPvFffOuLMCS/PAJzZAYcBKW0Adhk8qCmcQ+Ps4G4GKcCY6kD4/BuoDvaGodvie2it16ejPHEeZ8cMzfYN+/NMRQ+6q2dmwqb/Gf5kc6HJMbynaSkQotD2OFbnkzvYUdAcjpxLMsw4Ia5kP2Hz11mgwV1LqrGW70nDHFmojN4q/+PR+VrNd7FYN1ZgwoIbIoKPbF/E1chSmwGGU8CqwJxXATS+jYz1m7X5RR2PgL0fFdMHXB5jiXoGdZqTQKyt6okXxvF1fMthmZw5VrZBiTeE9pQnDCZEHq4rAXKuoWDjsrruMGATI/4JPive+snWDgpTEzHa40k+HXIj1/lHqiQfAQaRyLS5a89j+g20berJ8R/q6oYZhVEG4noKnntRcfKeT+DaeOeRoQ5M9Jn3AUfqke3R3sJJvYFTo0mU1F6fXq9YrOJRz3cQzPEGDqladBH8D9KHcl5dKs2PzZaAbpUlvT8YVadVWTtMm46etqBpAOE7rPYRQzhrmRHdRXOrN862p5qyhZLXgIvJASWheVaBbwIGK2PKpFSk1juzkZ9sAOFTkLD7BNJYn3rq6RFPl7CYjQ8ecNOQGGYPRIDDfAmmqHujiarAJXXqvyB8tjeSXqAd50ThkZGf7dO/zRUGAyI8a1KO3wYU - usernames: AgBTq5CHMVyTx6l2Ihqz4EE64Dm7G2wXSAQEnZr+4BA4nwU1bz+1xVNCen8AN7t8iPA5gO+8SyPIXKj9ZhqtjO+ltY2vjvIY2QXEQXOjDozfo+Q9TxgQ3jyKN3mr4hv2OxgVx+Obz8mD0rNPDO0cqI3SwUZQleDV/87dL09leUCIWFnNxHbhaLhuDNdPKTdw7ORSplHmTa35j1x9u5xOiwfOzUYshOYRcccqNzvKsp6Ptj2QWZkqiALn0FIkWC4uZ9KN0eQxv9w/ZLr/ixY5TI7tbBW5oiNYR6iQ0IK2xAOCl4tbTk/S8qkQBVbwxbvKrsNnR2FQR9hs8iimr1HDY1gFt2nt+3qY0Cle88Bngy0Yt/o7J7pZTV1rgr3SzpogcmIu/LCA1wln4OnMlhv/U+oMsoxVL/FssJupjFbX+5UiVzMpYYZ7CTLqiGnn29A+0VCp1bNaTTTYx1R5DGZc9JQj5+XkGCitCicf0GrSRs7nEjk/O/1aILE6CISpvqvXbMncjJysgVr8CdUoKwsdqhleRQ01llmhVj20LYhoGtMPe23DejGIrItlNlphp9dT4Sl0qvLPf3pmOaladabwCF0NXub9q4zpN5sM6p88xISHUIyD0Qh7T7WJ1wk0RBDC+onfZmWK8iZsP4XT2ZpbruwMJWriF9GlH+NSZhzwbym+QOBLV7x8jFebTF8P5lEUVf6oaGIa5dCQHAy0N3H0UzXE1U+XSBvo6eg= - template: - metadata: - creationTimestamp: null - labels: - argocd.argoproj.io/instance: workflows - name: postgres-application-passwords - namespace: workflows - type: Opaque diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml deleted file mode 100644 index 7d76405fb..000000000 --- a/charts/workflows-cluster/templates/sealed-secret-postgres-argo-workflows-password.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret -metadata: - creationTimestamp: null - name: postgres-argo-workflows-password - namespace: workflows -spec: - encryptedData: - password: AgABMdb+f+AyfmSgwm9NHvG13yK7Js3krlaH2nWoQAnupq1zZW7fFsmCnna1FW67RDzY0ZPOCc0T7yyWsEzVWuupBQWliRh9FaROQZ21wt6GWeQZD65tf0lqu9pLORwhMbaW8oSTTx/GAY2ojyz1YX0npsYfEdfh32YAEgpfrqZN8GAjdhqQUwGhsrhMIcxS4vilO8pk98Q6G+9hajduPNl766qW+IMyRnK1iZQdSU3i7r4neiLCaMh+cLpdbYfIYwG+LlChGWmHfYIucIH0pMb7bkCWzIdtQRobbcwK+atcD+nAEEl6IicyhEU+b/qHrGjCNvUQ5jq7JFYy6Ri0lKzFSpwVH4MkdzZWUpttsqo3EnKayQB8ZXZH5hTrpspifhhiI0D3s90relTAhn7UNz5fwbRtdTBpevhQzp5IZVuAMuvDdzcISh3LoBe7Vr/UUVHGOMLVyqzGY9z80VO95tJV+iDO2TNpEE3gNl4Gaxm9Dr3zDBmDyo8uKUuLYE38lVzB4EJmgo/vuE8OIdKdZGK905PIGQ6O5AidZbL3nEUvIHXoGrYiE0pZjyF4uVJpu65Dw5A3GDH6W6l5iK/sCTcL9LQdPX7o/AOfUWyNJbD4O6FAau3d1m5gie5kVVT8zzMhVH+BUxwT1JvRTxL3J6nazKlo0Xcoq4UdDai+I/dFg3di7aHo9obyWvcLAYPRMvhY3357PaxOsDAYkvaEbwPoFGTPIPLz8/o= - username: AgCfSEt91Uw44NHBeRVfIZOuu7zVlZFu80R9VifqNnxN2A/ggpIaHVqozXsStTeb/Qkl/axG2feP6hC2ilHVti20XHzDD98tTeo5p5j9yfStudLL/rIYZnNsO12uVUjKDPbOTrxgxtjJkRdDlO3Zd1Aqrsk11xZieeu9RaGBqY1qRVUkZb2bIM9kege/3wL8eTO9jF2ogMEybEtCBoOridBdmLMCPncYHt36NcPXi/8cpJOgj2icEFAQJT6MKlkdigiREMDXLByscJO0EseonIyiLdK/1WgRx/nUUMoqyt7CTqTej41cUZCM9ufjLC8VuM8OCtAHVKu4OOf76ya3wGp2OBf7ajBUQe0NbZ3+ckyrSgodQv92jemKCPkW2GeN2+t+M3/kTn9xQ0lc+TPpRR7JnlbHNYvCXLLtrtGG3AzkeyZJZ4FKBaIL5V5dS6ywSLvMsPlmjci1jfCswsHOE9uCVt456v968cvGFOpOXneHTALc46r/vjvJ58Nrtkayik3glhRsS7kPH26AJ2HhOOu6FwIp//+Emd2W3fw7MEWizu9tNCPJMUm9HrO7I59db74Cb7hZoBpzhNyzi7mfwQJCGCDU/ahlbYSWiknc2EDE0mCNZTIpyTPVYv7gc66yyroZSq4KHnaQl6pKLOCl3pHLa9xP6nuZfGqN5gaf+YCu6Qi05Ktq0IEHqIKNs/AXZE3iXVHzamhyUwFBqwnpDA== - template: - metadata: - creationTimestamp: null - labels: - argocd.argoproj.io/instance: workflows - name: postgres-argo-workflows-password - namespace: workflows - type: Opaque diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml deleted file mode 100644 index d5fb5f767..000000000 --- a/charts/workflows-cluster/templates/sealed-secret-postgres-auth-service-password.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret -metadata: - creationTimestamp: null - name: postgres-auth-service-password - namespace: workflows -spec: - encryptedData: - password: AgDHejDxPArV97Etg07L0oUlMDTIFlluz3cqYfMfJe/MBoPWLN8wxWq/Vpmy/0+LAW5aj9sIPnsXCE0Pfq4tXdr7sLdhNHOA0Efy2m5WLcoyTzbTU4/f/beXIGsabDFVvgEvIrEYIu2TOJj1mTLFmESWbYG4Z822oXdKEdmAE4Zvf8wmSkGLfOoFXYueNBaQ7N2BNIeA1+8pywuHMmoyeTOyxk6J743vRiPqEK940H+BT5bhuZz370FJVeXnKq+SBgsckqVZ42Rp7VW2qW1+j+tAku6AHcRhCxV0KLPjf08oQrzcY60blBvW4AUiwLrSghK88DfswBENQKtYlYO9nt5mV7ZaBD1dnSetCM867fRiSyTXXN0PJAXZjgAqkdQ5W8cBA5wImD0cF+wsZShZyVEO2qYGL5THrUATjHkSF2zGfhLSGHIlJlmsC527Yo2J0SovqjY4g3qTI8VxdugOax7yj/W8y2iwUxjokTvtwplIjM0nXNxwF7KqkbIOgxiW3IdtMyI7PQxTgO69jnch4odnzCgFToE7lOs/uVo1lNH+iU7a0o/o/5ksL8MqjX56zU1BYuGOtq+eGL9B3t7jnN91SkJzO9glRzuo15wRARKMdJ2Et2tqkfw6qQlCVnpvj8r4xApUnsMbvyrR6odP2jg5Sr2mgYnoN2krb6jjJwiBFeC3FZcJVctBUa60ZPpRiftXvUCpjhU4qMaABrk66k2xZZTD346wcMg= - username: AgBRyZIlJrZnf0VtwQE1iqJbwxwcE9d638Ii21F75xCj1eVGne0t1oCysZpi9ZLOjhPYTWZADBW8VwYM6OchzMRcTAO3M4tsALsb2tsf8id9zMl7He1NIeprLeKr3hNQQ4Ktcf+CNrStr/f/b5Ei3Po8aA1Aq3VOiuBd+C+0P/nHJWcEGl0hbw3GEytjILHl7JwjMg40B6j2Diq3Z3o7fry17iJ98V0ta1kyQBpAZdlmPr+mSXpllpl915dhepE86//k9c+2ZIN7+WmLln4MYmznakbcZpiN5QAhuxnJO69G8wYcwSsJdI0B4fOy3iNMc/zNCWLbd3pgmz0h5hvumU1XZ42ftujTvhDb6eagBWPMWr7gguNSjWw6zwgtCPSVt+lzRBEu9MUBAY1TA3Zk5MvMXAYPTlix0vN6lPZweB2u1C/f/GqAV7BzTDMzxj58Fa/r/B1PEkOvgZygZ16TojXOQlkcMT7DfPf9Yf4YWL59i1RBzUvw2lgDB1glZ4GqMcxYHTfTR6j4feQJzmvVh2FgP0kthsxAXhO0a/sZ4EHfxVeN51PKA3BPuFdX56HLAkYvj2Osmuy+fVC8UGsDW9ik5fndzhaqxap/9qzLYUtU2AtEI3tPKvJhpM0QQvFockUgY6J31y1IivOo+gGGS1DCnRVnNDPHXETE2DBidSwBSThTiuV8+7LMrCyoAvaFEBFhENcrbtX5Eb8= - template: - metadata: - creationTimestamp: null - labels: - argocd.argoproj.io/instance: workflows - name: postgres-auth-service-password - namespace: workflows - type: Opaque diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml deleted file mode 100644 index cc0fa322d..000000000 --- a/charts/workflows-cluster/templates/sealed-secret-postgres-initdb-script.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret -metadata: - creationTimestamp: null - name: postgres-initdb-script - namespace: workflows -spec: - encryptedData: - init.sql: AgB4hcgbt4yJhii5v3cJ5WZBuGOcRBS4PaZeT8kjHSc9gNAfxyCPM0EtwBaVZMfE2dinj3nk+2GDsoVsoYaKl8XXz7Ey0xfdPfypLLGmTaAUGFWFRL9ygrJV8T1wZB6rI33erTgO/NQCu35umLYq8xyFkIZolrZEOFP6hHShBMbz51yIjRdwvTVkYItfiEOKmHmHs4psyWvsK+KL58zhB/7PZZ7Twi4+rdBmB+wV0NMy6lpq41mQNz12tLVQUlvM0KKyUApow1FVXuBbeZkKgTSKEgHYOtrmrWwoqAl2qK1hf4B0jRocZAv1WCOcevbTb+IFqRdAUiOHDHc5TnCuSUNiffmTwyRXlvLgvoJLElFUaamsEESgzAS7+qkwzSeyrZ3F+qmeXXCIfnKUL0kzCo9kMgXGqOjJ6gibo4wFSL4QUctv6GT4rAGIqyUyLvrCoU0QhNpPfhZkXQf5FUz/n0wHD1qbisPLEyqsCGcZR45RClrhncza1RLWb/xWhHAsVUTeolrSZXpZOnEYOsjuIF2Gyf8029HMMQMhgguThhBho93MwhA7BUnbSbuMrQlQ+R7TryxlplOsWZfPGBEs1M/YYCVXs4+PRHPvttYps9KHcpvN+WlObE+IIxtVbozVaVEBz26j9xZezC7hFXYTifRXEpgRExfRtNtRIpel/xYpkAoQsBbJ+Xsi23Vrp/uyjU2ogXJoziGHaWs8/YKnvD5bA4AXnNAm3zLokCeXJ1ei3O8iFZ5R2vxXUSvDFC4oOxLMj+nB89xR7/0z7L5BxMe8v7gtOZ1q1qd543LgNvuysSOb8CT24bc3gc9Ueqk8nFZTg+R2L6avDUJuzPXRS0zl8cCfxZ/GEEkzPsVYTY6wTJm3GJ6wnf3Mwyzk+dTBViPhjzj96XMMAqEzWVHKpfQkxjmeUfoRynK7/quQvsWl2tLGZofDHGKAAB6ZdVirGHTqCqqidgVz8QNIz9ECybDJQpilwzWxHUHTCu0YoBidXwjR25BOI0Q= - template: - metadata: - creationTimestamp: null - name: postgres-initdb-script - namespace: workflows diff --git a/charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml b/charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml deleted file mode 100644 index 9d51b149f..000000000 --- a/charts/workflows-cluster/templates/sealed-secret-postgres-passwords.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret -metadata: - creationTimestamp: null - name: postgres-passwords - namespace: workflows -spec: - encryptedData: - password: AgBD1UtI2bqrlgkSPQVTOE0L7baaX/42Bq0w9209GiA7FztZkaOxGsOroAW0cCKifbbK9E4BlTPyFu6X1onw8OSowpmZ8bih5amuroYECugw/g669kfh//G7nKi44o26XoI9CajDJUVb+LkXHZFEJ8Xb9xnclxdR4U4klCriIow1cUnCkif2ELa1MMZ+mVvAIdsArIehymNfCpCRZzNu35u38Yf0EYAOCeh5W0LT5cyKp1pql8AGAGbpSSzojJxWpx8N0lA8toeKjOmVegKK2jS7q+4IfF8In2UU8E/DtcMTUbvorYwLPVKtDA7AlHTH8qU1+tosjTHQa5s8U0XvAGKuboiy7vPVDpypMo+tP5LKab9cdFkJumT+PFoIyJkacJnzs2TEzGAAi+PAgr/6yUBgsFejtV0yjFXNbh0vPhVdDQaqt+ylm451bTQo1FxgS6sOFYHnUo4Cj7+0vnMu8f994GZilaqdkY20aRWn/6pg66K1d/koDXB0hDJncx5xsZ1Zgx8Bo1B7rm0v7cyDmFaFEv4BSdcU9XMor98tRMOMQgdHaKBkyz4T/eViwmfoGI/9VA1PaqvO5cEZgkQ6Rn5LqvmkvNanKtrgn+BTsvlximUskQq0NklDl84EUEvieT4OmzNIAWiVTVImZ3/erVQFau7sILc8U+s5H6srGJO45wtFx4r+eKMGC/ZK4Ie128vVWn8e5JFDZ8UAJChyeV4aCzQw1Uw2soQ= - repmgr-password: AgDGDte8on0ZOp1Ts++H8D0ZtVDS6LrTZj6XQ1pdER1WoACEjuzg/VhEmqMBP52Rla1lU6agGbZph65tdS6cbf2c2pUSvTnh2agVncdADMjSZonG1dh5wW0fQj9k0WxB+40gv2iWlW3jsaOhYPSCaI38vSL4yjnTr0IVxTIRDBF3Lst+P4jSTgQxUaHzDy7OtRTsGMJDky/BCDFR4fh4MAJxFCoDLnPPG8FBsVVoPz4UeeOMNdq4Yj4/BH677G1PCbsJGGbbSOPn4zr1Fh0q9pJ4ge+vE82bhoqBkb++v2jYtjyCgicS0Tj+KaA6y87/6RTveOpDyooetomwa3JwVawzPWY2wMFB6NrPGeie97wMiYGTFZzcnVZycqfAp5LuSrWdqx+lvJEg2UOyXXHiT3v4qTJxvsDbONuVkHB/ogYi2o66ZBaAUObzFi5G4LHZg5qzxkTroO3T7OTZTSnqAPoyApHHo/t0uSPAWbv+wyqBaZQJxV4cQ7Eyf3wni7UKIXLK139D7Ah2/BrxCM0l4pL8gmFnCjkGKgJiDgG3C+rQXZc+lbjdw4XaLjdTh/T5fg5q1ve0ZErFIa+ugyoLmU17hFlIIbDKaw3nIQJP/abOkx08lLlAZLNuDhGj/HQR7gzEgiLXYWHpBWgUFYRrlAcF2pnq774QL7mnuHbDTZERu5eiC0TPI1FqpYWqujeIB/RIZw9caAzdB9fPJMvbeYQCIdY4uTbQlrs= - template: - metadata: - creationTimestamp: null - labels: - argocd.argoproj.io/instance: workflows - name: postgres-passwords - namespace: workflows - type: Opaque diff --git a/charts/workflows-cluster/values.yaml b/charts/workflows-cluster/values.yaml index f076ba430..d4b95509e 100644 --- a/charts/workflows-cluster/values.yaml +++ b/charts/workflows-cluster/values.yaml @@ -140,8 +140,7 @@ vcluster: "/s3-artifact": "workflows/artifact-s3" "/postgres-passwords": "workflows/postgres-passwords" "/postgres-argo-workflows-password": "workflows/postgres-argo-workflows-password" - "/postgres-application-passwords": "workflows/postgres-application-passwords" - "/postgres-initdb-script": "workflows/postgres-initdb-script" + "/postgres-postgres-auth-service-password": "workflows/postgres-postgres-auth-service-password" rbac: clusterRole: enabled: false diff --git a/charts/workflows/templates/postgres-secrets-policy.yaml b/charts/workflows/templates/postgres-secrets-policy.yaml new file mode 100644 index 000000000..dfda745a5 --- /dev/null +++ b/charts/workflows/templates/postgres-secrets-policy.yaml @@ -0,0 +1,78 @@ +apiVersion: kyverno.io/v1 +kind: Policy +metadata: + name: generate-postgres-secrets + namespace: {{ .Release.Namespace }} +spec: + rules: + - name: generate-postgres-application-passwords + match: + any: + - resources: + kinds: ["Secret"] + names: + - postgres-argo-workflows-password + - postgres-auth-service-password + context: + - name: argoSecret + apiCall: + urlPath: /api/v1/namespaces/{{ .Release.Namespace }}/secrets/postgres-argo-workflows-password + - name: authSecret + apiCall: + urlPath: "/api/v1/namespaces/{{ .Release.Namespace }}/secrets/postgres-auth-service-password" + generate: + apiVersion: v1 + kind: Secret + name: postgres-application-passwords + namespace: {{ .Release.Namespace }} + synchronize: true + generateExisting: true + data: + type: Opaque + stringData: + usernames: "{{`{{ join(',', [ + base64_decode(argoSecret.data.username || ''), + base64_decode(authSecret.data.username || '') + ]) }}`}}" + passwords: "{{`{{ join(',', [ + base64_decode(argoSecret.data.password || ''), + base64_decode(authSecret.data.password || '') + ]) }}`}}" + + - name: generate-initdb-script + match: + any: + - resources: + kinds: ["Secret"] + names: + - postgres-argo-workflows-password + - postgres-auth-service-password + context: + - name: argoSecret + apiCall: + urlPath: "/api/v1/namespaces/{{ .Release.Namespace }}/secrets/postgres-argo-workflows-password" + - name: authSecret + apiCall: + urlPath: "/api/v1/namespaces/{{ .Release.Namespace }}/secrets/postgres-auth-service-password" + generate: + apiVersion: v1 + kind: Secret + name: postgres-initdb-script + namespace: {{ .Release.Namespace }} + synchronize: true + generateExisting: true + data: + kind: Secret + type: Opaque + data: + init.sql: | + {{`{{ base64_encode(join('', [ + 'CREATE USER argo_workflows WITH PASSWORD \'', + base64_decode(argoSecret.data.password || ''), + '\'; ', + 'CREATE DATABASE argo_workflows OWNER argo_workflows; ', + 'CREATE USER auth_user WITH PASSWORD \'', + base64_decode(authSecret.data.password || ''), + '\'; ', + 'CREATE DATABASE auth_service OWNER auth_user;' + ])) }}`}} diff --git a/charts/workflows/test-policy/generate-postgres-secrets/chainsaw-test.yaml b/charts/workflows/test-policy/generate-postgres-secrets/chainsaw-test.yaml new file mode 100644 index 000000000..212271152 --- /dev/null +++ b/charts/workflows/test-policy/generate-postgres-secrets/chainsaw-test.yaml @@ -0,0 +1,56 @@ + +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: test-generate-postgres-secrets +spec: + concurrent: false + steps: + - name: create-input-postgres-secrets + - try: + # The Github action installed the policy in the "default" namespace, not "workflows" + - apply: + resource: + apiVersion: v1 + kind: Secret + metadata: + name: postgres-argo-workflows-password + namespace: default + type: Opaque + data: + username: YXJnb191c2Vy # argo_user + password: c2VjcmV0MQ== # secret1 + - apply: + resource: + apiVersion: v1 + kind: Secret + metadata: + name: postgres-auth-service-password + namespace: default + type: Opaque + data: + username: YXV0aF91c2Vy # auth_user + password: c2VjcmV0Mg== # secret2 + + - assert: + resource: + apiVersion: v1 + kind: Secret + metadata: + name: postgres-application-passwords + namespace: default + data: + # base64("argo_user,auth_user") + usernames: YXJnb191c2VyLGF1dGhfdXNlcg== + # base64("secret1,secret2") + passwords: c2VjcmV0MSxzZWNyZXQy + - assert: + resource: + apiVersion: v1 + kind: Secret + metadata: + name: postgres-initdb-script + namespace: default + data: + init.sql: Q1JFQVRFIFVTRVIgYXJnb193b3JrZmxvd3MgV0lUSCBQQVNTV09SRCAnc2VjcmV0MSc7IENSRUFURSBEQVRBQkFTRSBhcmdvX3dvcmtmbG93cyBPV05FUiBhcmdvX3dvcmtmbG93czsgQ1JFQVRFIFVTRVIgYXV0aF91c2VyIFdJVEggUEFTU1dPUkQgJ3NlY3JldDInOyBDUkVBVEUgREFUQUJBU0UgYXV0aF9zZXJ2aWNlIE9XTkVSIGF1dGhfdXNlcjs= + # "CREATE USER argo_workflows WITH PASSWORD 'secret1'; CREATE DATABASE argo_workflows OWNER argo_workflows; CREATE USER auth_user WITH PASSWORD 'secret2'; CREATE DATABASE auth_service OWNER auth_user;" From 3d80d3265d0b3e0f9f103cfc07db419c6ce2f636 Mon Sep 17 00:00:00 2001 From: TBThomas56 Date: Mon, 30 Mar 2026 01:21:44 +0100 Subject: [PATCH 06/20] feat(backend): auth-core scaffolding --- backend/Cargo.lock | 23 ++++++++++++- backend/Cargo.toml | 5 ++- backend/auth-core/Cargo.toml | 32 +++++++++++++++++++ .../migration/Cargo.toml | 0 .../migration/README.md | 0 .../migration/src/lib.rs | 0 .../src/m20220101_000001_create_table.rs | 0 .../migration/src/main.rs | 0 backend/auth-core/src/bin/keygen.rs | 23 +++++++++++++ backend/auth-core/src/config.rs | 27 ++++++++++++++++ backend/auth-core/src/entity/mod.rs | 5 +++ backend/auth-core/src/entity/oidc_tokens.rs | 22 +++++++++++++ backend/auth-core/src/entity/prelude.rs | 3 ++ backend/auth-core/src/error.rs | 26 +++++++++++++++ backend/auth-core/src/healthcheck.rs | 5 +++ backend/auth-core/src/lib.rs | 7 ++++ backend/auth-daemon/Cargo.toml | 2 +- backend/oidc-bff/Cargo.toml | 1 - 18 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 backend/auth-core/Cargo.toml rename backend/{oidc-bff => auth-core}/migration/Cargo.toml (100%) rename backend/{oidc-bff => auth-core}/migration/README.md (100%) rename backend/{oidc-bff => auth-core}/migration/src/lib.rs (100%) rename backend/{oidc-bff => auth-core}/migration/src/m20220101_000001_create_table.rs (100%) rename backend/{oidc-bff => auth-core}/migration/src/main.rs (100%) create mode 100644 backend/auth-core/src/bin/keygen.rs create mode 100644 backend/auth-core/src/config.rs create mode 100644 backend/auth-core/src/entity/mod.rs create mode 100644 backend/auth-core/src/entity/oidc_tokens.rs create mode 100644 backend/auth-core/src/entity/prelude.rs create mode 100644 backend/auth-core/src/error.rs create mode 100644 backend/auth-core/src/healthcheck.rs create mode 100644 backend/auth-core/src/lib.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index d4132130c..22817a9d8 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -407,6 +407,28 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "auth-core" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum", + "base64 0.22.1", + "chrono", + "http-body-util", + "migration", + "oauth2", + "openidconnect", + "rustls 0.23.35", + "sea-orm", + "serde", + "serde_json", + "serde_yaml", + "sodiumoxide", + "thiserror 2.0.17", + "tokio", +] + [[package]] name = "auth-daemon" version = "0.1.0" @@ -3987,7 +4009,6 @@ dependencies = [ "dotenvy", "http-body-util", "hyper 1.8.1", - "migration", "moka", "oauth2", "openidconnect", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index a6293090b..5bb7d93d1 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,8 +1,11 @@ [workspace] members = [ "argo-workflows-openapi", + "auth-core", + "auth-core/migration", "auth-daemon", - "graph-proxy", "oidc-bff", "oidc-bff/migration", + "graph-proxy", + "oidc-bff", "sessionspaces", "telemetry", ] diff --git a/backend/auth-core/Cargo.toml b/backend/auth-core/Cargo.toml new file mode 100644 index 000000000..3391a7407 --- /dev/null +++ b/backend/auth-core/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "auth-core" +version = "0.1.0" +edition = "2024" +license-file = "../../LICENSE" + +[lib] +name = "auth_core" +path = "src/lib.rs" + +[[bin]] +name = "keygen" +path = "src/bin/keygen.rs" +publish = false + +[dependencies] +anyhow = { workspace = true, features = ["backtrace"] } +axum = { workspace = true, features = ["macros"] } +base64 = "0.22.1" +chrono = { workspace = true } +http-body-util = "0.1.3" +migration = { version = "0.1.0", path = "migration" } +oauth2 = "5.0.0" +openidconnect = { version = "4.0.1", features = ["timing-resistant-secret-traits"] } +rustls = { version = "0.23.35", features = ["ring"] } +sea-orm = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +serde_yaml = "0.9.34" +sodiumoxide = "0.2.7" +thiserror = { workspace = true } +tokio = { workspace = true, features = ["full"] } diff --git a/backend/oidc-bff/migration/Cargo.toml b/backend/auth-core/migration/Cargo.toml similarity index 100% rename from backend/oidc-bff/migration/Cargo.toml rename to backend/auth-core/migration/Cargo.toml diff --git a/backend/oidc-bff/migration/README.md b/backend/auth-core/migration/README.md similarity index 100% rename from backend/oidc-bff/migration/README.md rename to backend/auth-core/migration/README.md diff --git a/backend/oidc-bff/migration/src/lib.rs b/backend/auth-core/migration/src/lib.rs similarity index 100% rename from backend/oidc-bff/migration/src/lib.rs rename to backend/auth-core/migration/src/lib.rs diff --git a/backend/oidc-bff/migration/src/m20220101_000001_create_table.rs b/backend/auth-core/migration/src/m20220101_000001_create_table.rs similarity index 100% rename from backend/oidc-bff/migration/src/m20220101_000001_create_table.rs rename to backend/auth-core/migration/src/m20220101_000001_create_table.rs diff --git a/backend/oidc-bff/migration/src/main.rs b/backend/auth-core/migration/src/main.rs similarity index 100% rename from backend/oidc-bff/migration/src/main.rs rename to backend/auth-core/migration/src/main.rs diff --git a/backend/auth-core/src/bin/keygen.rs b/backend/auth-core/src/bin/keygen.rs new file mode 100644 index 000000000..a49b24626 --- /dev/null +++ b/backend/auth-core/src/bin/keygen.rs @@ -0,0 +1,23 @@ +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use sodiumoxide::crypto::box_::gen_keypair; + +fn main() { + // Initialize sodiumoxide (required before using crypto functions) + if sodiumoxide::init().is_err() { + eprintln!("Failed to initialize libsodium"); + std::process::exit(1); + } + + // Generate a new sealed-box keypair + let (public_key, secret_key) = gen_keypair(); + + // Base64 encode for easy storage in environment variables + let public_b64 = BASE64.encode(public_key.0); + let secret_b64 = BASE64.encode(secret_key.0); + + println!("Public Key:"); + println!("{}", public_b64); + println!(); + println!("Private Key:"); + println!("{}", secret_b64); +} diff --git a/backend/auth-core/src/config.rs b/backend/auth-core/src/config.rs new file mode 100644 index 000000000..643eacd41 --- /dev/null +++ b/backend/auth-core/src/config.rs @@ -0,0 +1,27 @@ +use crate::Result; +use serde::{Deserialize, Serialize}; +use std::path::Path; + +// Create the config for auth-package +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CommonConfig { + pub client_id: String, + pub client_secret: String, + pub oidc_provider_url: String, + pub port: u16, + pub postgres_user: String, + pub postgres_password: String, + pub postgres_database: String, + pub postgres_hostname: String, + pub postgres_port: u16, + pub encryption_public_key: String, +} + +/// Generic config loader - works for any struct that immplements Deserialize +pub fn load_config_from_file>(path: P) -> Result { + let content = std::fs::read_to_string(&path)?; + match path.as_ref().extension().and_then(|e| e.to_str()) { + Some("json") => Ok(serde_json::from_str(&content)?), + _ => Ok(serde_yaml::from_str(&content)?), + } +} diff --git a/backend/auth-core/src/entity/mod.rs b/backend/auth-core/src/entity/mod.rs new file mode 100644 index 000000000..889654a14 --- /dev/null +++ b/backend/auth-core/src/entity/mod.rs @@ -0,0 +1,5 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 + +pub mod prelude; + +pub mod oidc_tokens; diff --git a/backend/auth-core/src/entity/oidc_tokens.rs b/backend/auth-core/src/entity/oidc_tokens.rs new file mode 100644 index 000000000..23ee74526 --- /dev/null +++ b/backend/auth-core/src/entity/oidc_tokens.rs @@ -0,0 +1,22 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "oidc_tokens")] +pub struct Model { + #[sea_orm(column_type = "Text")] + pub issuer: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub subject: String, + #[sea_orm(column_type = "VarBinary(StringLen::None)")] + pub encrypted_refresh_token: Vec, + pub expires_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/backend/auth-core/src/entity/prelude.rs b/backend/auth-core/src/entity/prelude.rs new file mode 100644 index 000000000..b303a78d8 --- /dev/null +++ b/backend/auth-core/src/entity/prelude.rs @@ -0,0 +1,3 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 + +pub use super::oidc_tokens::Entity as OidcTokens; diff --git a/backend/auth-core/src/error.rs b/backend/auth-core/src/error.rs new file mode 100644 index 000000000..a944ebb41 --- /dev/null +++ b/backend/auth-core/src/error.rs @@ -0,0 +1,26 @@ +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; + +#[derive(Debug)] +pub struct Error(anyhow::Error); + +impl IntoResponse for Error { + fn into_response(self) -> Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Something went wrong: {}", self.0), + ) + .into_response() + } +} + +impl From for Error +where + E: Into, +{ + fn from(err: E) -> Self { + Self(err.into()) + } +} diff --git a/backend/auth-core/src/healthcheck.rs b/backend/auth-core/src/healthcheck.rs new file mode 100644 index 000000000..c9be25c8a --- /dev/null +++ b/backend/auth-core/src/healthcheck.rs @@ -0,0 +1,5 @@ +use axum::http::StatusCode; + +pub async fn healthcheck() -> StatusCode { + StatusCode::ACCEPTED +} diff --git a/backend/auth-core/src/lib.rs b/backend/auth-core/src/lib.rs new file mode 100644 index 000000000..82bdbdbfc --- /dev/null +++ b/backend/auth-core/src/lib.rs @@ -0,0 +1,7 @@ +pub mod entity; +pub mod error; +pub mod healthcheck; +pub mod config; + +pub type Result = std::result::Result; + diff --git a/backend/auth-daemon/Cargo.toml b/backend/auth-daemon/Cargo.toml index e2367a75c..4e6687d8f 100644 --- a/backend/auth-daemon/Cargo.toml +++ b/backend/auth-daemon/Cargo.toml @@ -38,4 +38,4 @@ testcontainers = {version = "0.26.0", features = ["http_wait_plain"]} [dev-dependencies] mockito.workspace = true serde_json.workspace = true -migration = { version = "0.1.0", path = "../oidc-bff/migration" } +migration = { version = "0.1.0", path = "../auth-core/migration" } diff --git a/backend/oidc-bff/Cargo.toml b/backend/oidc-bff/Cargo.toml index 359686b18..c87214843 100644 --- a/backend/oidc-bff/Cargo.toml +++ b/backend/oidc-bff/Cargo.toml @@ -34,7 +34,6 @@ thiserror.workspace = true tokio = { workspace = true, features = ["full"] } tower-sessions = "0.14.0" sea-orm = {workspace=true} -migration = { version = "0.1.0", path = "migration" } sodiumoxide = "0.2.7" base64 = "0.22.1" serde_yaml = "0.9.34" From 08ff8c8a9f7e53f4d95ae227f458883c50174053 Mon Sep 17 00:00:00 2001 From: TBThomas56 Date: Mon, 30 Mar 2026 01:37:38 +0100 Subject: [PATCH 07/20] feat(backend): auth-core oidc helpers --- backend/auth-core/src/lib.rs | 1 + backend/auth-core/src/oidc.rs | 81 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 backend/auth-core/src/oidc.rs diff --git a/backend/auth-core/src/lib.rs b/backend/auth-core/src/lib.rs index 82bdbdbfc..7c54baec6 100644 --- a/backend/auth-core/src/lib.rs +++ b/backend/auth-core/src/lib.rs @@ -2,6 +2,7 @@ pub mod entity; pub mod error; pub mod healthcheck; pub mod config; +pub mod oidc; pub type Result = std::result::Result; diff --git a/backend/auth-core/src/oidc.rs b/backend/auth-core/src/oidc.rs new file mode 100644 index 000000000..88eb0aa06 --- /dev/null +++ b/backend/auth-core/src/oidc.rs @@ -0,0 +1,81 @@ +use crate::config::CommonConfig; +use anyhow::anyhow; +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use oauth2::{ClientId, ClientSecret, EndpointMaybeSet, EndpointNotSet, EndpointSet, reqwest}; +use openidconnect::core::{CoreClient, CoreProviderMetadata, CoreTokenResponse}; +use openidconnect::{IssuerUrl, RefreshToken}; +use sea_orm::{Database, DatabaseConnection}; +use sodiumoxide::crypto::box_::{PublicKey, SecretKey}; + +use crate::Result; + +// Re-export types needed by downstream crates (oidc-bff, auth-daemon) +pub use reqwest::Client as HttpClient; +pub use sea_orm::DatabaseConnection as DbConnection; +pub use sodiumoxide::crypto::box_::PublicKey as SodiumPublicKey; + +pub async fn create_db_connection(config: &CommonConfig) -> Result { + let database_url = format!( + "postgres://{}:{}@{}:{}/{}", + config.postgres_user, + config.postgres_password, + config.postgres_hostname, + config.postgres_port, + config.postgres_database + ); + Database::connect(&database_url).await.map_err(Into::into) +} + +pub type OidcClient = CoreClient< + EndpointSet, + EndpointNotSet, + EndpointNotSet, + EndpointNotSet, + EndpointMaybeSet, + EndpointMaybeSet, +>; + +pub async fn create_oidc_client(config: &CommonConfig) -> Result<(OidcClient, reqwest::Client)> { + let http_client = reqwest::ClientBuilder::new() + // Following redirects opens the client up to SSRF vulnerabilities. + .redirect(reqwest::redirect::Policy::none()) + .build()?; + + // Use OpenID Connect Discovery to fetch the provider metadata. + let provider_metadata = CoreProviderMetadata::discover_async( + IssuerUrl::new(config.oidc_provider_url.to_string())?, + &http_client, + ) + .await?; + + let oidc_client = CoreClient::from_provider_metadata( + provider_metadata, + ClientId::new(config.client_id.to_string()), + if config.client_secret.is_empty() { + None + } else { + Some(ClientSecret::new(config.client_secret.to_string())) + }, + ); + Ok((oidc_client, http_client)) +} + +pub fn decode_public_key(base64_key: &str) -> Result { + Ok(PublicKey::from_slice(&BASE64.decode(base64_key)?).ok_or(anyhow!("Invalid public key"))?) +} + +pub fn decode_secret_key(base64_key: &str) -> Result { + Ok(SecretKey::from_slice(&BASE64.decode(base64_key)?).ok_or(anyhow!("Invalid secret key"))?) +} + +pub async fn exchange_refresh_token( + oidc_client: &OidcClient, + http_client: &reqwest::Client, + refresh_token: &RefreshToken, +) -> Result { + let token_response = oidc_client + .exchange_refresh_token(refresh_token)? + .request_async(http_client) + .await?; + Ok(token_response) +} From 0afc2b5463b9af2b8e89aee0d34b672aa955670c Mon Sep 17 00:00:00 2001 From: TBThomas56 Date: Mon, 30 Mar 2026 13:14:41 +0100 Subject: [PATCH 08/20] feat(backend): common database module --- backend/Cargo.lock | 1 + backend/auth-core/Cargo.toml | 1 + backend/auth-core/src/database.rs | 139 ++++++++++++++++++++++++++++++ backend/auth-core/src/lib.rs | 4 +- 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 backend/auth-core/src/database.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 22817a9d8..42733d9a7 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -427,6 +427,7 @@ dependencies = [ "sodiumoxide", "thiserror 2.0.17", "tokio", + "tracing", ] [[package]] diff --git a/backend/auth-core/Cargo.toml b/backend/auth-core/Cargo.toml index 3391a7407..b6fd2dbe8 100644 --- a/backend/auth-core/Cargo.toml +++ b/backend/auth-core/Cargo.toml @@ -30,3 +30,4 @@ serde_yaml = "0.9.34" sodiumoxide = "0.2.7" thiserror = { workspace = true } tokio = { workspace = true, features = ["full"] } +tracing = { workspace = true } diff --git a/backend/auth-core/src/database.rs b/backend/auth-core/src/database.rs new file mode 100644 index 000000000..7bf362125 --- /dev/null +++ b/backend/auth-core/src/database.rs @@ -0,0 +1,139 @@ +use chrono::{DateTime, Duration, FixedOffset, Utc}; +use openidconnect::SubjectIdentifier; +use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set, sea_query}; +use sodiumoxide::crypto::box_::{PublicKey, SecretKey}; +use tracing::info; + +use crate::Result; +use crate::entity; + +pub trait RefreshTokenInfo { + fn refresh_token_secret(&self) -> &str; + fn issuer(&self) -> &str; + fn subject(&self) -> &str; +} + +pub struct StoredToken { + pub issuer: String, + pub subject: String, + pub refresh_token_secret: String, +} + +pub async fn migrate_database(connection: &DatabaseConnection) -> Result<()> { + use migration::{Migrator, MigratorTrait}; + + Migrator::up(connection, None).await?; + Ok(()) +} + +pub async fn read_token_from_database( + connection: &DatabaseConnection, + subject: &SubjectIdentifier, + issuer: Option<&str>, + public_key: &PublicKey, + secret_key: &SecretKey, +) -> Result { + info!(subject = subject.as_str(), "Fetching token from database"); + // Build query: filter by Subject (and Issuer if provided) + let mut query = entity::oidc_tokens::Entity::find() + .filter(entity::oidc_tokens::Column::Subject.eq(subject.as_str())); + + if let Some(iss) = issuer { + query = query.filter(entity::oidc_tokens::Column::Issuer.eq(iss)); + } + + let row = query.one(connection).await?.ok_or_else(|| { + anyhow::anyhow!( + "No token row found for subject='{}' issuer={:?}", + subject.as_str(), + issuer + ) + })?; + + // Decrypt sealed box + let ciphertext = row.encrypted_refresh_token; + let decrypted = sodiumoxide::crypto::sealedbox::open(&ciphertext, public_key, secret_key) + .map_err(|_| anyhow::anyhow!("Unable to decrypt refresh token (sealedbox::open failed)"))?; + + // Check when token expires + let expires_at_utc = match row.expires_at { + Some(dt) => to_utc(dt), + None => { + // If not stored, decide on a policy: here we treat as "no expiry" + // You can choose to error instead. + Utc::now() + } + }; + if expires_at_utc < Utc::now() { + Err(anyhow::anyhow!( + "Stored refresh token has expired at {}", + expires_at_utc + ))?; + } + + // Return Stored Token + let stored = StoredToken { + issuer: row.issuer, + subject: row.subject, + refresh_token_secret: String::from_utf8(decrypted)?, + }; + + info!( + subject = stored.subject.as_str(), + "Fetched token from database successfully" + ); + Ok(stored) +} + +pub async fn write_token_to_database( + connection: &DatabaseConnection, + token: &impl RefreshTokenInfo, + public_key: &PublicKey, +) -> Result<()> { + let encrypted_refresh_token = + sodiumoxide::crypto::sealedbox::seal(token.refresh_token_secret().as_bytes(), public_key); + let refresh_token_expires_at = Utc::now() + Duration::days(30); // TODO: offline_access tokens will expire if not used within 30 days. Keycloak returns the actual expiration date in the field "refresh_expires_in", we should use that + let token_update = entity::oidc_tokens::ActiveModel { + issuer: Set(token.issuer().to_string()), + subject: Set(token.subject().to_string()), + encrypted_refresh_token: Set(encrypted_refresh_token), + expires_at: Set(Some(convert_time(refresh_token_expires_at))), + created_at: Set(Utc::now().into()), + updated_at: Set(Utc::now().into()), + }; + entity::oidc_tokens::Entity::insert(token_update) + .on_conflict( + sea_query::OnConflict::column(entity::oidc_tokens::Column::Subject) + .update_columns([ + entity::oidc_tokens::Column::Issuer, + entity::oidc_tokens::Column::Subject, + entity::oidc_tokens::Column::EncryptedRefreshToken, + entity::oidc_tokens::Column::ExpiresAt, + entity::oidc_tokens::Column::UpdatedAt, + // deliberately do not update CreatedAt + ]) + .to_owned(), + ) + .exec(connection) + .await?; + Ok(()) +} + +pub async fn delete_token_from_database( + connection: &DatabaseConnection, + subject: &SubjectIdentifier, +) -> Result<()> { + entity::oidc_tokens::Entity::delete_many() + .filter(entity::oidc_tokens::Column::Subject.eq(subject.as_str())) + .exec(connection) + .await?; + Ok(()) +} + +fn convert_time(utc_time: DateTime) -> DateTime { + utc_time.with_timezone(&FixedOffset::east_opt(0).unwrap()) +} + +fn to_utc(dt: DateTime) -> DateTime { + dt.with_timezone(&Utc) +} diff --git a/backend/auth-core/src/lib.rs b/backend/auth-core/src/lib.rs index 7c54baec6..36c82ebf0 100644 --- a/backend/auth-core/src/lib.rs +++ b/backend/auth-core/src/lib.rs @@ -1,8 +1,8 @@ +pub mod config; +pub mod database; pub mod entity; pub mod error; pub mod healthcheck; -pub mod config; pub mod oidc; pub type Result = std::result::Result; - From 50ca1ef5cbcc7d18749120df5d0801dafbc24493 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Tue, 31 Mar 2026 00:22:52 +0000 Subject: [PATCH 09/20] feat(backend): auth-core request helpers --- backend/auth-core/src/lib.rs | 1 + backend/auth-core/src/request.rs | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 backend/auth-core/src/request.rs diff --git a/backend/auth-core/src/lib.rs b/backend/auth-core/src/lib.rs index 36c82ebf0..bc19a0725 100644 --- a/backend/auth-core/src/lib.rs +++ b/backend/auth-core/src/lib.rs @@ -4,5 +4,6 @@ pub mod entity; pub mod error; pub mod healthcheck; pub mod oidc; +pub mod request; pub type Result = std::result::Result; diff --git a/backend/auth-core/src/request.rs b/backend/auth-core/src/request.rs new file mode 100644 index 000000000..e3f257637 --- /dev/null +++ b/backend/auth-core/src/request.rs @@ -0,0 +1,25 @@ +use axum::{ + body::Body, + extract::Request, + http::{self, HeaderValue}, +}; + +use crate::Result; + +pub async fn clone_request(req: Request) -> Result<(Request, Request)> { + // TODO: an inefficient method of cloning a request, improve this + let (parts, body) = req.into_parts(); + let bytes = http_body_util::BodyExt::collect(body).await?.to_bytes(); + let req1 = Request::from_parts(parts.clone(), Body::from(bytes.clone())); + let req2 = Request::from_parts(parts, Body::from(bytes)); + Ok((req1, req2)) +} + +pub fn prepare_headers(req: &mut Request, bearer_token: &str) { + let value = format!("Bearer {}", bearer_token); + req.headers_mut().insert( + http::header::AUTHORIZATION, + HeaderValue::from_str(&value).unwrap(), + ); + req.headers_mut().remove(http::header::COOKIE); +} From 1f9a1271d200bd3ced338d221e9526891b1680a4 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Tue, 31 Mar 2026 01:08:42 +0000 Subject: [PATCH 10/20] feat(backend): auth-core middleware creation --- backend/Cargo.lock | 5 +- backend/auth-core/Cargo.toml | 1 + backend/auth-core/src/lib.rs | 1 + .../auth-core/src/middleware/inject_token.rs | 53 +++++++++++++++++++ backend/auth-core/src/middleware/mod.rs | 2 + backend/auth-core/src/middleware/traits.rs | 25 +++++++++ 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 backend/auth-core/src/middleware/inject_token.rs create mode 100644 backend/auth-core/src/middleware/mod.rs create mode 100644 backend/auth-core/src/middleware/traits.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 42733d9a7..8c198eb2a 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -383,9 +383,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", @@ -412,6 +412,7 @@ name = "auth-core" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "axum", "base64 0.22.1", "chrono", diff --git a/backend/auth-core/Cargo.toml b/backend/auth-core/Cargo.toml index b6fd2dbe8..13fec80d4 100644 --- a/backend/auth-core/Cargo.toml +++ b/backend/auth-core/Cargo.toml @@ -15,6 +15,7 @@ publish = false [dependencies] anyhow = { workspace = true, features = ["backtrace"] } +async-trait = "0.1.89" axum = { workspace = true, features = ["macros"] } base64 = "0.22.1" chrono = { workspace = true } diff --git a/backend/auth-core/src/lib.rs b/backend/auth-core/src/lib.rs index bc19a0725..fe93c10ef 100644 --- a/backend/auth-core/src/lib.rs +++ b/backend/auth-core/src/lib.rs @@ -5,5 +5,6 @@ pub mod error; pub mod healthcheck; pub mod oidc; pub mod request; +pub mod middleware; pub type Result = std::result::Result; diff --git a/backend/auth-core/src/middleware/inject_token.rs b/backend/auth-core/src/middleware/inject_token.rs new file mode 100644 index 000000000..0610dc658 --- /dev/null +++ b/backend/auth-core/src/middleware/inject_token.rs @@ -0,0 +1,53 @@ +use std::sync::Arc; +use axum::{ + body::Body, + extract::{Request, State}, + middleware, + response::IntoResponse, +}; +use http_body_util::BodyExt; + +use crate::Result; +use crate::request::{clone_request, prepare_headers}; +use super::traits::{TokenStore, TokenInspector, RetryPolicy}; + +pub async fn inject_token( + State(store): State>, + req: Request, + next: middleware::Next, +) -> Result +where + S: TokenStore + RetryPolicy, +{ + let token = store.load_token().await; + if let Some(mut token) = token { + if token.is_expired() { + token = store.refresh_and_persist(&token).await?; + } + + let (mut primary_req, mut retry_req) = clone_request(req).await?; + + if let Some(bearer) = token.bearer_value() { + prepare_headers(&mut primary_req, &bearer); + } + + let response = next.clone().run(primary_req).await; + + let (response_parts, response_body) = response.into_parts(); + let response_bytes = response_body.collect().await + .map_err(|e| anyhow::anyhow!("collect body error: {e}"))? + .to_bytes(); + + if store.should_retry(response_parts.status, &response_bytes) { + token = store.refresh_and_persist(&token).await?; + if let Some(bearer) = token.bearer_value() { + prepare_headers(&mut retry_req, &bearer); + } + Ok(next.run(retry_req).await) + } else { + Ok(axum::response::Response::from_parts(response_parts, Body::from(response_bytes)).into_response()) + } + } else { + Ok(next.run(req).await) + } +} \ No newline at end of file diff --git a/backend/auth-core/src/middleware/mod.rs b/backend/auth-core/src/middleware/mod.rs new file mode 100644 index 000000000..751ff6394 --- /dev/null +++ b/backend/auth-core/src/middleware/mod.rs @@ -0,0 +1,2 @@ +pub mod inject_token; +pub mod traits; diff --git a/backend/auth-core/src/middleware/traits.rs b/backend/auth-core/src/middleware/traits.rs new file mode 100644 index 000000000..2973e4611 --- /dev/null +++ b/backend/auth-core/src/middleware/traits.rs @@ -0,0 +1,25 @@ +use async_trait::async_trait; +use axum::http::StatusCode; + +use crate::Result; + +// How tokens ore loaded, saved and refreshed +#[async_trait] +pub trait TokenStore: Send + Sync { + type Token: TokenInspector + Send + Sync + Clone; + + async fn load_token(&self) -> Option; + async fn save_token(&self, token: &Self::Token) -> Result<()>; + async fn refresh_and_persist(&self, token: &Self::Token) -> Result; +} + +//How to inspect a token's state +pub trait TokenInspector { + fn is_expired(&self) -> bool; + fn bearer_value(&self) -> Option; +} + +// Whether to retry after a response +pub trait RetryPolicy: Send + Sync { + fn should_retry(&self, status: StatusCode, body: &[u8]) -> bool; +} From 0abe6533ca558e1ed27ce50bae3fbf09a528b2be Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Fri, 10 Apr 2026 01:04:57 +0000 Subject: [PATCH 11/20] fix(backend): modify oidc-bff to use auth-core --- backend/Cargo.toml | 1 + backend/auth-core/Cargo.toml | 2 +- backend/oidc-bff/Cargo.toml | 15 +- backend/oidc-bff/src/auth_session_data.rs | 13 +- backend/oidc-bff/src/bin/keygen.rs | 6 +- backend/oidc-bff/src/callback.rs | 9 +- backend/oidc-bff/src/config.rs | 29 +--- backend/oidc-bff/src/database.rs | 65 -------- backend/oidc-bff/src/entity/mod.rs | 5 - backend/oidc-bff/src/entity/oidc_tokens.rs | 22 --- backend/oidc-bff/src/entity/prelude.rs | 3 - backend/oidc-bff/src/error.rs | 26 --- backend/oidc-bff/src/healthcheck.rs | 5 - .../oidc-bff/src/inject_token_from_session.rs | 87 ---------- backend/oidc-bff/src/lib.rs | 1 - backend/oidc-bff/src/login.rs | 6 +- backend/oidc-bff/src/main.rs | 74 +++++---- backend/oidc-bff/src/state.rs | 151 +++++++++++------- 18 files changed, 162 insertions(+), 358 deletions(-) delete mode 100644 backend/oidc-bff/src/database.rs delete mode 100644 backend/oidc-bff/src/entity/mod.rs delete mode 100644 backend/oidc-bff/src/entity/oidc_tokens.rs delete mode 100644 backend/oidc-bff/src/entity/prelude.rs delete mode 100644 backend/oidc-bff/src/error.rs delete mode 100644 backend/oidc-bff/src/healthcheck.rs delete mode 100644 backend/oidc-bff/src/inject_token_from_session.rs delete mode 100644 backend/oidc-bff/src/lib.rs diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 5bb7d93d1..175078a51 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -12,6 +12,7 @@ members = [ resolver = "2" [workspace.dependencies] +async-trait = { version = "0.1.89" } anyhow = { version = "1.0.100" } clap = { version = "4.5.49", features = ["derive", "env"] } chrono = { version = "0.4.42" } diff --git a/backend/auth-core/Cargo.toml b/backend/auth-core/Cargo.toml index 13fec80d4..9f970431d 100644 --- a/backend/auth-core/Cargo.toml +++ b/backend/auth-core/Cargo.toml @@ -15,7 +15,7 @@ publish = false [dependencies] anyhow = { workspace = true, features = ["backtrace"] } -async-trait = "0.1.89" +async-trait = {workspace = true } axum = { workspace = true, features = ["macros"] } base64 = "0.22.1" chrono = { workspace = true } diff --git a/backend/oidc-bff/Cargo.toml b/backend/oidc-bff/Cargo.toml index c87214843..a4b0e43e8 100644 --- a/backend/oidc-bff/Cargo.toml +++ b/backend/oidc-bff/Cargo.toml @@ -4,17 +4,14 @@ version = "0.1.0" edition = "2024" default-run = "oidc-bff" -[lib] -name = "oidc_bff" # the library name as used in code: `use oidc_bff::...` -path = "src/lib.rs" - - [[bin]] name = "keygen" path = "src/bin/keygen.rs" publish = false [dependencies] +async-trait = {workspace = true } +auth-core = { path = "../auth-core" } anyhow = { workspace = true, features = ["backtrace"] } axum = { workspace = true, features = ["macros"] } axum-reverse-proxy = "1.0.3" @@ -22,18 +19,10 @@ bytes = "1.11.0" chrono.workspace = true clap.workspace = true dotenvy.workspace = true -http-body-util = "0.1.3" hyper = "1.8.1" moka = { version = "0.12.11", features = ["future"] } -oauth2 = "5.0.0" -openidconnect = { version = "4.0.1", features = ["timing-resistant-secret-traits"]} -rustls = { version = "0.23.35", features = ["ring"] } serde.workspace = true serde_json.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["full"] } tower-sessions = "0.14.0" -sea-orm = {workspace=true} -sodiumoxide = "0.2.7" -base64 = "0.22.1" -serde_yaml = "0.9.34" diff --git a/backend/oidc-bff/src/auth_session_data.rs b/backend/oidc-bff/src/auth_session_data.rs index a3efc4a7b..3bedb8823 100644 --- a/backend/oidc-bff/src/auth_session_data.rs +++ b/backend/oidc-bff/src/auth_session_data.rs @@ -2,11 +2,10 @@ use std::time::Duration; use crate::Result; use anyhow::anyhow; -use chrono::{DateTime, Utc}; -use openidconnect::{ - AccessToken, CsrfToken, IssuerUrl, Nonce, PkceCodeVerifier, - RefreshToken, SubjectIdentifier, +use auth_core::openidconnect::{ + AccessToken, CsrfToken, IssuerUrl, Nonce, PkceCodeVerifier, RefreshToken, SubjectIdentifier, }; +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] @@ -44,7 +43,7 @@ impl TokenSessionData { } } - pub fn from_token_response( + pub fn from_token_response( token_response: &T, issuer: IssuerUrl, subject: SubjectIdentifier, @@ -67,7 +66,7 @@ impl TokenSessionData { )) } - pub fn update_tokens_mut(&mut self, token_response: &T) { + pub fn update_tokens_mut(&mut self, token_response: &T) { let access_token = token_response.access_token().clone(); let refresh_token = token_response.refresh_token(); let access_token_expires_at = Utc::now() @@ -81,7 +80,7 @@ impl TokenSessionData { self.access_token_expires_at = access_token_expires_at; } - pub fn update_tokens(&self, token_response: &T) -> Self { + pub fn update_tokens(&self, token_response: &T) -> Self { let mut clone = self.clone(); clone.update_tokens_mut(token_response); clone diff --git a/backend/oidc-bff/src/bin/keygen.rs b/backend/oidc-bff/src/bin/keygen.rs index a49b24626..865c487e7 100644 --- a/backend/oidc-bff/src/bin/keygen.rs +++ b/backend/oidc-bff/src/bin/keygen.rs @@ -1,9 +1,9 @@ -use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; -use sodiumoxide::crypto::box_::gen_keypair; +use auth_core::base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use auth_core::sodiumoxide::crypto::box_::gen_keypair; fn main() { // Initialize sodiumoxide (required before using crypto functions) - if sodiumoxide::init().is_err() { + if auth_core::sodiumoxide::init().is_err() { eprintln!("Failed to initialize libsodium"); std::process::exit(1); } diff --git a/backend/oidc-bff/src/callback.rs b/backend/oidc-bff/src/callback.rs index c3b405c44..9df97b960 100644 --- a/backend/oidc-bff/src/callback.rs +++ b/backend/oidc-bff/src/callback.rs @@ -1,19 +1,18 @@ use std::borrow::Cow; use std::sync::Arc; +use auth_core::openidconnect::{ + AccessTokenHash, AuthorizationCode, CsrfToken, OAuth2TokenResponse, RedirectUrl, TokenResponse, +}; use axum::debug_handler; use axum::extract::{Query, State}; -use openidconnect::{ - AccessTokenHash, AuthorizationCode,CsrfToken, - OAuth2TokenResponse, RedirectUrl, TokenResponse, -}; use serde::{Deserialize, Serialize}; use tower_sessions::Session; use crate::Result; use crate::auth_session_data::{LoginSessionData, TokenSessionData}; -use crate::database::write_token_to_database; use crate::state::AppState; +use auth_core::database::write_token_to_database; #[derive(Serialize, Deserialize)] pub struct CallbackQuery { diff --git a/backend/oidc-bff/src/config.rs b/backend/oidc-bff/src/config.rs index f2c58a390..dcd5d2bae 100644 --- a/backend/oidc-bff/src/config.rs +++ b/backend/oidc-bff/src/config.rs @@ -1,32 +1,19 @@ -use std::path::Path; - use crate::Result; +use auth_core::config::{self, CommonConfig}; use serde::Deserialize; use serde::Serialize; +use std::path::Path; #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Config { - pub client_id: String, - pub client_secret: String, - pub oidc_provider_url: String, - pub port: u16, - pub postgres_user: String, - pub postgres_password: String, - pub postgres_database: String, - pub postgres_hostname: String, - pub postgres_port: u16, - pub encryption_public_key: String, - pub encryption_private_key: String, +pub struct GatewayConfig { + #[serde(flatten)] + pub common: CommonConfig, + // Can add extra fields in future if necessary } -impl Config { +impl GatewayConfig { /// Load config from JSON or YAML file pub fn from_file>(path: P) -> Result { - let content = std::fs::read_to_string(&path)?; - match path.as_ref().extension().and_then(|e| e.to_str()) { - Some("json") => Ok(serde_json::from_str(&content)?), - // otherwise assume yaml - _ => Ok(serde_yaml::from_str(&content)?), - } + config::load_config_from_file(path) } } diff --git a/backend/oidc-bff/src/database.rs b/backend/oidc-bff/src/database.rs deleted file mode 100644 index cfe20faf3..000000000 --- a/backend/oidc-bff/src/database.rs +++ /dev/null @@ -1,65 +0,0 @@ -use chrono::{DateTime, Duration, FixedOffset, Utc}; -//use sea_orm::{ActiveModelTrait, DatabaseConnection, Query}; -use crate::{Result, auth_session_data::TokenSessionData}; -use sea_orm::*; -use oidc_bff::entity; -use openidconnect::SubjectIdentifier; - -pub async fn migrate_database(connection: &DatabaseConnection) -> Result<()> { - use migration::{Migrator, MigratorTrait}; - - Migrator::up(connection, None).await?; - Ok(()) -} - -/// Delete a user's token from the database by subject identifier. -/// This is called during logout to revoke workflow access. -pub async fn delete_token_from_database( - connection: &DatabaseConnection, - subject: &SubjectIdentifier, -) -> Result<()> { - entity::oidc_tokens::Entity::delete_many() - .filter(entity::oidc_tokens::Column::Subject.eq(subject.as_str())) - .exec(connection) - .await?; - Ok(()) -} - -pub async fn write_token_to_database( - connection: &DatabaseConnection, - token: &TokenSessionData, - public_key: &sodiumoxide::crypto::box_::PublicKey, -) -> Result<()> { - let encrypted_refresh_token = - sodiumoxide::crypto::sealedbox::seal(token.refresh_token.secret().as_bytes(), public_key); - let refresh_token_expires_at = Utc::now() + Duration::days(30); // TODO: offline_access tokens will expire if not used within 30 days. Keycloak returns the actual expiration date in the field "refresh_expires_in", we should use that - let token_update = entity::oidc_tokens::ActiveModel { - issuer: Set(token.issuer.to_string()), - subject: Set(token.subject.to_string()), - encrypted_refresh_token: Set(encrypted_refresh_token), - expires_at: Set(Some(convert_time(refresh_token_expires_at))), - created_at: Set(Utc::now().into()), - updated_at: Set(Utc::now().into()), - ..Default::default() - }; - entity::oidc_tokens::Entity::insert(token_update) - .on_conflict( - sea_query::OnConflict::column(entity::oidc_tokens::Column::Subject) - .update_columns([ - entity::oidc_tokens::Column::Issuer, - entity::oidc_tokens::Column::Subject, - entity::oidc_tokens::Column::EncryptedRefreshToken, - entity::oidc_tokens::Column::ExpiresAt, - entity::oidc_tokens::Column::UpdatedAt, - // deliberately do not update CreatedAt - ]) - .to_owned(), - ) - .exec(connection) - .await?; - Ok(()) -} - -fn convert_time(utc_time: DateTime) -> DateTime { - utc_time.with_timezone(&FixedOffset::east_opt(0).unwrap()) -} diff --git a/backend/oidc-bff/src/entity/mod.rs b/backend/oidc-bff/src/entity/mod.rs deleted file mode 100644 index 889654a14..000000000 --- a/backend/oidc-bff/src/entity/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 - -pub mod prelude; - -pub mod oidc_tokens; diff --git a/backend/oidc-bff/src/entity/oidc_tokens.rs b/backend/oidc-bff/src/entity/oidc_tokens.rs deleted file mode 100644 index 23ee74526..000000000 --- a/backend/oidc-bff/src/entity/oidc_tokens.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "oidc_tokens")] -pub struct Model { - #[sea_orm(column_type = "Text")] - pub issuer: String, - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub subject: String, - #[sea_orm(column_type = "VarBinary(StringLen::None)")] - pub encrypted_refresh_token: Vec, - pub expires_at: Option, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/backend/oidc-bff/src/entity/prelude.rs b/backend/oidc-bff/src/entity/prelude.rs deleted file mode 100644 index b303a78d8..000000000 --- a/backend/oidc-bff/src/entity/prelude.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19 - -pub use super::oidc_tokens::Entity as OidcTokens; diff --git a/backend/oidc-bff/src/error.rs b/backend/oidc-bff/src/error.rs deleted file mode 100644 index a944ebb41..000000000 --- a/backend/oidc-bff/src/error.rs +++ /dev/null @@ -1,26 +0,0 @@ -use axum::{ - http::StatusCode, - response::{IntoResponse, Response}, -}; - -#[derive(Debug)] -pub struct Error(anyhow::Error); - -impl IntoResponse for Error { - fn into_response(self) -> Response { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Something went wrong: {}", self.0), - ) - .into_response() - } -} - -impl From for Error -where - E: Into, -{ - fn from(err: E) -> Self { - Self(err.into()) - } -} diff --git a/backend/oidc-bff/src/healthcheck.rs b/backend/oidc-bff/src/healthcheck.rs deleted file mode 100644 index c9be25c8a..000000000 --- a/backend/oidc-bff/src/healthcheck.rs +++ /dev/null @@ -1,5 +0,0 @@ -use axum::http::StatusCode; - -pub async fn healthcheck() -> StatusCode { - StatusCode::ACCEPTED -} diff --git a/backend/oidc-bff/src/inject_token_from_session.rs b/backend/oidc-bff/src/inject_token_from_session.rs deleted file mode 100644 index 2a1a9bc3a..000000000 --- a/backend/oidc-bff/src/inject_token_from_session.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::{database::write_token_to_database, state::AppState}; -// use openidconnect::{ -// ClientId, ClientSecret, IssuerUrl, TokenResponse, -// core::{CoreClient, CoreProviderMetadata}, -// reqwest, -// }; -use std::sync::Arc; -use tower_sessions::Session; - -use axum::{ - body::Body, - extract::{Request, State}, - http::{self, HeaderValue, StatusCode}, - middleware, -}; - -use crate::Result; - -use crate::auth_session_data::TokenSessionData; - -pub async fn inject_token_from_session( - State(state): State>, - session: Session, - req: Request, - next: middleware::Next, -) -> Result { - // Read token from session - let token: Option = session.get(TokenSessionData::SESSION_KEY).await?; - if let Some(mut token) = token { - if token.access_token_is_expired() { - token = refresh_token_and_update_session(&state, &token, &session).await?; - } - let mut req = clone_request(req).await?; - prepare_headers(&mut req.0, &token); - let response = next.clone().run(req.0).await; - if response.status() == StatusCode::UNAUTHORIZED { - token = refresh_token_and_update_session(&state, &token, &session).await?; - prepare_headers(&mut req.1, &token); - Ok(next.run(req.1).await) - } else { - Ok(response) - } - } else { - Ok(next.run(req).await) - } -} - -async fn clone_request(req: Request) -> Result<(Request, Request)> { - // TODO: an inefficient method of cloning a request, improve this - let (parts, body) = req.into_parts(); - let bytes = http_body_util::BodyExt::collect(body).await?.to_bytes(); - let req1 = Request::from_parts(parts.clone(), Body::from(bytes.clone())); - let req2 = Request::from_parts(parts, Body::from(bytes)); - Ok((req1, req2)) -} - -fn prepare_headers(req: &mut Request, token: &TokenSessionData) { - let value = format!("Bearer {}", token.access_token.secret()); - req.headers_mut().insert( - http::header::AUTHORIZATION, - HeaderValue::from_str(&value).unwrap(), - ); - req.headers_mut().remove(http::header::COOKIE); -} - -async fn refresh_token_and_update_session( - state: &AppState, - token: &TokenSessionData, - session: &Session, -) -> Result { - let token = refresh_token(state, token).await?; - write_token_to_database(&state.database_connection, &token, &state.public_key).await?; - session - .insert(TokenSessionData::SESSION_KEY, token.clone()) - .await?; - Ok(token) -} - -async fn refresh_token(state: &AppState, token: &TokenSessionData) -> Result { - let token_response = state - .oidc_client - .exchange_refresh_token(&token.refresh_token)? - .request_async(&state.http_client) - .await?; - let token = token.update_tokens(&token_response); - Ok(token) -} diff --git a/backend/oidc-bff/src/lib.rs b/backend/oidc-bff/src/lib.rs deleted file mode 100644 index bccca666a..000000000 --- a/backend/oidc-bff/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod entity; \ No newline at end of file diff --git a/backend/oidc-bff/src/login.rs b/backend/oidc-bff/src/login.rs index 7ed99fb98..ae3d72d48 100644 --- a/backend/oidc-bff/src/login.rs +++ b/backend/oidc-bff/src/login.rs @@ -1,11 +1,9 @@ use std::sync::Arc; +use auth_core::openidconnect::core::CoreAuthenticationFlow; +use auth_core::openidconnect::{CsrfToken, Nonce, PkceCodeChallenge, RedirectUrl, Scope}; use axum::extract::State; use axum::response::Redirect; -use openidconnect::core::CoreAuthenticationFlow; -use openidconnect::{ - CsrfToken, Nonce, PkceCodeChallenge, RedirectUrl, Scope, -}; use tower_sessions::Session; use crate::Result; diff --git a/backend/oidc-bff/src/main.rs b/backend/oidc-bff/src/main.rs index d302328fb..9cd5d06e6 100644 --- a/backend/oidc-bff/src/main.rs +++ b/backend/oidc-bff/src/main.rs @@ -1,34 +1,33 @@ -mod healthcheck; +mod auth_session_data; +mod callback; mod config; mod login; -mod auth_session_data; mod state; -mod callback; -mod database; -mod error; +use auth_core::middleware::inject_token::inject_token_with; use clap::Parser; -use config::Config; -use tower_sessions::{MemoryStore, Session, SessionManagerLayer}; +use config::GatewayConfig; +use state::{AppState, GatewayTokenContext}; use std::{ - net::{Ipv4Addr, SocketAddr}, process, sync::Arc, + net::{Ipv4Addr, SocketAddr}, + process, + sync::Arc, }; -use state::AppState; +use tower_sessions::{MemoryStore, Session, SessionManagerLayer}; -type Result = std::result::Result; +type Result = std::result::Result; use axum::{ Router, - extract::State, + extract::{Request, State}, middleware, response::IntoResponse, routing::{get, post}, }; use axum_reverse_proxy::ReverseProxy; -use tokio::signal::unix::{signal, Signal, SignalKind}; +use tokio::signal::unix::{Signal, SignalKind, signal}; use crate::auth_session_data::TokenSessionData; -mod inject_token_from_session; #[derive(Parser, Debug)] #[command(author, version, about)] @@ -42,48 +41,52 @@ struct Args { default_value = "config.yaml" )] config: String, + #[arg( + env = "GRAPH_URL", + default_value = "https://staging.workflows.diamond.ac.uk/graphql" + )] + graph_url: String, } #[tokio::main] async fn main() -> Result<()> { dotenvy::dotenv().ok(); let args: Args = Args::try_parse()?; - let config = Config::from_file(args.config)?; - let port = config.port; + let graph_url = args.graph_url; + let config = GatewayConfig::from_file(args.config)?; + let port = config.common.port; let appstate = Arc::new(AppState::new(config).await?); - database::migrate_database(&appstate.database_connection).await?; + auth_core::database::migrate_database(&appstate.database_connection).await?; - rustls::crypto::ring::default_provider() + auth_core::rustls::crypto::ring::default_provider() .install_default() .expect("Failed to install rust TLS cryptography"); - let router = create_router(appstate); + let router = create_router(appstate, graph_url); serve(router, port).await } -fn create_router(state: Arc) -> Router { +fn create_router(state: Arc, graph_url: String) -> Router { let session_store = MemoryStore::default(); let session_layer = SessionManagerLayer::new(session_store) .with_secure(false) // .with_expiry(Expiry::OnInactivity(Duration::seconds(600))) ; - let proxy: Router<()> = - ReverseProxy::new("/", "https://staging.workflows.diamond.ac.uk/graphql").into(); + let proxy: Router<()> = ReverseProxy::new("/", &graph_url).into(); let proxy = proxy; Router::new() .fallback_service(proxy) .layer(middleware::from_fn_with_state( state.clone(), - inject_token_from_session::inject_token_from_session, + gateway_inject_token, )) .route("/auth/login", get(login::login)) .route("/auth/callback", get(callback::callback)) .route("/auth/logout", post(logout)) - // .route("/debug", get(debug)) - .route("/healthcheck", get(healthcheck::healthcheck)) + .route("/healthcheck", get(auth_core::healthcheck::healthcheck)) .layer(session_layer) .with_state(state) } @@ -93,8 +96,8 @@ async fn serve(router: Router, port: u16) -> Result<()> { tokio::net::TcpListener::bind(SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port)).await?; let service = router.into_make_service(); axum::serve(listener, service) - .with_graceful_shutdown(shutdown_signal()) - .await?; + .with_graceful_shutdown(shutdown_signal()) + .await?; Ok(()) } @@ -102,17 +105,14 @@ async fn serve(router: Router, port: u16) -> Result<()> { /// 1. Retrieves the user's token from the session (to get subject ID) /// 2. Deletes the token from the database (so workflows can't use it) /// 3. Clears the session (so browser requests are no longer authenticated) -async fn logout( - State(state): State>, - session: Session, -) -> Result { +async fn logout(State(state): State>, session: Session) -> Result { // Get the token data to find the subject for database deletion let token_session_data: Option = session.get(TokenSessionData::SESSION_KEY).await?; // If we have token data, delete it from the database if let Some(token_data) = token_session_data { - database::delete_token_from_database( + auth_core::database::delete_token_from_database( &state.database_connection, &token_data.subject, ) @@ -126,9 +126,19 @@ async fn logout( } async fn shutdown_signal() { - let mut sigterm: Signal = signal(SignalKind::terminate()).expect("Failed to listen for SIGTERM"); + let mut sigterm: Signal = + signal(SignalKind::terminate()).expect("Failed to listen for SIGTERM"); sigterm.recv().await; println!("Shutting Down"); process::exit(0); } +async fn gateway_inject_token( + State(state): State>, + session: Session, + req: Request, + next: middleware::Next, +) -> Result { + let ctx = GatewayTokenContext { state, session }; + inject_token_with(&ctx, req, next).await +} diff --git a/backend/oidc-bff/src/state.rs b/backend/oidc-bff/src/state.rs index d91d22719..db30c21d1 100644 --- a/backend/oidc-bff/src/state.rs +++ b/backend/oidc-bff/src/state.rs @@ -1,68 +1,32 @@ +use async_trait::async_trait; +use axum::http::StatusCode; +use std::sync::Arc; +use tower_sessions::Session; + use crate::Result; -use crate::config::Config; -use anyhow::anyhow; -use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; -use oauth2::{ClientId, ClientSecret, EndpointMaybeSet, EndpointNotSet, EndpointSet, reqwest}; -use openidconnect::IssuerUrl; -use openidconnect::core::{CoreClient, CoreProviderMetadata}; -use sea_orm::Database; -use sea_orm::DatabaseConnection; -use sodiumoxide::crypto::box_::PublicKey; +use crate::auth_session_data::TokenSessionData; +use crate::config::GatewayConfig; +use auth_core::database::{self, RefreshTokenInfo}; +use auth_core::middleware::traits::{RetryPolicy, TokenInspector, TokenStore}; +use auth_core::oidc::{ + DbConnection, HttpClient, OidcClient, SodiumPublicKey, create_db_connection, + create_oidc_client, decode_public_key, exchange_refresh_token, +}; + #[derive(Debug, Clone)] pub struct AppState { - // pub config: Config, - pub http_client: reqwest::Client, - pub oidc_client: openidconnect::core::CoreClient< - EndpointSet, - EndpointNotSet, - EndpointNotSet, - EndpointNotSet, - EndpointMaybeSet, - EndpointMaybeSet, - >, - pub database_connection: DatabaseConnection, - pub public_key: PublicKey, + pub http_client: HttpClient, + pub oidc_client: OidcClient, + pub database_connection: DbConnection, + pub public_key: SodiumPublicKey, } impl AppState { - pub async fn new(config: Config) -> Result { - let http_client = reqwest::ClientBuilder::new() - // Following redirects opens the client up to SSRF vulnerabilities. - .redirect(reqwest::redirect::Policy::none()) - .build()?; - - // Use OpenID Connect Discovery to fetch the provider metadata. - let provider_metadata = CoreProviderMetadata::discover_async( - IssuerUrl::new(config.oidc_provider_url.to_string())?, - &http_client, - ) - .await?; - - let oidc_client = CoreClient::from_provider_metadata( - provider_metadata, - ClientId::new(config.client_id.to_string()), - if config.client_secret.is_empty() { - None - } else { - Some(ClientSecret::new(config.client_secret.to_string())) - }, - ); - - let database_url = format!( - "postgres://{}:{}@{}:{}/{}", - config.postgres_user, - config.postgres_password, - config.postgres_hostname, - config.postgres_port, - config.postgres_database - ); - let database_connection = Database::connect(&database_url).await?; - - let public_key = PublicKey::from_slice(&BASE64.decode(&config.encryption_public_key)?) - .ok_or(anyhow!("Invalid public key"))?; - + pub async fn new(config: GatewayConfig) -> Result { + let (oidc_client, http_client) = create_oidc_client(&config.common).await?; + let database_connection = create_db_connection(&config.common).await?; + let public_key = decode_public_key(&config.common.encryption_public_key)?; Ok(AppState { - // config, http_client, oidc_client, database_connection, @@ -70,3 +34,74 @@ impl AppState { }) } } + +impl TokenInspector for TokenSessionData { + fn is_expired(&self) -> bool { + self.access_token_is_expired() + } + fn bearer_value(&self) -> Option { + Some(self.access_token.secret().to_string()) + } +} + +impl RefreshTokenInfo for TokenSessionData { + fn refresh_token_secret(&self) -> &str { + self.refresh_token.secret() + } + fn issuer(&self) -> &str { + self.issuer.as_str() + } + fn subject(&self) -> &str { + self.subject.as_str() + } +} + +pub struct GatewayTokenContext { + pub state: Arc, + pub session: Session, +} + +#[async_trait] +impl TokenStore for GatewayTokenContext { + type Token = TokenSessionData; + + async fn load_token(&self) -> Option { + self.session + .get(TokenSessionData::SESSION_KEY) + .await + .ok() + .flatten() + } + + async fn save_token(&self, token: &Self::Token) -> auth_core::Result<()> { + self.session + .insert(TokenSessionData::SESSION_KEY, token.clone()) + .await + .map_err(|e| anyhow::anyhow!("session insert error: {e}"))?; + Ok(()) + } + + async fn refresh_and_persist(&self, token: &Self::Token) -> auth_core::Result { + let token_response = exchange_refresh_token( + &self.state.oidc_client, + &self.state.http_client, + &token.refresh_token, + ) + .await?; + let new_token = token.update_tokens(&token_response); + database::write_token_to_database( + &self.state.database_connection, + &new_token, + &self.state.public_key, + ) + .await?; + self.save_token(&new_token).await?; + Ok(new_token) + } +} + +impl RetryPolicy for GatewayTokenContext { + fn should_retry(&self, status: StatusCode, _body: &[u8]) -> bool { + status == StatusCode::UNAUTHORIZED + } +} From 932b1ecd696a49af0bb024b1f5554221d64dc155 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Fri, 10 Apr 2026 01:56:17 +0000 Subject: [PATCH 12/20] fix(backend): export libraries from auth-core to dependants --- backend/auth-core/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/auth-core/src/lib.rs b/backend/auth-core/src/lib.rs index fe93c10ef..f3350b58f 100644 --- a/backend/auth-core/src/lib.rs +++ b/backend/auth-core/src/lib.rs @@ -3,8 +3,15 @@ pub mod database; pub mod entity; pub mod error; pub mod healthcheck; +pub mod middleware; pub mod oidc; pub mod request; -pub mod middleware; +pub use async_trait; +pub use base64; +pub use oauth2; +pub use openidconnect; +pub use rustls; +pub use sea_orm; +pub use sodiumoxide; pub type Result = std::result::Result; From d11636c0a05383796598fdf6fe38c2e27dfb1557 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Fri, 10 Apr 2026 01:56:52 +0000 Subject: [PATCH 13/20] fix(backend): modified auth-core inject token logic --- .../auth-core/src/middleware/inject_token.rs | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/backend/auth-core/src/middleware/inject_token.rs b/backend/auth-core/src/middleware/inject_token.rs index 0610dc658..2d5538838 100644 --- a/backend/auth-core/src/middleware/inject_token.rs +++ b/backend/auth-core/src/middleware/inject_token.rs @@ -1,21 +1,22 @@ -use std::sync::Arc; use axum::{ body::Body, extract::{Request, State}, middleware, - response::IntoResponse, }; use http_body_util::BodyExt; +use std::sync::Arc; +use super::traits::{RetryPolicy, TokenInspector, TokenStore}; use crate::Result; use crate::request::{clone_request, prepare_headers}; -use super::traits::{TokenStore, TokenInspector, RetryPolicy}; -pub async fn inject_token( - State(store): State>, +/// Core inject-token logic, usable by any caller that already has a store reference. +/// Use this when the store must be constructed per-request (e.g. BFF wrapping AppState + Session). +pub async fn inject_token_with( + store: &S, req: Request, next: middleware::Next, -) -> Result +) -> Result where S: TokenStore + RetryPolicy, { @@ -34,7 +35,9 @@ where let response = next.clone().run(primary_req).await; let (response_parts, response_body) = response.into_parts(); - let response_bytes = response_body.collect().await + let response_bytes = response_body + .collect() + .await .map_err(|e| anyhow::anyhow!("collect body error: {e}"))? .to_bytes(); @@ -45,9 +48,25 @@ where } Ok(next.run(retry_req).await) } else { - Ok(axum::response::Response::from_parts(response_parts, Body::from(response_bytes)).into_response()) + Ok(axum::response::Response::from_parts( + response_parts, + Body::from(response_bytes), + )) } } else { Ok(next.run(req).await) } -} \ No newline at end of file +} + +/// Axum middleware that extracts `State>` and delegates to [`inject_token_with`]. +/// Use this when the store is shared application state (e.g. auth-daemon's RouterState). +pub async fn inject_token( + State(store): State>, + req: Request, + next: middleware::Next, +) -> Result +where + S: TokenStore + RetryPolicy + 'static, +{ + inject_token_with(store.as_ref(), req, next).await +} From 58400621a874d3fdb319ca21b78cbab3e33ce84c Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Mon, 13 Apr 2026 12:06:08 +0100 Subject: [PATCH 14/20] fix(backend): modify auth-daemon to use auth-core logic --- backend/auth-daemon/Cargo.toml | 11 +- backend/auth-daemon/src/config.rs | 32 +--- backend/auth-daemon/src/database.rs | 104 ------------ backend/auth-daemon/src/error.rs | 26 --- backend/auth-daemon/src/healthcheck.rs | 5 - backend/auth-daemon/src/inject_token.rs | 118 ------------- backend/auth-daemon/src/main.rs | 211 ++++++++++++------------ backend/auth-daemon/src/state.rs | 206 ++++++++++++----------- 8 files changed, 233 insertions(+), 480 deletions(-) delete mode 100644 backend/auth-daemon/src/database.rs delete mode 100644 backend/auth-daemon/src/error.rs delete mode 100644 backend/auth-daemon/src/healthcheck.rs delete mode 100644 backend/auth-daemon/src/inject_token.rs diff --git a/backend/auth-daemon/Cargo.toml b/backend/auth-daemon/Cargo.toml index 4e6687d8f..dc310e338 100644 --- a/backend/auth-daemon/Cargo.toml +++ b/backend/auth-daemon/Cargo.toml @@ -5,31 +5,23 @@ edition = "2024" license-file = "../../LICENSE" [dependencies] +auth-core = { path = "../auth-core" } anyhow.workspace = true axum = { workspace = true, features = ["json"] } axum-reverse-proxy = "1.0.3" clap = { workspace = true, features = ["env"] } dotenvy.workspace = true -openidconnect = "4.0.1" regex = { workspace = true } reqwest.workspace = true serde.workspace = true serde_json.workspace = true -serde_yaml = "0.9.34" thiserror.workspace = true tokio = { workspace = true, features = ["full"] } tower-http = { workspace = true, features = ["cors"] } tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } url.workspace = true -oidc-bff = { path = "../oidc-bff" } -sea-orm = { workspace = true, features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", "macros"] } chrono.workspace = true -sodiumoxide = "0.2.7" -http-body-util = "0.1.3" -oauth2 = "5.0.0" -base64 = "0.22.1" -rustls = "0.23.35" axum-test = "18.4.1" env_logger = "0.11.8" oauth2-test-server = "0.1.3" @@ -38,4 +30,5 @@ testcontainers = {version = "0.26.0", features = ["http_wait_plain"]} [dev-dependencies] mockito.workspace = true serde_json.workspace = true +sea-orm = { workspace = true, features = ["sqlx-postgres", "sqlx-sqlite"] } migration = { version = "0.1.0", path = "../auth-core/migration" } diff --git a/backend/auth-daemon/src/config.rs b/backend/auth-daemon/src/config.rs index b85d41c1a..0f1f5389d 100644 --- a/backend/auth-daemon/src/config.rs +++ b/backend/auth-daemon/src/config.rs @@ -1,32 +1,18 @@ -use std::path::Path; - -use serde::{Deserialize, Serialize}; use crate::Result; +use auth_core::config::{self, CommonConfig}; +use serde::{Deserialize, Serialize}; +use std::path::Path; -#[derive(Serialize, Deserialize)] -pub struct Config { - pub client_id: String, - pub client_secret: String, - pub oidc_provider_url: String, +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DaemonConfig { + #[serde(flatten)] + pub common: CommonConfig, pub graph_url: String, - pub port: u16, - pub postgres_user: String, - pub postgres_password: String, - pub postgres_database: String, - pub postgres_hostname: String, - pub postgres_port: u16, - pub encryption_public_key: String, pub encryption_private_key: String, } -impl Config { - /// Load config from JSON or YAML file +impl DaemonConfig { pub fn from_file>(path: P) -> Result { - let content = std::fs::read_to_string(&path)?; - match path.as_ref().extension().and_then(|e| e.to_str()) { - Some("json") => Ok(serde_json::from_str(&content)?), - // otherwise assume yaml - _ => Ok(serde_yaml::from_str(&content)?), - } + config::load_config_from_file(path) } } diff --git a/backend/auth-daemon/src/database.rs b/backend/auth-daemon/src/database.rs deleted file mode 100644 index b191bf1ff..000000000 --- a/backend/auth-daemon/src/database.rs +++ /dev/null @@ -1,104 +0,0 @@ -use chrono::{DateTime, Duration, FixedOffset, Utc}; -use oauth2::RefreshToken; -use openidconnect::{IssuerUrl, SubjectIdentifier}; -use sea_orm::DatabaseConnection; -use crate::{Result, state::TokenData}; -use sea_orm::*; -use oidc_bff::entity; - -pub async fn write_token_to_database( - connection: &DatabaseConnection, - token: &TokenData, - public_key: &sodiumoxide::crypto::box_::PublicKey, -) -> Result<()> { - let encrypted_refresh_token = - sodiumoxide::crypto::sealedbox::seal(token.refresh_token.secret().as_bytes(), public_key); - let refresh_token_expires_at = Utc::now() + Duration::days(30); // TODO: offline_access tokens will expire if not used within 30 days. Keycloak returns the actual expiration date in the field "refresh_expires_in", we should use that - let token_update = entity::oidc_tokens::ActiveModel { - issuer: Set(token.issuer.to_string()), - subject: Set(token.subject.to_string()), - encrypted_refresh_token: Set(encrypted_refresh_token), - expires_at: Set(Some(convert_time(refresh_token_expires_at))), - created_at: Set(Utc::now().into()), - updated_at: Set(Utc::now().into()), - ..Default::default() - }; - entity::oidc_tokens::Entity::insert(token_update) - .on_conflict( - sea_query::OnConflict::column(entity::oidc_tokens::Column::Subject) - .update_columns([ - entity::oidc_tokens::Column::Issuer, - entity::oidc_tokens::Column::Subject, - entity::oidc_tokens::Column::EncryptedRefreshToken, - entity::oidc_tokens::Column::ExpiresAt, - entity::oidc_tokens::Column::UpdatedAt, - // deliberately do not update CreatedAt - ]) - .to_owned(), - ) - .exec(connection) - .await?; - Ok(()) -} - -fn convert_time(utc_time: DateTime) -> DateTime { - utc_time.with_timezone(&FixedOffset::east_opt(0).unwrap()) -} - - -/// Convert DB stored FixedOffset time to Utc -fn to_utc(dt: DateTime) -> DateTime { - dt.with_timezone(&Utc) -} - -pub async fn read_token_from_database( - connection: &DatabaseConnection, - subject: &SubjectIdentifier, - issuer: Option<&IssuerUrl>, - public_key: &sodiumoxide::crypto::box_::PublicKey, - secret_key: &sodiumoxide::crypto::box_::SecretKey, -) -> Result { - println!("Fetching token from database for subject {}", subject.as_str()); - // Build query: filter by Subject (and Issuer if provided) - let mut query = entity::oidc_tokens::Entity::find() - .filter(entity::oidc_tokens::Column::Subject.eq(subject.as_str())); - - if let Some(iss) = issuer { - query = query.filter(entity::oidc_tokens::Column::Issuer.eq(iss.as_str())); - } - - let row = query.one(connection).await? - .ok_or_else(|| anyhow::anyhow!("No token row found for subject='{}' issuer={:?}", subject.as_str(), issuer))?; - - // Decrypt sealed box - let ciphertext = row.encrypted_refresh_token; - let decrypted = sodiumoxide::crypto::sealedbox::open(&ciphertext, public_key, secret_key) - .map_err(|_| anyhow::anyhow!("Unable to decrypt refresh token (sealedbox::open failed)"))?; - - let expires_at_utc = match row.expires_at { - Some(dt) => to_utc(dt), - None => { - // If not stored, decide on a policy: here we treat as "no expiry" - // You can choose to error instead. - Utc::now() - } - }; - - if expires_at_utc < Utc::now() { - Err(anyhow::anyhow!("Stored refresh token has expired at {}", expires_at_utc))?; - } - - let issuer = IssuerUrl::new(row.issuer)?; - let subject = SubjectIdentifier::new(row.subject); - let refresh_token = RefreshToken::new(String::from_utf8(decrypted)?); - let token = TokenData::new( - issuer, - subject, - None, - Utc::now(), - refresh_token - - ); - println!("Fetching token from database for subject {}: success", token.subject.as_str()); - Ok(token) -} diff --git a/backend/auth-daemon/src/error.rs b/backend/auth-daemon/src/error.rs deleted file mode 100644 index a944ebb41..000000000 --- a/backend/auth-daemon/src/error.rs +++ /dev/null @@ -1,26 +0,0 @@ -use axum::{ - http::StatusCode, - response::{IntoResponse, Response}, -}; - -#[derive(Debug)] -pub struct Error(anyhow::Error); - -impl IntoResponse for Error { - fn into_response(self) -> Response { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Something went wrong: {}", self.0), - ) - .into_response() - } -} - -impl From for Error -where - E: Into, -{ - fn from(err: E) -> Self { - Self(err.into()) - } -} diff --git a/backend/auth-daemon/src/healthcheck.rs b/backend/auth-daemon/src/healthcheck.rs deleted file mode 100644 index c9be25c8a..000000000 --- a/backend/auth-daemon/src/healthcheck.rs +++ /dev/null @@ -1,5 +0,0 @@ -use axum::http::StatusCode; - -pub async fn healthcheck() -> StatusCode { - StatusCode::ACCEPTED -} diff --git a/backend/auth-daemon/src/inject_token.rs b/backend/auth-daemon/src/inject_token.rs deleted file mode 100644 index 852fe25a2..000000000 --- a/backend/auth-daemon/src/inject_token.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::{database::write_token_to_database, state::{RouterState, TokenData}}; -use http_body_util::BodyExt; -use serde_json::Value; -use std::sync::Arc; -use axum::response::IntoResponse; - -use axum::{ - body::Body, - extract::{Request, State}, - http::{self, HeaderValue}, - middleware, response::Response, -}; - -use crate::Result; - -pub async fn inject_token( - State(state): State>, - req: Request, - next: middleware::Next, -) -> Result { - let token: Option = state.token.read().await.clone(); - if let Some(mut token) = token { - println!("Injecting token"); - if token.access_token_is_expired() { - println!("Access token is expired, refreshing"); - token = refresh_token_and_write_to_database(&state, &token).await?; - } - let mut req = clone_request(req).await?; - prepare_headers(&mut req.0, &token); - let response = next.clone().run(req.0).await; - let response = response_as_json(response).await?; - println!("DEBUG response json: {:?}", response); - if !is_good_response(&response) { - println!("Query failed, refreshing token and trying again"); - token = refresh_token_and_write_to_database(&state, &token).await?; - prepare_headers(&mut req.1, &token); - Ok(next.run(req.1).await) - } else { - Ok(axum::Json(response).into_response()) - } - } else { - println!("No token to inject"); - Ok(next.run(req).await) - } -} - -fn is_good_response(response: &Value) -> bool { - - if let Some(object) = response.as_object() { - if let Some(errors) = object.get("errors") { - return errors.as_array().map(|it| it.len() == 0).unwrap_or(false); - } else { - return true; - } - } - false -} - -async fn response_as_json(response: Response) -> Result { - - if !response.status().is_success() { - Err(anyhow::anyhow!("HTTP error: {}", response.status()))?; - } - - - let collected = response.into_body().collect().await - .map_err(|e| anyhow::anyhow!("collect body error: {}", e))?; - let bytes = collected.to_bytes(); - - let json: Value = serde_json::from_slice(&bytes) - .map_err(|e| anyhow::anyhow!("JSON parse error: {}", e))?; - Ok(json) -} - -// async fn set_token(state: &RouterState, new_token: TokenData) { -// let mut guard = state.token.write().await; -// *guard = Some(new_token); -// } - -async fn clone_request(req: Request) -> Result<(Request, Request)> { - // TODO: an inefficient method of cloning a request, improve this - let (parts, body) = req.into_parts(); - let bytes = http_body_util::BodyExt::collect(body).await?.to_bytes(); - let req1 = Request::from_parts(parts.clone(), Body::from(bytes.clone())); - let req2 = Request::from_parts(parts, Body::from(bytes)); - Ok((req1, req2)) -} - -fn prepare_headers(req: &mut Request, token: &TokenData) { - if let Some(access_token) = &token.access_token { - let value = format!("Bearer {}", access_token.secret()); - println!("DEBUG injecting token:{:?}", value); - req.headers_mut().insert( - http::header::AUTHORIZATION, - HeaderValue::from_str(&value).unwrap(), - ); - req.headers_mut().remove(http::header::COOKIE); -} -} - -async fn refresh_token_and_write_to_database( - state: &RouterState, - token: &TokenData, -) -> Result { - let token = refresh_token(state, token).await?; - write_token_to_database(&state.database_connection, &token, &state.public_key).await?; - Ok(token) -} - -async fn refresh_token(state: &RouterState, token: &TokenData) -> Result { - let token_response = state - .oidc_client - .exchange_refresh_token(&token.refresh_token)? - .request_async(&state.http_client) - .await?; - let token = token.update_tokens(&token_response); - Ok(token) -} diff --git a/backend/auth-daemon/src/main.rs b/backend/auth-daemon/src/main.rs index ab31b911a..179b80204 100644 --- a/backend/auth-daemon/src/main.rs +++ b/backend/auth-daemon/src/main.rs @@ -1,9 +1,11 @@ #![forbid(unsafe_code)] #![doc = include_str!("../README.md")] -mod healthcheck; -use healthcheck::healthcheck; -use openidconnect::SubjectIdentifier; +use crate::state::RouterState; +use auth_core::error::Error; +use auth_core::healthcheck::healthcheck; +use auth_core::middleware::inject_token; +use auth_core::openidconnect::SubjectIdentifier; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -11,9 +13,7 @@ use std::{ sync::Arc, }; -use axum::{ - Router, http::Method, middleware, routing::get, -}; +use axum::{Router, http::Method, middleware, routing::get}; use clap::Parser; use regex::Regex; use tokio::signal::unix::{SignalKind, signal}; @@ -22,17 +22,13 @@ use tower_http::cors::{AllowOrigin, CorsLayer}; use tracing::{debug, info}; use tracing_subscriber::EnvFilter; -use crate::{config::Config, state::RouterState}; mod config; mod state; -mod error; use axum_reverse_proxy::ReverseProxy; -mod inject_token; -mod database; - +use config::DaemonConfig; -type Result = std::result::Result; +type Result = std::result::Result; #[derive(Parser, Debug)] #[command(author, version, about)] @@ -45,9 +41,7 @@ struct ServeArgs { default_value = "config.yaml" )] config: String, - #[arg( - env = "WORKFLOWS_AUTH_DAEMON_SUBJECT", - )] + #[arg(env = "WORKFLOWS_AUTH_DAEMON_SUBJECT")] subject: String, } @@ -58,7 +52,6 @@ enum Cli { Serve(ServeArgs), } - #[tokio::main] async fn main() -> Result<()> { dotenvy::dotenv().ok(); @@ -69,9 +62,10 @@ async fn main() -> Result<()> { match args { Cli::Serve(args) => { - let config = Config::from_file(args.config)?; - let requested_port = config.port; - let router_state = Arc::new(RouterState::new(config, &SubjectIdentifier::new(args.subject)).await?); + let config = DaemonConfig::from_file(args.config)?; + let requested_port = config.common.port; + let router_state = + Arc::new(RouterState::new(config, &SubjectIdentifier::new(args.subject)).await?); let router = setup_router(router_state, None)?; serve(router, IpAddr::V4(Ipv4Addr::UNSPECIFIED), requested_port).await?; @@ -84,7 +78,7 @@ async fn main() -> Result<()> { fn setup_router(state: Arc, cors_allow: Option>) -> anyhow::Result { debug!("Setting up the router"); - rustls::crypto::ring::default_provider() + auth_core::rustls::crypto::ring::default_provider() .install_default() .expect("Failed to install rust TLS cryptography"); @@ -103,10 +97,9 @@ fn setup_router(state: Arc, cors_allow: Option>) -> anyh }; let proxy: Router> = - ReverseProxy::new("/", state.config.graph_url.as_str()).into(); + ReverseProxy::new("/", state.config.graph_url.as_str()).into(); let proxy = proxy; - Ok(proxy .layer(middleware::from_fn_with_state( state.clone(), @@ -144,22 +137,19 @@ mod tests { use std::sync::Arc; use std::time::Duration; + use auth_core::openidconnect::SubjectIdentifier; + use auth_core::sea_orm::ActiveValue::Set; + use auth_core::sea_orm::{Database, DatabaseConnection, EntityTrait}; use mockito::Matcher; - use openidconnect::SubjectIdentifier; - use sea_orm::ActiveValue::Set; - use sea_orm::{Database, DatabaseConnection, EntityTrait}; use serde_json::json; use testcontainers::core::wait::HttpWaitStrategy; use testcontainers::{GenericImage, ImageExt}; - use testcontainers::{ - core::WaitFor, - runners::AsyncRunner, -}; + use testcontainers::{core::WaitFor, runners::AsyncRunner}; - use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; + use auth_core::base64::{Engine, engine::general_purpose::STANDARD as BASE64}; - use crate::{config::Config, state::RouterState}; use crate::{Result, setup_router}; + use crate::{config::DaemonConfig, state::RouterState}; async fn test_database(issuer_url: &str, refresh_token: &str) -> Result { let db = Database::connect("sqlite::memory:").await?; @@ -169,90 +159,107 @@ mod tests { let now: chrono::DateTime = chrono::Utc::now().into(); let expires_at = now + Duration::from_secs(600); - let public_key = sodiumoxide::crypto::box_::PublicKey::from_slice(&BASE64.decode("ZpJ703xR7atXbGXI20FkQk3J1qjLxodTP6yk92yPVGM=")?).expect("valid key"); - let encrypted_refresh_token = sodiumoxide::crypto::sealedbox::seal(refresh_token.as_bytes(), &public_key); - - oidc_bff::entity::oidc_tokens::Entity::insert(oidc_bff::entity::oidc_tokens::ActiveModel { - issuer: Set(issuer_url.into()), - subject: Set("test-subject".into()), - encrypted_refresh_token: Set(encrypted_refresh_token.into()), - expires_at: Set(expires_at.into()), - created_at: Set(now.clone().into()), - updated_at: Set(now.into()), - ..Default::default() - }).exec(&db) + let public_key = auth_core::sodiumoxide::crypto::box_::PublicKey::from_slice( + &BASE64.decode("ZpJ703xR7atXbGXI20FkQk3J1qjLxodTP6yk92yPVGM=")?, + ) + .expect("valid key"); + let encrypted_refresh_token = + auth_core::sodiumoxide::crypto::sealedbox::seal(refresh_token.as_bytes(), &public_key); + + auth_core::entity::oidc_tokens::Entity::insert( + auth_core::entity::oidc_tokens::ActiveModel { + issuer: Set(issuer_url.into()), + subject: Set("test-subject".into()), + encrypted_refresh_token: Set(encrypted_refresh_token.into()), + expires_at: Set(expires_at.into()), + created_at: Set(now.clone().into()), + updated_at: Set(now.into()), + ..Default::default() + }, + ) + .exec(&db) .await?; Ok(db) } - #[tokio::test] async fn test() -> Result<()> { - let _ = env_logger::try_init(); let mut graphql_server = mockito::Server::new_async().await; let graphql_server_url = graphql_server.url(); - let graphql_mock = graphql_server.mock("POST", "/") - .match_header("Authorization", Matcher::Regex("Bearer .+".into())) - .with_status(200) - .with_body("{\"name\": \"workflow-name\"}") - .expect(1) - .create_async() - .await; - - let wait_strategy = HttpWaitStrategy::new("default/.well-known/openid-configuration").with_expected_status_code(200u16); - let oidc_container = GenericImage::new("ghcr.io/navikt/mock-oauth2-server", "3.0.1") - .with_wait_for(WaitFor::http(wait_strategy)) - .with_env_var("SERVER_PORT", "8080").with_startup_timeout(Duration::from_secs(60)).start().await.expect("failed to start mock OIDC server"); - let port = oidc_container.get_host_port_ipv4(8080).await?; - - let mock_admin_url = format!("http://localhost:{}/default/token", port); - let params = [ - ("grant_type", "refresh_token"), - ("scope", "openid offline_access"), - ("subject", "test-subject"), - ("refresh_token", "test-refresh-token"), - ("client_id", "test-client"), - ]; - - let res: serde_json::Value = reqwest::Client::new() - .post(mock_admin_url) - .timeout(Duration::from_secs(10)) - .form(¶ms) - .send() - .await? - .json() - .await?; - - // println!("RESPONSE: {:?}", res.to_string()); - - let refresh_token = res["refresh_token"].as_str().expect("no refresh token"); - - let issuer_url = format!("http://localhost:{}/default", port); - - let db = test_database(&issuer_url, &refresh_token).await?; - - let config = Config{ - client_id: "test-client".into(), - client_secret: "".into(), - oidc_provider_url: issuer_url.into(), - graph_url: graphql_server_url.into(), - port: 6000, - postgres_user: "auth_user".into(), - postgres_password: "password".into(), - postgres_database: "auth_service".into(), - postgres_hostname: "database-hostname".into(), - postgres_port: 5432, - encryption_public_key: "ZpJ703xR7atXbGXI20FkQk3J1qjLxodTP6yk92yPVGM=".into(), - encryption_private_key: "yxjSYB/nvdAzktd83diOtADvp3RX/0Kx5V3FgK7YlXk=".into() }; - - let router_state = Arc::new(RouterState::with_database(config, &SubjectIdentifier::new("test-subject".into()), db).await?); + let graphql_mock = graphql_server + .mock("POST", "/") + .match_header("Authorization", Matcher::Regex("Bearer .+".into())) + .with_status(200) + .with_body("{\"name\": \"workflow-name\"}") + .expect(1) + .create_async() + .await; + + let wait_strategy = HttpWaitStrategy::new("default/.well-known/openid-configuration") + .with_expected_status_code(200u16); + let oidc_container = GenericImage::new("ghcr.io/navikt/mock-oauth2-server", "3.0.1") + .with_wait_for(WaitFor::http(wait_strategy)) + .with_env_var("SERVER_PORT", "8080") + .with_startup_timeout(Duration::from_secs(60)) + .start() + .await + .expect("failed to start mock OIDC server"); + let port = oidc_container.get_host_port_ipv4(8080).await?; + + let mock_admin_url = format!("http://localhost:{}/default/token", port); + let params = [ + ("grant_type", "refresh_token"), + ("scope", "openid offline_access"), + ("subject", "test-subject"), + ("refresh_token", "test-refresh-token"), + ("client_id", "test-client"), + ]; + + let res: serde_json::Value = reqwest::Client::new() + .post(mock_admin_url) + .timeout(Duration::from_secs(10)) + .form(¶ms) + .send() + .await? + .json() + .await?; + + // println!("RESPONSE: {:?}", res.to_string()); + + let refresh_token = res["refresh_token"].as_str().expect("no refresh token"); + + let issuer_url = format!("http://localhost:{}/default", port); + + let db = test_database(&issuer_url, &refresh_token).await?; + + let config = DaemonConfig { + common: auth_core::config::CommonConfig { + client_id: "test-client".into(), + client_secret: "".into(), + oidc_provider_url: issuer_url.into(), + port: 6000, + postgres_user: "auth_user".into(), + postgres_password: "password".into(), + postgres_database: "auth_service".into(), + postgres_hostname: "database-hostname".into(), + postgres_port: 5432, + encryption_public_key: "ZpJ703xR7atXbGXI20FkQk3J1qjLxodTP6yk92yPVGM=".into(), + }, + graph_url: graphql_server_url.into(), + encryption_private_key: "yxjSYB/nvdAzktd83diOtADvp3RX/0Kx5V3FgK7YlXk=".into(), + }; + + let router_state = Arc::new( + RouterState::with_database(config, &SubjectIdentifier::new("test-subject".into()), db) + .await?, + ); let router = setup_router(router_state, None)?; let test_server = axum_test::TestServer::new(router)?; - // + // let response = test_server.post("/").content_type("application/json").json(&json!( {"query": "mutation{ submitWorkflowTemplate(name: \"template-name\", visit: {proposalCode: \"xy\", proposalNumber: 1234, number: 5}, parameters: {}){ name } }" } )).await; @@ -264,4 +271,4 @@ mod tests { Ok(()) } -} \ No newline at end of file +} diff --git a/backend/auth-daemon/src/state.rs b/backend/auth-daemon/src/state.rs index 6353889d5..949e7a109 100644 --- a/backend/auth-daemon/src/state.rs +++ b/backend/auth-daemon/src/state.rs @@ -1,86 +1,66 @@ - use chrono::{DateTime, Utc}; -use openidconnect::core::{CoreClient, CoreProviderMetadata}; -use sodiumoxide::crypto::box_::{PublicKey, SecretKey}; -use std::time::Duration; -use openidconnect::{AccessToken, IssuerUrl, RefreshToken, SubjectIdentifier}; use serde::{Deserialize, Serialize}; +use std::time::Duration; use tokio::sync::RwLock; -use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; -use oauth2::{ClientId, ClientSecret, EndpointMaybeSet, EndpointNotSet, EndpointSet, reqwest}; -use sea_orm::{Database, DatabaseConnection}; -use crate::config::Config; -use crate::Result; -use crate::database::read_token_from_database; -use anyhow::anyhow; +use auth_core::async_trait::async_trait; +use auth_core::database::RefreshTokenInfo; +use auth_core::middleware::traits::{RetryPolicy, TokenInspector, TokenStore}; +use auth_core::oidc::{ + DbConnection, HttpClient, OidcClient, SodiumPublicKey, create_db_connection, + create_oidc_client, decode_public_key, decode_secret_key, exchange_refresh_token, +}; + +use auth_core::oauth2::{self, AccessToken, RefreshToken}; +use auth_core::openidconnect::{IssuerUrl, SubjectIdentifier}; +use axum::http::StatusCode; + +use crate::config::DaemonConfig; + +type Result = auth_core::Result; pub struct RouterState { - pub config: Config, + pub config: DaemonConfig, pub token: RwLock>, - pub http_client: reqwest::Client, - pub oidc_client: openidconnect::core::CoreClient< - EndpointSet, - EndpointNotSet, - EndpointNotSet, - EndpointNotSet, - EndpointMaybeSet, - EndpointMaybeSet, - >, - pub database_connection: DatabaseConnection, - pub public_key: PublicKey, + pub http_client: HttpClient, + pub oidc_client: OidcClient, + pub database_connection: DbConnection, + pub public_key: SodiumPublicKey, } impl RouterState { - - pub async fn new(config: Config, subject: impl Into<&SubjectIdentifier>) -> Result { - let database_url = format!( - "postgres://{}:{}@{}:{}/{}", - config.postgres_user, - config.postgres_password, - config.postgres_hostname, - config.postgres_port, - config.postgres_database - ); - let database_connection = Database::connect(&database_url).await?; + pub async fn new(config: DaemonConfig, subject: &SubjectIdentifier) -> Result { + let database_connection = create_db_connection(&config.common).await?; Self::with_database(config, subject, database_connection).await } - pub async fn with_database(config: Config, subject: impl Into<&SubjectIdentifier>, database_connection: impl Into) -> Result { - - let http_client = reqwest::ClientBuilder::new() - // Following redirects opens the client up to SSRF vulnerabilities. - .redirect(reqwest::redirect::Policy::none()) - .build()?; - - // Use OpenID Connect Discovery to fetch the provider metadata. - let provider_metadata = CoreProviderMetadata::discover_async( - IssuerUrl::new(config.oidc_provider_url.to_string())?, - &http_client, + pub async fn with_database( + config: DaemonConfig, + subject: &SubjectIdentifier, + database_connection: impl Into, + ) -> Result { + let (oidc_client, http_client) = create_oidc_client(&config.common).await?; + let public_key = decode_public_key(&config.common.encryption_public_key)?; + let private_key = decode_secret_key(&config.encryption_private_key)?; + let database_connection = database_connection.into(); + let stored = auth_core::database::read_token_from_database( + &database_connection, + subject, + None, + &public_key, + &private_key, ) .await?; - - let oidc_client = CoreClient::from_provider_metadata( - provider_metadata, - ClientId::new(config.client_id.to_string()), - if config.client_secret.is_empty() { - None - } else { - Some(ClientSecret::new(config.client_secret.to_string())) - }, + let token = TokenData::new( + IssuerUrl::new(stored.issuer)?, + SubjectIdentifier::new(stored.subject), + None, + Utc::now(), // expired — will be refreshed on first request + RefreshToken::new(stored.refresh_token_secret), ); - - let public_key = PublicKey::from_slice(&BASE64.decode(&config.encryption_public_key)?) - .ok_or(anyhow!("Invalid public key"))?; - - let private_key = SecretKey::from_slice(&BASE64.decode(&config.encryption_private_key)?) - .ok_or(anyhow!("Invalid public key"))?; - - let subject = subject.into(); - let database_connection = database_connection.into(); - let token = read_token_from_database(&database_connection, subject, None, &public_key, &private_key).await?; - - Ok(Self {config, token: RwLock::new(Some(token)), + Ok(Self { + config, + token: RwLock::new(Some(token)), http_client, oidc_client, database_connection, @@ -89,6 +69,51 @@ impl RouterState { } } +#[async_trait] +impl TokenStore for RouterState { + type Token = TokenData; + + async fn load_token(&self) -> Option { + self.token.read().await.clone() + } + + async fn save_token(&self, token: &Self::Token) -> auth_core::Result<()> { + let mut guard = self.token.write().await; + *guard = Some(token.clone()); + Ok(()) + } + + async fn refresh_and_persist(&self, token: &Self::Token) -> auth_core::Result { + let token_response = + exchange_refresh_token(&self.oidc_client, &self.http_client, &token.refresh_token) + .await?; + let new_token = token.update_tokens(&token_response); + auth_core::database::write_token_to_database( + &self.database_connection, + &new_token, + &self.public_key, + ) + .await?; + self.save_token(&new_token).await?; + Ok(new_token) + } +} + +impl RetryPolicy for RouterState { + fn should_retry(&self, status: StatusCode, body: &[u8]) -> bool { + if !status.is_success() { + return true; + } + // Check for GraphQL errors in the response body + if let Ok(json) = serde_json::from_slice::(body) + && let Some(errors) = json.get("errors").and_then(|e| e.as_array()) + { + return !errors.is_empty(); + } + false + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TokenData { pub issuer: IssuerUrl, @@ -98,8 +123,28 @@ pub struct TokenData { pub refresh_token: RefreshToken, } -impl TokenData { +impl TokenInspector for TokenData { + fn is_expired(&self) -> bool { + self.access_token_is_expired() + } + fn bearer_value(&self) -> Option { + self.access_token.as_ref().map(|t| t.secret().to_string()) + } +} +impl RefreshTokenInfo for TokenData { + fn refresh_token_secret(&self) -> &str { + self.refresh_token.secret() + } + fn issuer(&self) -> &str { + self.issuer.as_str() + } + fn subject(&self) -> &str { + self.subject.as_str() + } +} + +impl TokenData { pub fn new( issuer: IssuerUrl, subject: SubjectIdentifier, @@ -116,29 +161,6 @@ impl TokenData { } } - // pub fn from_token_response( - // token_response: &T, - // issuer: IssuerUrl, - // subject: SubjectIdentifier, - // ) -> Result { - // let access_token = token_response.access_token().clone(); - // let refresh_token = token_response - // .refresh_token() - // .ok_or_else(|| anyhow!("Token Response did not return a refresh token"))? - // .clone(); - // let access_token_expires_at = Utc::now() - // + token_response - // .expires_in() - // .unwrap_or_else(|| Duration::from_secs(60)); - // Ok(Self::new( - // issuer, - // subject, - // Some(access_token), - // access_token_expires_at, - // refresh_token, - // )) - // } - pub fn update_tokens_mut(&mut self, token_response: &T) { let access_token = token_response.access_token().clone(); let refresh_token = token_response.refresh_token(); @@ -163,5 +185,3 @@ impl TokenData { self.access_token_expires_at <= Utc::now() || self.access_token.is_none() } } - - From 422afc4d155ed1353cae4fb26391381354e0a808 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Mon, 13 Apr 2026 15:50:57 +0100 Subject: [PATCH 15/20] fix: updated workspace Cargo.lock --- backend/Cargo.lock | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 8c198eb2a..c003a7d07 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -436,29 +436,21 @@ name = "auth-daemon" version = "0.1.0" dependencies = [ "anyhow", + "auth-core", "axum", "axum-reverse-proxy", "axum-test", - "base64 0.22.1", "chrono", "clap", "dotenvy", "env_logger", - "http-body-util", "migration", "mockito", - "oauth2", "oauth2-test-server", - "oidc-bff", - "openidconnect", "regex", "reqwest", - "rustls 0.23.35", - "sea-orm", "serde", "serde_json", - "serde_yaml", - "sodiumoxide", "testcontainers", "thiserror 2.0.17", "tokio", @@ -3596,7 +3588,6 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ - "cc", "pkg-config", "vcpkg", ] @@ -4002,24 +3993,18 @@ name = "oidc-bff" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", + "auth-core", "axum", "axum-reverse-proxy", - "base64 0.22.1", "bytes", "chrono", "clap", "dotenvy", - "http-body-util", "hyper 1.8.1", "moka", - "oauth2", - "openidconnect", - "rustls 0.23.35", - "sea-orm", "serde", "serde_json", - "serde_yaml", - "sodiumoxide", "thiserror 2.0.17", "tokio", "tower-sessions", From 1bcc2ac24d020d4b15f0da982ed4accc28c029d2 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Mon, 13 Apr 2026 16:14:15 +0100 Subject: [PATCH 16/20] feat: add auth-core components to Dockerfiles --- backend/Dockerfile.auth-daemon | 3 ++- backend/Dockerfile.graph-proxy | 2 ++ backend/Dockerfile.oidc-bff | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/Dockerfile.auth-daemon b/backend/Dockerfile.auth-daemon index 6ed136f50..fb77fec7a 100644 --- a/backend/Dockerfile.auth-daemon +++ b/backend/Dockerfile.auth-daemon @@ -8,7 +8,8 @@ COPY argo-workflows-openapi/Cargo.toml argo-workflows-openapi/Cargo.toml COPY graph-proxy/Cargo.toml graph-proxy/ COPY sessionspaces/Cargo.toml sessionspaces/ COPY oidc-bff/Cargo.toml oidc-bff/ -COPY oidc-bff/migration/Cargo.toml oidc-bff/migration/ +COPY auth-core/Cargo.toml auth-core/ +COPY auth-core/migration/Cargo.toml auth-core/migration/ COPY auth-daemon/Cargo.toml auth-daemon/ COPY telemetry/build.rs telemetry/build.rs COPY telemetry/Cargo.toml telemetry/Cargo.toml diff --git a/backend/Dockerfile.graph-proxy b/backend/Dockerfile.graph-proxy index 7ca04f298..2762ab74f 100644 --- a/backend/Dockerfile.graph-proxy +++ b/backend/Dockerfile.graph-proxy @@ -11,6 +11,8 @@ COPY argo-workflows-openapi/Cargo.toml argo-workflows-openapi/Cargo.toml COPY argo-workflows-openapi/build.rs argo-workflows-openapi/build.rs COPY argo-workflows-openapi/src/lib.rs argo-workflows-openapi/src/lib.rs COPY sessionspaces/Cargo.toml sessionspaces/Cargo.toml +COPY auth-core/Cargo.toml auth-core/ +COPY auth-core/migration/Cargo.toml auth-core/migration/ COPY auth-daemon/Cargo.toml auth-daemon/ COPY graph-proxy/Cargo.toml graph-proxy/ COPY telemetry/build.rs telemetry/Cargo.toml telemetry/ diff --git a/backend/Dockerfile.oidc-bff b/backend/Dockerfile.oidc-bff index a67be847c..4a1bd9ee6 100644 --- a/backend/Dockerfile.oidc-bff +++ b/backend/Dockerfile.oidc-bff @@ -3,7 +3,8 @@ FROM docker.io/library/rust:1.91.0-bookworm AS build WORKDIR /app RUN cargo install cargo-auditable - +COPY auth-core/Cargo.toml auth-core/ +COPY auth-core/migration/Cargo.toml auth-core/migration/ COPY Cargo.toml Cargo.lock ./ COPY . . From aced09c7c52a2d94878d0d97b692a7897a34ee13 Mon Sep 17 00:00:00 2001 From: TBThomas56 Date: Tue, 14 Apr 2026 23:29:43 +0100 Subject: [PATCH 17/20] feat(backend): updated Cargo.toml files --- backend/Cargo.lock | 217 +++++++++++++-------------------- backend/auth-daemon/Cargo.toml | 2 +- backend/oidc-bff/Cargo.toml | 1 + 3 files changed, 85 insertions(+), 135 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index c003a7d07..fc255fb11 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -145,7 +145,7 @@ name = "argo-workflows-openapi" version = "0.1.0" dependencies = [ "chrono", - "reqwest 0.12.15", + "reqwest 0.12.24", "rustfmt-wrapper", "schemars 0.8.22", "serde", @@ -448,13 +448,13 @@ dependencies = [ "mockito", "oauth2-test-server", "regex", - "reqwest", + "reqwest 0.12.24", "serde", "serde_json", "testcontainers", "thiserror 2.0.17", "tokio", - "tower-http 0.6.6", + "tower-http 0.6.8", "tracing", "tracing-subscriber", "url", @@ -1019,26 +1019,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.107", -] - [[package]] name = "bitflags" version = "2.9.0" @@ -1071,9 +1051,9 @@ dependencies = [ [[package]] name = "bollard" -version = "0.19.4" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87a52479c9237eb04047ddb94788c41ca0d26eaff8b697ecfbb4c32f7fdc3b1b" +checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" dependencies = [ "async-stream", "base64 0.22.1", @@ -1081,7 +1061,6 @@ dependencies = [ "bollard-buildkit-proto", "bollard-stubs", "bytes", - "chrono", "futures-core", "futures-util", "hex", @@ -1099,14 +1078,13 @@ dependencies = [ "rand 0.9.2", "rustls 0.23.35", "rustls-native-certs 0.8.1", - "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_derive", "serde_json", - "serde_repr", "serde_urlencoded", "thiserror 2.0.17", + "time", "tokio", "tokio-stream", "tokio-util", @@ -1131,19 +1109,18 @@ dependencies = [ [[package]] name = "bollard-stubs" -version = "1.49.1-rc.28.4.0" +version = "1.52.1-rc.29.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5731fe885755e92beff1950774068e0cae67ea6ec7587381536fca84f1779623" +checksum = "0f0a8ca8799131c1837d1282c3f81f31e76ceb0ce426e04a7fe1ccee3287c066" dependencies = [ "base64 0.22.1", "bollard-buildkit-proto", "bytes", - "chrono", "prost", "serde", "serde_json", "serde_repr", - "serde_with", + "time", ] [[package]] @@ -1581,16 +1558,6 @@ dependencies = [ "darling_macro 0.21.3", ] -[[package]] -name = "darling" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" -dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", -] - [[package]] name = "darling_core" version = "0.20.11" @@ -1619,19 +1586,6 @@ dependencies = [ "syn 2.0.107", ] -[[package]] -name = "darling_core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" -dependencies = [ - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.107", -] - [[package]] name = "darling_macro" version = "0.20.11" @@ -1654,17 +1608,6 @@ dependencies = [ "syn 2.0.107", ] -[[package]] -name = "darling_macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" -dependencies = [ - "darling_core 0.23.0", - "quote", - "syn 2.0.107", -] - [[package]] name = "data-encoding" version = "2.8.0" @@ -2453,7 +2396,8 @@ dependencies = [ "opentelemetry", "opentelemetry_sdk", "regex", - "reqwest", + "reqwest 0.12.24", + "rstest", "rustls 0.23.35", "secrecy", "serde", @@ -2464,9 +2408,10 @@ dependencies = [ "tokio", "tokio-stream", "tokio-tungstenite 0.28.0", - "tower-http 0.6.6", + "tower-http 0.6.8", "tower-service", "tracing", + "tungstenite 0.28.0", "url", ] @@ -2988,21 +2933,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyperlocal" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" -dependencies = [ - "hex", - "http-body-util", - "hyper 1.7.0", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - [[package]] name = "iana-time-zone" version = "0.1.63" @@ -3260,15 +3190,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.14.0" @@ -3365,9 +3286,9 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "10.2.0" +version = "10.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76e1c7d7df3e34443b3621b459b066a7b79644f059fc8b2db7070c825fd417e" +checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" dependencies = [ "aws-lc-rs", "base64 0.22.1", @@ -3437,7 +3358,7 @@ dependencies = [ "tokio", "tokio-util", "tower", - "tower-http 0.6.6", + "tower-http 0.6.8", "tracing", ] @@ -3933,7 +3854,7 @@ dependencies = [ "getrandom 0.2.15", "http 1.3.1", "rand 0.8.5", - "reqwest", + "reqwest 0.12.24", "serde", "serde_json", "serde_path_to_error", @@ -3957,7 +3878,7 @@ dependencies = [ "jsonwebtoken", "once_cell", "rand 0.8.5", - "reqwest", + "reqwest 0.12.24", "rsa", "serde", "serde_json", @@ -4115,7 +4036,7 @@ dependencies = [ "bytes", "http 1.3.1", "opentelemetry", - "reqwest 0.12.15", + "reqwest 0.12.24", ] [[package]] @@ -4130,7 +4051,7 @@ dependencies = [ "opentelemetry-proto", "opentelemetry_sdk", "prost", - "reqwest 0.12.15", + "reqwest 0.12.24", "thiserror 2.0.17", "tokio", "tonic", @@ -4508,15 +4429,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "prettyplease" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve 0.13.8", -] - [[package]] name = "primeorder" version = "0.13.6" @@ -4864,6 +4776,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "rend" version = "0.4.2" @@ -4914,23 +4832,14 @@ dependencies = [ "tokio-rustls 0.26.2", "tokio-util", "tower", - "tower-http 0.6.6", + "tower-http 0.6.8", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.4", -] - -[[package]] -name = "reserve-port" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21918d6644020c6f6ef1993242989bf6d4952d2e025617744f184c02df51c356" -dependencies = [ - "thiserror 2.0.17", + "webpki-roots 1.0.6", ] [[package]] @@ -4947,7 +4856,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.27.5", "hyper-util", "js-sys", @@ -4960,7 +4869,7 @@ dependencies = [ "sync_wrapper", "tokio", "tower", - "tower-http", + "tower-http 0.6.8", "tower-service", "url", "wasm-bindgen", @@ -4968,6 +4877,15 @@ dependencies = [ "web-sys", ] +[[package]] +name = "reserve-port" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21918d6644020c6f6ef1993242989bf6d4952d2e025617744f184c02df51c356" +dependencies = [ + "thiserror 2.0.17", +] + [[package]] name = "rfc6979" version = "0.3.1" @@ -5067,6 +4985,35 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rstest" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", +] + +[[package]] +name = "rstest_macros" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.107", + "unicode-ident", +] + [[package]] name = "rust-multipart-rfc7578_2" version = "0.8.0" @@ -5189,7 +5136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.4", + "rustls-pemfile", "schannel", "security-framework 2.11.1", ] @@ -5215,15 +5162,6 @@ dependencies = [ "base64 0.21.7", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.13.0" @@ -6430,9 +6368,9 @@ dependencies = [ [[package]] name = "testcontainers" -version = "0.26.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a347cac4368ba4f1871743adb27dc14829024d26b1763572404726b0b9943eb8" +checksum = "0bd36b06a2a6c0c3c81a83be1ab05fe86460d054d4d51bf513bc56b3e15bdc22" dependencies = [ "astral-tokio-tar", "async-trait", @@ -6443,6 +6381,7 @@ dependencies = [ "etcetera 0.11.0", "ferroid", "futures", + "http 1.3.1", "itertools 0.14.0", "log", "memchr", @@ -6768,6 +6707,7 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "hdrhistogram", "indexmap 2.8.0", "pin-project-lite", "slab", @@ -7174,7 +7114,7 @@ dependencies = [ "base64 0.22.1", "log", "percent-encoding", - "rustls 0.23.28", + "rustls 0.23.35", "rustls-pki-types", "ureq-proto", "utf8-zero", @@ -7423,6 +7363,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "whoami" version = "1.6.0" diff --git a/backend/auth-daemon/Cargo.toml b/backend/auth-daemon/Cargo.toml index dc310e338..f9dcc747f 100644 --- a/backend/auth-daemon/Cargo.toml +++ b/backend/auth-daemon/Cargo.toml @@ -25,7 +25,7 @@ chrono.workspace = true axum-test = "18.4.1" env_logger = "0.11.8" oauth2-test-server = "0.1.3" -testcontainers = {version = "0.26.0", features = ["http_wait_plain"]} +testcontainers = {version = "0.27.0", features = ["http_wait_plain"]} [dev-dependencies] mockito.workspace = true diff --git a/backend/oidc-bff/Cargo.toml b/backend/oidc-bff/Cargo.toml index a4b0e43e8..8c3db0092 100644 --- a/backend/oidc-bff/Cargo.toml +++ b/backend/oidc-bff/Cargo.toml @@ -3,6 +3,7 @@ name = "oidc-bff" version = "0.1.0" edition = "2024" default-run = "oidc-bff" +license-file = "../../LICENSE" [[bin]] name = "keygen" From d2861d3ea09031aed6d6fb29342a22fdf4925886 Mon Sep 17 00:00:00 2001 From: TBThomas56 Date: Tue, 14 Apr 2026 23:42:59 +0100 Subject: [PATCH 18/20] feat(charts): updated chart versions --- charts/apps/Chart.yaml | 2 +- charts/dashboard/Chart.yaml | 2 +- charts/workflows-cluster/Chart.yaml | 2 +- charts/workflows/Chart.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/apps/Chart.yaml b/charts/apps/Chart.yaml index 3ad15748c..7841332c3 100644 --- a/charts/apps/Chart.yaml +++ b/charts/apps/Chart.yaml @@ -2,4 +2,4 @@ apiVersion: v2 name: apps description: An argocd app to deploy apps inside the virtual cluster type: application -version: 0.5.1 +version: 0.5.2 diff --git a/charts/dashboard/Chart.yaml b/charts/dashboard/Chart.yaml index 7c9f4a0f9..2d751dd85 100644 --- a/charts/dashboard/Chart.yaml +++ b/charts/dashboard/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: dashboard description: A dashboard for Diamond workflows type: application -version: 0.2.13 +version: 0.2.15 appVersion: 0.1.12 dependencies: - name: common diff --git a/charts/workflows-cluster/Chart.yaml b/charts/workflows-cluster/Chart.yaml index 2dccb16b4..ff5381532 100644 --- a/charts/workflows-cluster/Chart.yaml +++ b/charts/workflows-cluster/Chart.yaml @@ -3,7 +3,7 @@ name: workflows-cluster description: A virtual cluster for Data Analysis workflows type: application -version: 0.11.2 +version: 0.11.3 dependencies: - name: common version: 2.23.0 diff --git a/charts/workflows/Chart.yaml b/charts/workflows/Chart.yaml index 8ad1a5f4c..19da02dd9 100644 --- a/charts/workflows/Chart.yaml +++ b/charts/workflows/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: workflows description: Data Analysis workflow orchestration type: application -version: 0.13.42 +version: 0.13.43 dependencies: - name: argo-workflows repository: https://argoproj.github.io/argo-helm From 85b9202471ca52179c7838455dadeb0e420ed281 Mon Sep 17 00:00:00 2001 From: TBThomas56 Date: Wed, 15 Apr 2026 01:38:46 +0100 Subject: [PATCH 19/20] fix(charts): moved secret to secrets folder in workflows-cluster --- .../charts/secrets/templates/oidc-bff.yaml | 28 +++++++++++++++++++ .../workflows-cluster/templates/oidc-bff.yaml | 13 --------- 2 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 charts/workflows-cluster/charts/secrets/templates/oidc-bff.yaml delete mode 100644 charts/workflows-cluster/templates/oidc-bff.yaml diff --git a/charts/workflows-cluster/charts/secrets/templates/oidc-bff.yaml b/charts/workflows-cluster/charts/secrets/templates/oidc-bff.yaml new file mode 100644 index 000000000..ece30883b --- /dev/null +++ b/charts/workflows-cluster/charts/secrets/templates/oidc-bff.yaml @@ -0,0 +1,28 @@ +{{- if eq .Values.cluster "argus" }} +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + name: oidc-bff-config + namespace: workflows +spec: + encryptedData: + config.yaml: AgBmJplbabGvBLH9zqvt3YANVjBPUaARwJu/H0pBx/k5FpCSASfP0vKx7/XL4JCg01+awygBW8a8t7bBChs6yXTcatXGWKeVE1eX2go9XPmwGM9OKR8cLoFlufQx++0N6HhMAOuonCsbM33X9RbmfYm5Azxontmk9+W6nQqT+7UkcpPheC2f0tFKyJVvIVbrUOsJmls1TgmQUFZIj5dWtOrgChhC6rSbogMWF2WtFpT4RRlCKZUXMggFPTw82fjytCVxDXaxnjwD2Wzj33dY9gxy10iGp/MUQefZ2AM3iMqcgu2u0ENe5dCO8bKVcaemytRuKRiK6DUbKq2pa5gATUG9pDUhbW3g9Aa7sQyjvOSun+G4S+1+n9+EMTaYcv79eVkAnl07XHe6p5T3Bsl42iZdL8gMahtFwYH31yybWFI57Q66zyIFj7oTzr8zvyYwyYj/VpAA6gMKxAF2eBXwNOhKd7LnUjI7iitBiDxIBfNQImkfcfDaAQSm84JPZW1YJl6jolvJTQAckjLMrrzDKR4X953Qv9BsPZBjS16MVg3hkZR9Db3XdP2lSQngsT/WMDSJ44X0fxNHU6Hamv2hanvYw1kCJCeESYfA+aWtAcsZtjX2axRfiuWHTxVZ5nUcTsCuxbIpla/iS7jG5i81BZu79ilEKj2rJjm6of1y5dWehZm93DQjQK++jgU8Bil9UARvrLG2hsrodpl0FTSYUMAyF2Lct3FYp9yr5juMKWNqXeK4z/2E/fX3DbQUK0vNCpUXvhwTPq0KOtlnTBbQHJanHjROI5IMe2Mtmoypzne/K/pWJSGz7b6+n5jBGZJjaOeH77+f/mAFu5M3K/KL2yxEjU55BuHnzXhHgDQxErwM61NJQx5OhJI0zLcVln593N0c8J73Ei7I5yaEYo/AVorADwv0tjWztUgCplE/4GHAgbV9Fats2dmZw90FnBpZALDOJZInujrxGze+//rex6s8tzk2xEUXIZMZvPOKiIUhp65+m1PX2aQwNOjO/v3GJUHdnvjpCk8PXAAq9l8rlyOTE1QimBwaLzIA8CI4vh/iD+dUh+TpWbs4wopJyA9jBUMCRhZLNvXuHG4bXygZc5b2OJ8Az+qMU1LpTcrLa1g7/qQHOhMv4EyoqbluMLFY8RtaeT59GtBmwvvVCkCoLDQazCxvkHRr0f/vTiKE7sG/CQ+rlDxL4DqGJsgcQYJYWYbBaykr1nOBsoxeIUBKFzJY7o8PP9LwBlf7PmKpQFhcT+xyIdOZJFSVDtiqVr+jWwTJm+iE+3WI/M/QYwmhuLcRf8M= + template: + metadata: + name: oidc-bff-config + namespace: workflows +{{- else if eq .Values.cluster "pollux" }} +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + name: oidc-bff-config + namespace: workflows +spec: + encryptedData: + config.yaml: AgBmJplbabGvBLH9zqvt3YANVjBPUaARwJu/H0pBx/k5FpCSASfP0vKx7/XL4JCg01+awygBW8a8t7bBChs6yXTcatXGWKeVE1eX2go9XPmwGM9OKR8cLoFlufQx++0N6HhMAOuonCsbM33X9RbmfYm5Azxontmk9+W6nQqT+7UkcpPheC2f0tFKyJVvIVbrUOsJmls1TgmQUFZIj5dWtOrgChhC6rSbogMWF2WtFpT4RRlCKZUXMggFPTw82fjytCVxDXaxnjwD2Wzj33dY9gxy10iGp/MUQefZ2AM3iMqcgu2u0ENe5dCO8bKVcaemytRuKRiK6DUbKq2pa5gATUG9pDUhbW3g9Aa7sQyjvOSun+G4S+1+n9+EMTaYcv79eVkAnl07XHe6p5T3Bsl42iZdL8gMahtFwYH31yybWFI57Q66zyIFj7oTzr8zvyYwyYj/VpAA6gMKxAF2eBXwNOhKd7LnUjI7iitBiDxIBfNQImkfcfDaAQSm84JPZW1YJl6jolvJTQAckjLMrrzDKR4X953Qv9BsPZBjS16MVg3hkZR9Db3XdP2lSQngsT/WMDSJ44X0fxNHU6Hamv2hanvYw1kCJCeESYfA+aWtAcsZtjX2axRfiuWHTxVZ5nUcTsCuxbIpla/iS7jG5i81BZu79ilEKj2rJjm6of1y5dWehZm93DQjQK++jgU8Bil9UARvrLG2hsrodpl0FTSYUMAyF2Lct3FYp9yr5juMKWNqXeK4z/2E/fX3DbQUK0vNCpUXvhwTPq0KOtlnTBbQHJanHjROI5IMe2Mtmoypzne/K/pWJSGz7b6+n5jBGZJjaOeH77+f/mAFu5M3K/KL2yxEjU55BuHnzXhHgDQxErwM61NJQx5OhJI0zLcVln593N0c8J73Ei7I5yaEYo/AVorADwv0tjWztUgCplE/4GHAgbV9Fats2dmZw90FnBpZALDOJZInujrxGze+//rex6s8tzk2xEUXIZMZvPOKiIUhp65+m1PX2aQwNOjO/v3GJUHdnvjpCk8PXAAq9l8rlyOTE1QimBwaLzIA8CI4vh/iD+dUh+TpWbs4wopJyA9jBUMCRhZLNvXuHG4bXygZc5b2OJ8Az+qMU1LpTcrLa1g7/qQHOhMv4EyoqbluMLFY8RtaeT59GtBmwvvVCkCoLDQazCxvkHRr0f/vTiKE7sG/CQ+rlDxL4DqGJsgcQYJYWYbBaykr1nOBsoxeIUBKFzJY7o8PP9LwBlf7PmKpQFhcT+xyIdOZJFSVDtiqVr+jWwTJm+iE+3WI/M/QYwmhuLcRf8M= + template: + metadata: + name: oidc-bff-config + namespace: workflows +{{ else }} +{{- end }} diff --git a/charts/workflows-cluster/templates/oidc-bff.yaml b/charts/workflows-cluster/templates/oidc-bff.yaml deleted file mode 100644 index 8afd7be74..000000000 --- a/charts/workflows-cluster/templates/oidc-bff.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: bitnami.com/v1alpha1 -kind: SealedSecret -metadata: - name: oidc-bff-config - namespace: workflows -spec: - encryptedData: - config.yaml: AgBmJplbabGvBLH9zqvt3YANVjBPUaARwJu/H0pBx/k5FpCSASfP0vKx7/XL4JCg01+awygBW8a8t7bBChs6yXTcatXGWKeVE1eX2go9XPmwGM9OKR8cLoFlufQx++0N6HhMAOuonCsbM33X9RbmfYm5Azxontmk9+W6nQqT+7UkcpPheC2f0tFKyJVvIVbrUOsJmls1TgmQUFZIj5dWtOrgChhC6rSbogMWF2WtFpT4RRlCKZUXMggFPTw82fjytCVxDXaxnjwD2Wzj33dY9gxy10iGp/MUQefZ2AM3iMqcgu2u0ENe5dCO8bKVcaemytRuKRiK6DUbKq2pa5gATUG9pDUhbW3g9Aa7sQyjvOSun+G4S+1+n9+EMTaYcv79eVkAnl07XHe6p5T3Bsl42iZdL8gMahtFwYH31yybWFI57Q66zyIFj7oTzr8zvyYwyYj/VpAA6gMKxAF2eBXwNOhKd7LnUjI7iitBiDxIBfNQImkfcfDaAQSm84JPZW1YJl6jolvJTQAckjLMrrzDKR4X953Qv9BsPZBjS16MVg3hkZR9Db3XdP2lSQngsT/WMDSJ44X0fxNHU6Hamv2hanvYw1kCJCeESYfA+aWtAcsZtjX2axRfiuWHTxVZ5nUcTsCuxbIpla/iS7jG5i81BZu79ilEKj2rJjm6of1y5dWehZm93DQjQK++jgU8Bil9UARvrLG2hsrodpl0FTSYUMAyF2Lct3FYp9yr5juMKWNqXeK4z/2E/fX3DbQUK0vNCpUXvhwTPq0KOtlnTBbQHJanHjROI5IMe2Mtmoypzne/K/pWJSGz7b6+n5jBGZJjaOeH77+f/mAFu5M3K/KL2yxEjU55BuHnzXhHgDQxErwM61NJQx5OhJI0zLcVln593N0c8J73Ei7I5yaEYo/AVorADwv0tjWztUgCplE/4GHAgbV9Fats2dmZw90FnBpZALDOJZInujrxGze+//rex6s8tzk2xEUXIZMZvPOKiIUhp65+m1PX2aQwNOjO/v3GJUHdnvjpCk8PXAAq9l8rlyOTE1QimBwaLzIA8CI4vh/iD+dUh+TpWbs4wopJyA9jBUMCRhZLNvXuHG4bXygZc5b2OJ8Az+qMU1LpTcrLa1g7/qQHOhMv4EyoqbluMLFY8RtaeT59GtBmwvvVCkCoLDQazCxvkHRr0f/vTiKE7sG/CQ+rlDxL4DqGJsgcQYJYWYbBaykr1nOBsoxeIUBKFzJY7o8PP9LwBlf7PmKpQFhcT+xyIdOZJFSVDtiqVr+jWwTJm+iE+3WI/M/QYwmhuLcRf8M= - template: - metadata: - name: oidc-bff-config - namespace: workflows From 773d22fecfaa13c93fe1b7ae4a3337193c70cd71 Mon Sep 17 00:00:00 2001 From: Thomas Binu Thomas Date: Wed, 15 Apr 2026 00:50:41 +0000 Subject: [PATCH 20/20] fix(backend): updated lockfile --- backend/Cargo.lock | 2816 ++++++++++++++++++++++++++------------------ 1 file changed, 1690 insertions(+), 1126 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index fc255fb11..d869b2bc1 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -7,25 +7,6 @@ name = "Inflector" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" @@ -33,7 +14,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", "once_cell", "version_check", ] @@ -45,7 +26,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.2", + "const-random", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -53,9 +35,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -83,9 +65,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -98,59 +80,56 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "once_cell", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -dependencies = [ - "backtrace", -] +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "argo-workflows-openapi" version = "0.1.0" dependencies = [ "chrono", - "reqwest 0.12.24", + "reqwest 0.12.28", "rustfmt-wrapper", "schemars 0.8.22", "serde", "serde_json", - "syn 2.0.107", + "syn 2.0.117", "typify", ] @@ -160,6 +139,165 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "arrow" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4754a624e5ae42081f464514be454b39711daae0458906dacde5f4c632f33a8" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b3141e0ec5145a22d8694ea8b6d6f69305971c4fa1c1a13ef0195aef2d678b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num-traits", +] + +[[package]] +name = "arrow-array" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8955af33b25f3b175ee10af580577280b4bd01f7e823d94c7cdef7cf8c9aef" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.16.1", + "num-complex", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-buffer" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c697ddca96183182f35b3a18e50b9110b11e916d7b7799cbfd4d34662f2c56c2" +dependencies = [ + "bytes", + "half", + "num-bigint", + "num-traits", +] + +[[package]] +name = "arrow-cast" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "646bbb821e86fd57189c10b4fcdaa941deaf4181924917b0daa92735baa6ada5" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "half", + "lexical-core", + "num-traits", + "ryu", +] + +[[package]] +name = "arrow-data" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fdd994a9d28e6365aa78e15da3f3950c0fdcea6b963a12fa1c391afb637b304" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-ord" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d8f1870e03d4cbed632959498bcc84083b5a24bded52905ae1695bd29da45b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18228633bad92bff92a95746bbeb16e5fc318e8382b75619dec26db79e4de4c0" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c872d36b7bf2a6a6a2b40de9156265f0242910791db366a2c17476ba8330d68" + +[[package]] +name = "arrow-select" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bf3e3efbd1278f770d67e5dc410257300b161b93baedb3aae836144edcaf4b" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num-traits", +] + +[[package]] +name = "arrow-string" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e968097061b3c0e9fe3079cf2e703e487890700546b5b0647f60fca1b5a8d8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num-traits", + "regex", + "regex-syntax", +] + [[package]] name = "ascii_utils" version = "0.9.3" @@ -257,25 +395,25 @@ dependencies = [ [[package]] name = "async-graphql" -version = "7.0.17" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "036618f842229ba0b89652ffe425f96c7c16a49f7e3cb23b56fca7f61fd74980" +checksum = "1057a9f7ccf2404d94571dec3451ade1cb524790df6f1ada0d19c2a49f6b0f40" dependencies = [ "async-graphql-derive", "async-graphql-parser", "async-graphql-value", - "async-stream", + "async-io", "async-trait", + "asynk-strim", "base64 0.22.1", "bytes", "chrono", "fast_chemail", "fnv", - "futures-timer", "futures-util", "handlebars", - "http 1.3.1", - "indexmap 2.8.0", + "http 1.4.0", + "indexmap 2.14.0", "mime", "multer", "num-traits", @@ -286,15 +424,15 @@ dependencies = [ "serde_urlencoded", "static_assertions_next", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.18", "url", ] [[package]] name = "async-graphql-axum" -version = "7.0.17" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8725874ecfbf399e071150b8619c4071d7b2b7a2f117e173dddef53c6bdb6bb1" +checksum = "a1e37c5532e4b686acf45e7162bc93da91fc2c702fb0d465efc2c20c8f973795" dependencies = [ "async-graphql", "axum", @@ -309,26 +447,26 @@ dependencies = [ [[package]] name = "async-graphql-derive" -version = "7.0.17" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd45deb3dbe5da5cdb8d6a670a7736d735ba65b455328440f236dfb113727a3d" +checksum = "2e6cbeadc8515e66450fba0985ce722192e28443697799988265d86304d7cc68" dependencies = [ "Inflector", "async-graphql-parser", - "darling 0.20.11", + "darling 0.23.0", "proc-macro-crate", "proc-macro2", "quote", - "strum 0.26.3", - "syn 2.0.107", - "thiserror 1.0.69", + "strum 0.27.2", + "syn 2.0.117", + "thiserror 2.0.18", ] [[package]] name = "async-graphql-parser" -version = "7.0.17" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b7607e59424a35dadbc085b0d513aa54ec28160ee640cf79ec3b634eba66d3" +checksum = "e64ef70f77a1c689111e52076da1cd18f91834bcb847de0a9171f83624b07fbf" dependencies = [ "async-graphql-value", "pest", @@ -338,21 +476,39 @@ dependencies = [ [[package]] name = "async-graphql-value" -version = "7.0.17" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ecdaff7c9cffa3614a9f9999bf9ee4c3078fe3ce4d6a6e161736b56febf2de" +checksum = "3e3ef112905abea9dea592fc868a6873b10ebd3f983e83308f995d6284e9ba41" dependencies = [ "bytes", - "indexmap 2.8.0", + "indexmap 2.14.0", "serde", "serde_json", ] +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.2", +] + [[package]] name = "async-lock" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener", "event-listener-strategy", @@ -378,7 +534,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -389,7 +545,17 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", +] + +[[package]] +name = "asynk-strim" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52697735bdaac441a29391a9e97102c74c6ef0f9b60a40cf109b1b404e29d2f6" +dependencies = [ + "futures-core", + "pin-project-lite", ] [[package]] @@ -420,13 +586,13 @@ dependencies = [ "migration", "oauth2", "openidconnect", - "rustls 0.23.35", + "rustls 0.23.38", "sea-orm", "serde", "serde_json", "serde_yaml", "sodiumoxide", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", ] @@ -448,11 +614,12 @@ dependencies = [ "mockito", "oauth2-test-server", "regex", - "reqwest 0.12.24", + "reqwest 0.12.28", + "sea-orm", "serde", "serde_json", "testcontainers", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tower-http 0.6.8", "tracing", @@ -462,15 +629,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-credential-types" -version = "1.2.2" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4471bef4c22a06d2c7a1b6492493d3fdf24a805323109d6874f9c94d5906ac14" +checksum = "8f20799b373a1be121fe3005fba0c2090af9411573878f224df44b42727fcaf7" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -503,24 +670,26 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.6" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aff45ffe35196e593ea3b9dd65b320e51e2dda95aff4390bc459e461d09c6ad" +checksum = "5fc0651c57e384202e47153c1260b84a9936e19803d747615edf199dc3b98d17" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.63.6", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "bytes-utils", "fastrand", "http 0.2.12", + "http 1.4.0", "http-body 0.4.6", - "once_cell", + "http-body 1.0.1", "percent-encoding", "pin-project-lite", "tracing", @@ -529,9 +698,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.82.0" +version = "1.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6eab2900764411ab01c8e91a76fd11a63b4e12bc3da97d9e14a0ce1343d86d3" +checksum = "1d65fddc3844f902dfe1864acb8494db5f9342015ee3ab7890270d36fbd2e01c" dependencies = [ "aws-credential-types", "aws-runtime", @@ -539,7 +708,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-checksums", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -551,10 +720,9 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "lru", - "once_cell", "percent-encoding", "regex-lite", "sha2", @@ -564,13 +732,13 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d03c3c05ff80d54ff860fe38c726f6f494c639ae975203a101335f223386db" +checksum = "b0b660013a6683ab23797778e21f1f854744fdf05f68204b4cca4c8c04b5d1f4" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.63.6", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", @@ -579,8 +747,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.3.1", - "once_cell", + "http 1.4.0", "p256 0.11.1", "percent-encoding", "ring 0.17.14", @@ -593,9 +760,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.5" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c" +checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc" dependencies = [ "futures-util", "pin-project-lite", @@ -604,16 +771,14 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.63.1" +version = "0.63.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65d21e1ba6f2cdec92044f904356a19f5ad86961acf015741106cdfafd747c0" +checksum = "87294a084b43d649d967efe58aa1f9e0adc260e13a6938eb904c0ae9b45824ae" dependencies = [ - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-types", "bytes", - "crc32c", - "crc32fast", - "crc64fast-nvme", + "crc-fast", "hex", "http 0.2.12", "http-body 0.4.6", @@ -626,9 +791,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.8" +version = "0.60.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c45d3dddac16c5c59d553ece225a88870cf81b7b813c9cc17b78cf4685eac7a" +checksum = "faf09d74e5e32f76b8762da505a3cd59303e367a664ca67295387baa8c1d7548" dependencies = [ "aws-smithy-types", "bytes", @@ -637,9 +802,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.0" +version = "0.62.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5949124d11e538ca21142d1fba61ab0a2a2c1bc3ed323cdb3e4b878bfb83166" +checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -647,10 +812,31 @@ dependencies = [ "bytes", "bytes-utils", "futures-core", + "futures-util", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", - "once_cell", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-http" +version = "0.63.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231" +dependencies = [ + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", "percent-encoding", "pin-project-lite", "pin-utils", @@ -659,59 +845,60 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.1" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aff1159006441d02e57204bf57a1b890ba68bedb6904ffd2873c1c4c11c546b" +checksum = "6a2f165a7feee6f263028b899d0a181987f4fa7179a6411a32a439fba7c5f769" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "h2 0.4.8", + "h2 0.3.27", + "h2 0.4.13", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "hyper 0.14.32", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-rustls 0.24.2", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.9", "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.35", - "rustls-native-certs 0.8.1", + "rustls 0.23.38", + "rustls-native-certs 0.8.3", "rustls-pki-types", "tokio", + "tokio-rustls 0.26.4", "tower", "tracing", ] [[package]] name = "aws-smithy-json" -version = "0.61.3" +version = "0.61.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92144e45819cae7dc62af23eac5a038a58aa544432d2102609654376a900bd07" +checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" dependencies = [ "aws-smithy-types", ] [[package]] name = "aws-smithy-observability" -version = "0.1.2" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445d065e76bc1ef54963db400319f1dd3ebb3e0a74af20f7f7630625b0cc7cc0" +checksum = "a06c2315d173edbf1920da8ba3a7189695827002e4c0fc961973ab1c54abca9c" dependencies = [ "aws-smithy-runtime-api", - "once_cell", ] [[package]] name = "aws-smithy-runtime" -version = "1.8.1" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0152749e17ce4d1b47c7747bdfec09dac1ccafdcbc741ebf9daa2a373356730f" +checksum = "028999056d2d2fd58a697232f9eec4a643cf73a71cf327690a7edad1d2af2110" dependencies = [ "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.63.6", "aws-smithy-http-client", "aws-smithy-observability", "aws-smithy-runtime-api", @@ -719,10 +906,10 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", - "once_cell", + "http-body-util", "pin-project-lite", "pin-utils", "tokio", @@ -731,15 +918,15 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.7.4" +version = "1.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da37cf5d57011cb1753456518ec76e31691f1f474b73934a284eb2a1c76510f" +checksum = "876ab3c9c29791ba4ba02b780a3049e21ec63dabda09268b175272c3733a79e6" dependencies = [ "aws-smithy-async", "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "pin-project-lite", "tokio", "tracing", @@ -748,16 +935,16 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.0" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836155caafba616c0ff9b07944324785de2ab016141c3550bd1c07882f8cee8f" +checksum = "9d73dbfbaa8e4bc57b9045137680b958d274823509a360abfd8e1d514d40c95c" dependencies = [ "base64-simd", "bytes", "bytes-utils", "futures-core", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -774,18 +961,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.9" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" +checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.6" +version = "1.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3873f8deed8927ce8d04487630dc9ff73193bab64742a61d050e57a68dec4125" +checksum = "47c8323699dd9b3c8d5b3c13051ae9cdef58fd179957c882f8374dd8725962d9" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -797,9 +984,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", "axum-macros", @@ -807,10 +994,10 @@ dependencies = [ "bytes", "form_urlencoded", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "itoa", "matchit", @@ -825,7 +1012,7 @@ dependencies = [ "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite 0.29.0", "tower", "tower-layer", "tower-service", @@ -834,13 +1021,13 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "mime", @@ -853,9 +1040,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.12.1" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5136e6c5e7e7978fe23e9876fb924af2c0f84c72127ac6ac17e7c46f457d362c" +checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" dependencies = [ "axum", "axum-core", @@ -863,7 +1050,7 @@ dependencies = [ "futures-core", "futures-util", "headers", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "mime", @@ -875,36 +1062,34 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "axum-reverse-proxy" -version = "1.0.3" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84bb2eec9f1a2c150ce1204d843d690db0da305f6f2848cbfd4a840c830b4f0b" +checksum = "5718c2ee9685bc80e343ded8a56412307c0c6a5c361e1e67747d4996bcc698db" dependencies = [ "axum", - "base64 0.21.7", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.5", + "hyper 1.9.0", + "hyper-rustls 0.27.9", "hyper-util", - "rand 0.9.2", - "rustls 0.23.35", - "sha1", + "rand 0.9.4", + "rustls 0.23.38", "tokio", - "tokio-tungstenite 0.21.0", + "tokio-tungstenite 0.28.0", "tower", "tracing", "url", @@ -912,9 +1097,9 @@ dependencies = [ [[package]] name = "axum-test" -version = "18.4.1" +version = "18.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3290e73c56c5cc4701cdd7d46b9ced1b4bd61c7e9f9c769a9e9e87ff617d75d2" +checksum = "0ce2a8627e8d8851f894696b39f2b67807d6375c177361d376173ace306a21e2" dependencies = [ "anyhow", "axum", @@ -922,9 +1107,9 @@ dependencies = [ "bytesize", "cookie", "expect-json", - "http 1.3.1", + "http 1.4.0", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "mime", "pretty_assertions", @@ -941,30 +1126,15 @@ dependencies = [ [[package]] name = "backon" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302eaff5357a264a2c42f127ecb8bac761cf99749fc3dc95677e2743991f99e7" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ "fastrand", "gloo-timers", "tokio", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link 0.2.0", -] - [[package]] name = "base16ct" version = "0.1.1" @@ -1001,15 +1171,15 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.7.3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bigdecimal" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560f42649de9fa436b73517378a147ec21f6c997a546581df4b4b31677828934" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" dependencies = [ "autocfg", "libm", @@ -1021,11 +1191,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -1065,25 +1235,25 @@ dependencies = [ "futures-util", "hex", "home", - "http 1.3.1", + "http 1.4.0", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-named-pipe", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.9", "hyper-util", "hyperlocal", "log", "num", "pin-project-lite", - "rand 0.9.2", - "rustls 0.23.35", - "rustls-native-certs 0.8.1", + "rand 0.9.4", + "rustls 0.23.38", + "rustls-native-certs 0.8.3", "rustls-pki-types", "serde", "serde_derive", "serde_json", "serde_urlencoded", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tokio", "tokio-stream", @@ -1125,25 +1295,26 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ "borsh-derive", + "bytes", "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -1154,9 +1325,9 @@ checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytecheck" @@ -1213,9 +1384,9 @@ checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" [[package]] name = "cc" -version = "1.2.46" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -1225,9 +1396,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -1237,23 +1408,23 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link", ] [[package]] name = "clap" -version = "4.5.49" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -1261,9 +1432,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -1273,44 +1444,44 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "colored" -version = "3.0.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1338,6 +1509,35 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.18.1" @@ -1351,9 +1551,9 @@ dependencies = [ [[package]] name = "cookie_store" -version = "0.21.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" dependencies = [ "cookie", "document-features", @@ -1379,9 +1579,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -1404,9 +1604,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -1418,32 +1618,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "crc32c" -version = "0.6.8" +name = "crc-fast" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +checksum = "6ddc2d09feefeee8bd78101665bd8645637828fa9317f9f292496dbbd8c65ff3" dependencies = [ - "rustc_version", + "crc", + "digest", + "rand 0.9.4", + "regex", + "rustversion", ] [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] -[[package]] -name = "crc64fast-nvme" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4955638f00a809894c947f85a024020a20815b65a5eea633798ea7924edab2b3" -dependencies = [ - "crc", -] - [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -1477,6 +1672,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.4.9" @@ -1535,7 +1736,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -1558,6 +1759,16 @@ dependencies = [ "darling_macro 0.21.3", ] +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + [[package]] name = "darling_core" version = "0.20.11" @@ -1569,7 +1780,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -1583,7 +1794,20 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.107", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", ] [[package]] @@ -1594,7 +1818,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -1605,22 +1829,34 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.107", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.117", ] [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "deadpool" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" dependencies = [ "deadpool-runtime", + "lazy_static", "num_cpus", "tokio", ] @@ -1643,9 +1879,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -1668,32 +1904,65 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", - "serde", + "serde_core", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.117", ] [[package]] name = "derive_more" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ + "convert_case", "proc-macro2", "quote", - "syn 2.0.107", + "rustc_version", + "syn 2.0.117", "unicode-xid", ] @@ -1723,7 +1992,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -1760,9 +2029,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "ecdsa" @@ -1782,7 +2051,7 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der 0.7.9", + "der 0.7.10", "digest", "elliptic-curve 0.13.8", "rfc6979 0.4.0", @@ -1832,7 +2101,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -1905,29 +2174,29 @@ dependencies = [ [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", "regex", @@ -1935,9 +2204,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ "anstream", "anstyle", @@ -1954,9 +2223,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" dependencies = [ "serde", "serde_core", @@ -1965,12 +2234,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.11" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1991,14 +2260,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" dependencies = [ "cfg-if", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -2028,9 +2297,9 @@ dependencies = [ [[package]] name = "expect-json" -version = "1.7.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422e7906e79941e5ac58c64dfd2da03e6ae3de62227f87606fbbe125d91080f9" +checksum = "869f97f4abe8e78fc812a94ad6b721d72c4fb5532877c79610f2c238d7ccf6c4" dependencies = [ "chrono", "email_address", @@ -2039,20 +2308,20 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "typetag", "uuid", ] [[package]] name = "expect-json-macros" -version = "1.5.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bf7f5979e98460a0eb412665514594f68f366a32b85fa8d7ffb65bb1edee6a0" +checksum = "6e6fdf550180a6c29a28cb9aac262dc0064c25735641d2317f670075e9a469d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -2066,18 +2335,18 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "ferroid" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0e9414a6ae93ef993ce40a1e02944f13d4508e2bf6f1ced1580ce6910f08253" +checksum = "bb330bbd4cb7a5b9f559427f06f98a4f853a137c8298f3bd3f8ca57663e21986" dependencies = [ "portable-atomic", - "rand 0.9.2", + "rand 0.9.4", "web-time", ] @@ -2109,21 +2378,20 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.26" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.60.2", ] [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flume" @@ -2148,6 +2416,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -2165,9 +2439,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -2186,9 +2460,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -2201,9 +2475,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -2211,15 +2485,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -2239,9 +2513,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -2258,26 +2532,26 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" @@ -2287,9 +2561,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -2299,15 +2573,14 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -2316,42 +2589,49 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "r-efi 5.3.0", + "wasip2", "wasm-bindgen", ] [[package]] -name = "gimli" -version = "0.32.3" +name = "getrandom" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "gloo-timers" @@ -2396,15 +2676,15 @@ dependencies = [ "opentelemetry", "opentelemetry_sdk", "regex", - "reqwest 0.12.24", + "reqwest 0.12.28", "rstest", - "rustls 0.23.35", + "rustls 0.23.38", "secrecy", "serde", "serde_json", "telemetry", "testcontainers", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-tungstenite 0.28.0", @@ -2436,9 +2716,9 @@ dependencies = [ [[package]] name = "graphql-ws-client" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c12b734aef65c081d988163f5a3b8991f4193c837aa5bfdcad96630e4f2385" +checksum = "4855443d93653e3b7a0378cf65eb680098600dfd2319a663ea45e49240084ec6" dependencies = [ "async-channel", "futures-lite", @@ -2449,7 +2729,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tungstenite 0.28.0", ] @@ -2516,9 +2796,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -2526,7 +2806,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.8.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -2535,35 +2815,49 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.3.1", - "indexmap 2.8.0", + "http 1.4.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + [[package]] name = "handlebars" -version = "5.1.2" +version = "6.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "9b3f9296c208515b87bd915a2f5d1163d4b3f863ba83337d7713cf478055948e" dependencies = [ + "derive_builder", "log", + "num-order", "pest", "pest_derive", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -2577,22 +2871,39 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", ] +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + [[package]] name = "hashlink" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.5", ] [[package]] @@ -2607,14 +2918,14 @@ dependencies = [ [[package]] name = "headers" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bytes", "headers-core", - "http 1.3.1", + "http 1.4.0", "httpdate", "mime", "sha1", @@ -2626,7 +2937,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -2643,9 +2954,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -2673,22 +2984,22 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "hostname" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" dependencies = [ "cfg-if", "libc", - "windows-link 0.1.1", + "windows-link", ] [[package]] @@ -2704,12 +3015,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -2731,7 +3041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -2742,7 +3052,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2775,14 +3085,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.9", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -2791,22 +3101,21 @@ dependencies = [ [[package]] name = "hyper" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", - "h2 0.4.8", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "httparse", "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -2819,7 +3128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ "hex", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "pin-project-lite", "tokio", @@ -2838,29 +3147,26 @@ dependencies = [ "hyper 0.14.32", "log", "rustls 0.21.12", - "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", ] [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "futures-util", - "http 1.3.1", - "hyper 1.8.1", + "http 1.4.0", + "hyper 1.9.0", "hyper-util", "log", - "rustls 0.23.35", - "rustls-native-certs 0.8.1", - "rustls-pki-types", + "rustls 0.23.38", + "rustls-native-certs 0.8.3", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", - "webpki-roots 0.26.8", + "webpki-roots 1.0.6", ] [[package]] @@ -2869,7 +3175,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "pin-project-lite", "tokio", @@ -2884,7 +3190,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "native-tls", "tokio", @@ -2894,23 +3200,22 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", - "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", - "hyper 1.8.1", + "hyper 1.9.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.3", "system-configuration", "tokio", "tower-service", @@ -2926,7 +3231,7 @@ checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" dependencies = [ "hex", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "pin-project-lite", "tokio", @@ -2935,9 +3240,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2959,121 +3264,91 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", + "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" +name = "icu_locale_core" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", + "litemap", "tinystr", + "writeable", "zerovec", ] -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ - "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", + "icu_locale_core", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] [[package]] -name = "icu_provider_macros" -version = "1.5.0" +name = "id-arena" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.107", -] +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] name = "ident_case" @@ -3083,9 +3358,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -3094,9 +3369,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -3121,13 +3396,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.17.0", "serde", + "serde_core", ] [[package]] @@ -3147,29 +3423,29 @@ checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "inventory" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" dependencies = [ "rustversion", ] [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" dependencies = [ "memchr", "serde", @@ -3177,9 +3453,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -3201,15 +3477,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.16" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" dependencies = [ "jiff-static", "log", @@ -3220,40 +3496,42 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.16" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] [[package]] name = "json-patch" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159294d661a039f7644cea7e4d844e6b25aaf71c1ffe9d73a96d768c24b0faf4" +checksum = "f300e415e2134745ef75f04562dd0145405c2f7fd92065db029ac4b16b57fe90" dependencies = [ "jsonptr", "serde", @@ -3271,7 +3549,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3292,7 +3570,7 @@ checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" dependencies = [ "aws-lc-rs", "base64 0.22.1", - "getrandom 0.2.15", + "getrandom 0.2.17", "js-sys", "pem", "serde", @@ -3303,9 +3581,9 @@ dependencies = [ [[package]] name = "k8s-openapi" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d13f06d5326a915becaffabdfab75051b8cdc260c2a5c06c0e90226ede89a692" +checksum = "06d9e5e61dd037cdc51da0d7e2b2be10f497478ea7e120d85dad632adb99882b" dependencies = [ "base64 0.22.1", "chrono", @@ -3338,23 +3616,23 @@ dependencies = [ "either", "futures", "home", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.5", + "hyper 1.9.0", + "hyper-rustls 0.27.9", "hyper-timeout", "hyper-util", "jsonpath-rust", "k8s-openapi", "kube-core", "pem", - "rustls 0.23.35", + "rustls 0.23.38", "secrecy", "serde", "serde_json", "serde_yaml", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", "tower", @@ -3371,14 +3649,14 @@ dependencies = [ "chrono", "derive_more", "form_urlencoded", - "http 1.3.1", + "http 1.4.0", "json-patch", "k8s-openapi", - "schemars 1.0.4", + "schemars 1.2.1", "serde", "serde-value", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3392,7 +3670,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -3407,7 +3685,7 @@ dependencies = [ "backon", "educe", "futures", - "hashbrown 0.15.2", + "hashbrown 0.15.5", "hostname", "json-patch", "k8s-openapi", @@ -3416,7 +3694,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", "tracing", @@ -3468,27 +3746,91 @@ dependencies = [ "x509-parser", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + [[package]] name = "libc" -version = "0.2.174" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.11" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ "bitflags", "libc", - "redox_syscall 0.6.0", + "plain", + "redox_syscall 0.7.4", ] [[package]] @@ -3509,21 +3851,22 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ + "cc", "pkg-config", "vcpkg", ] [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "litrs" @@ -3533,20 +3876,19 @@ checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", "serde", ] [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru" @@ -3554,7 +3896,24 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.5", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "mac_address" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" +dependencies = [ + "nix", + "serde", + "winapi", ] [[package]] @@ -3584,9 +3943,18 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] [[package]] name = "migration" @@ -3618,43 +3986,35 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] name = "mockito" -version = "1.7.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7760e0e418d9b7e5777c0374009ca4c93861b9066f18cb334a20ce50ab63aa48" +checksum = "90820618712cab19cfc46b274c6c22546a82affcb3c3bdf0f29e3db8e1bb92c0" dependencies = [ "assert-json-diff", "bytes", "colored", - "futures-util", - "http 1.3.1", + "futures-core", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "log", - "rand 0.9.2", + "pin-project-lite", + "rand 0.9.4", "regex", "serde_json", "serde_urlencoded", @@ -3664,9 +4024,9 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.11" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" dependencies = [ "async-lock", "crossbeam-channel", @@ -3677,7 +4037,6 @@ dependencies = [ "futures-util", "parking_lot", "portable-atomic", - "rustc_version", "smallvec", "tagptr", "uuid", @@ -3692,7 +4051,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.3.1", + "http 1.4.0", "httparse", "memchr", "mime", @@ -3702,21 +4061,34 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.2.1", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework 3.7.0", "security-framework-sys", "tempfile", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nom" version = "7.1.3" @@ -3729,11 +4101,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3762,11 +4134,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -3788,9 +4159,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-integer" @@ -3812,6 +4183,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -3835,9 +4221,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ "hermit-abi", "libc", @@ -3851,10 +4237,10 @@ checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" dependencies = [ "base64 0.22.1", "chrono", - "getrandom 0.2.15", - "http 1.3.1", + "getrandom 0.2.17", + "http 1.4.0", "rand 0.8.5", - "reqwest 0.12.24", + "reqwest 0.12.28", "serde", "serde_json", "serde_path_to_error", @@ -3874,11 +4260,11 @@ dependencies = [ "chrono", "colored", "futures", - "http 1.3.1", + "http 1.4.0", "jsonwebtoken", "once_cell", "rand 0.8.5", - "reqwest 0.12.24", + "reqwest 0.12.28", "rsa", "serde", "serde_json", @@ -3891,15 +4277,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "oid-registry" version = "0.6.1" @@ -3922,20 +4299,26 @@ dependencies = [ "chrono", "clap", "dotenvy", - "hyper 1.8.1", + "hyper 1.9.0", "moka", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tower-sessions", ] [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openidconnect" @@ -3948,7 +4331,7 @@ dependencies = [ "dyn-clone", "ed25519-dalek", "hmac", - "http 1.3.1", + "http 1.4.0", "itertools 0.10.5", "log", "oauth2", @@ -3970,9 +4353,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.75" +version = "0.10.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +checksum = "bfe4646e360ec77dff7dde40ed3d6c5fee52d156ef4a62f53973d38294dad87f" dependencies = [ "bitflags", "cfg-if", @@ -3991,7 +4374,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -4000,11 +4383,17 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "openssl-sys" -version = "0.9.111" +version = "0.9.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "ad2f2c0eba47118757e4c6d2bff2838f3e0523380021356e7875e858372ce644" dependencies = [ "cc", "libc", @@ -4022,7 +4411,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", ] @@ -4034,25 +4423,25 @@ checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" dependencies = [ "async-trait", "bytes", - "http 1.3.1", + "http 1.4.0", "opentelemetry", - "reqwest 0.12.24", + "reqwest 0.12.28", ] [[package]] name = "opentelemetry-otlp" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" +checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f" dependencies = [ - "http 1.3.1", + "http 1.4.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", "opentelemetry_sdk", "prost", - "reqwest 0.12.24", - "thiserror 2.0.17", + "reqwest 0.12.28", + "thiserror 2.0.18", "tokio", "tonic", "tracing", @@ -4088,8 +4477,8 @@ dependencies = [ "futures-util", "opentelemetry", "percent-encoding", - "rand 0.9.2", - "thiserror 2.0.17", + "rand 0.9.4", + "thiserror 2.0.18", "tokio", "tokio-stream", ] @@ -4133,7 +4522,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -4185,9 +4574,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -4195,15 +4584,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -4228,17 +4617,17 @@ dependencies = [ "regex", "regex-syntax", "structmeta", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "pem" -version = "3.0.5" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ "base64 0.22.1", - "serde", + "serde_core", ] [[package]] @@ -4252,26 +4641,25 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" dependencies = [ "memchr", - "thiserror 2.0.17", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" dependencies = [ "pest", "pest_generator", @@ -4279,24 +4667,23 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" dependencies = [ - "once_cell", "pest", "sha2", ] @@ -4312,29 +4699,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -4348,7 +4735,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der 0.7.9", + "der 0.7.10", "pkcs8 0.10.2", "spki 0.7.3", ] @@ -4369,15 +4756,21 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.9", + "der 0.7.10", "spki 0.7.3", ] [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "pluralizer" @@ -4389,21 +4782,44 @@ dependencies = [ "regex", ] +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -4429,6 +4845,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -4440,11 +4866,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit", + "toml_edit 0.25.11+spec-1.1.0", ] [[package]] @@ -4466,14 +4892,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -4486,16 +4912,16 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", "version_check", "yansi", ] [[package]] name = "prost" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -4503,22 +4929,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "prost-types" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" dependencies = [ "prost", ] @@ -4561,9 +4987,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", @@ -4571,9 +4997,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.35", - "socket2 0.5.9", - "thiserror 2.0.17", + "rustls 0.23.38", + "socket2 0.6.3", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -4581,19 +5007,20 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.10" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", - "getrandom 0.3.2", - "rand 0.9.2", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", "ring 0.17.14", "rustc-hash", - "rustls 0.23.35", + "rustls 0.23.38", "rustls-pki-types", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -4601,32 +5028,38 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.11" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.9", + "socket2 0.6.3", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.41" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "radium" @@ -4647,12 +5080,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4672,7 +5105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4681,32 +5114,32 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "redox_syscall" -version = "0.6.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ "bitflags", ] @@ -4728,14 +5161,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -4745,9 +5178,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -4756,23 +5189,23 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "regress" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145bb27393fe455dd64d6cbc8d059adfa392590a45eadf079c01b11857e7b010" +checksum = "2057b2325e68a893284d1538021ab90279adac1139957ca2a74426c6f118fb48" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.16.1", "memchr", ] @@ -4793,9 +5226,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.24" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", @@ -4805,12 +5238,12 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.8", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.5", + "hyper 1.9.0", + "hyper-rustls 0.27.9", "hyper-tls", "hyper-util", "js-sys", @@ -4821,7 +5254,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.35", + "rustls 0.23.38", "rustls-pki-types", "serde", "serde_json", @@ -4829,7 +5262,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tokio-util", "tower", "tower-http 0.6.8", @@ -4852,12 +5285,12 @@ dependencies = [ "bytes", "encoding_rs", "futures-core", - "h2 0.4.8", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.5", + "hyper 1.9.0", + "hyper-rustls 0.27.9", "hyper-util", "js-sys", "log", @@ -4879,11 +5312,11 @@ dependencies = [ [[package]] name = "reserve-port" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21918d6644020c6f6ef1993242989bf6d4952d2e025617744f184c02df51c356" +checksum = "94070964579245eb2f76e62a7668fe87bd9969ed6c41256f3bf614e3323dd3cc" dependencies = [ - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -4930,7 +5363,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.17", "libc", "untrusted 0.9.0", "windows-sys 0.52.0", @@ -4938,9 +5371,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" dependencies = [ "bitvec", "bytecheck", @@ -4956,9 +5389,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" dependencies = [ "proc-macro2", "quote", @@ -4967,9 +5400,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", @@ -5010,7 +5443,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.107", + "syn 2.0.117", "unicode-ident", ] @@ -5023,17 +5456,17 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "mime", - "rand 0.9.2", - "thiserror 2.0.17", + "rand 0.9.4", + "thiserror 2.0.18", ] [[package]] name = "rust_decimal" -version = "1.39.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +checksum = "2ce901f9a19d251159075a4c37af514c3b8ef99c22e02dd8c19161cf397ee94a" dependencies = [ "arrayvec", "borsh", @@ -5043,19 +5476,14 @@ dependencies = [ "rkyv", "serde", "serde_json", + "wasm-bindgen", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -5090,15 +5518,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5115,16 +5543,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring 0.17.14", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.12", "subtle", "zeroize", ] @@ -5135,7 +5563,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ - "openssl-probe", + "openssl-probe 0.1.6", "rustls-pemfile", "schannel", "security-framework 2.11.1", @@ -5143,14 +5571,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework 3.7.0", ] [[package]] @@ -5164,9 +5592,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -5184,9 +5612,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" dependencies = [ "aws-lc-rs", "ring 0.17.14", @@ -5196,15 +5624,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -5217,11 +5645,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5250,13 +5678,13 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ "dyn-clone", "ref-cast", - "schemars_derive 1.0.4", + "schemars_derive 1.2.1", "serde", "serde_json", ] @@ -5270,19 +5698,19 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "schemars_derive" -version = "1.0.4" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -5311,14 +5739,14 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "sea-orm" -version = "2.0.0-rc.19" +version = "2.0.0-rc.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6dda57d64724c4c3e2b39ce17ca5f4084561656a3518b65b26edc5b36e4607" +checksum = "9b5428ce6a0c8f6b9858df21ad1aa00c2fb94e1c9f344a0436bc855391e5a225" dependencies = [ "async-stream", "async-trait", @@ -5328,9 +5756,11 @@ dependencies = [ "futures-util", "itertools 0.14.0", "log", + "mac_address", "ouroboros", "pgvector", "rust_decimal", + "sea-orm-arrow", "sea-orm-macros", "sea-query", "sea-query-sqlx", @@ -5338,19 +5768,30 @@ dependencies = [ "serde", "serde_json", "sqlx", - "strum 0.27.2", - "thiserror 2.0.17", + "strum 0.28.0", + "thiserror 2.0.18", "time", "tracing", "url", "uuid", ] +[[package]] +name = "sea-orm-arrow" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2eee8405f16c1f337fe3a83389361caea83c928d14dbd666a480407072c365" +dependencies = [ + "arrow", + "sea-query", + "thiserror 2.0.18", +] + [[package]] name = "sea-orm-cli" -version = "2.0.0-rc.19" +version = "2.0.0-rc.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63b7fcf2623bfc47e4fcca48fd35f77fd376611935862a6e316991d035ac85c" +checksum = "4cd42605c3b611785eed593406900f463b86c61792e723272e0434e77ed9cd8d" dependencies = [ "chrono", "clap", @@ -5368,24 +5809,25 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "2.0.0-rc.19" +version = "2.0.0-rc.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7674a565e093a4bfffbfd6d7fd79a5dc8d75463d442ffb44d0fc3a3dcce5a6" +checksum = "ae1374d83dd5b43f14dcc90fc726486c556f4db774b680b12b8c680af76e8233" dependencies = [ "heck 0.5.0", + "itertools 0.14.0", "pluralizer", "proc-macro2", "quote", "sea-bae", - "syn 2.0.107", + "syn 2.0.117", "unicode-ident", ] [[package]] name = "sea-orm-migration" -version = "2.0.0-rc.19" +version = "2.0.0-rc.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c77522b82141205bd99137be96b81b4540531f9ff7773b77d70f5749c39dcc" +checksum = "73f6ce467587c910bb2842cf001ea600ac6228ba5f3f39c1dc499929e34a8f29" dependencies = [ "async-trait", "clap", @@ -5399,11 +5841,10 @@ dependencies = [ [[package]] name = "sea-query" -version = "1.0.0-rc.20" +version = "1.0.0-rc.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ebab2b9d558deec08e43887a63ed4d96d56b32cb9d98578bd1749e2c8c7e24" +checksum = "b04cdb0135c16e829504e93fbe7880513578d56f07aaea152283526590111828" dependencies = [ - "bigdecimal", "chrono", "inherent", "ordered-float 4.6.0", @@ -5416,39 +5857,33 @@ dependencies = [ [[package]] name = "sea-query-derive" -version = "1.0.0-rc.11" +version = "1.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365d236217f5daa4f40d3c9998ff3921351b53472da50308e384388162353b3a" +checksum = "8d88ad44b6ad9788c8b9476b6b91f94c7461d1e19d39cd8ea37838b1e6ff5aa8" dependencies = [ "darling 0.20.11", "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.107", - "thiserror 2.0.17", + "syn 2.0.117", + "thiserror 2.0.18", ] [[package]] name = "sea-query-sqlx" -version = "0.8.0-rc.9" +version = "0.8.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68873fa1776b4c25a26e7679f8ee22332978c721168ec1b0b32b6583d5a9381d" +checksum = "a04aeecfe00614fece56336fd35dc385bb9ffed0c75660695ba925e42a3991ef" dependencies = [ - "bigdecimal", - "chrono", - "rust_decimal", "sea-query", - "serde_json", "sqlx", - "time", - "uuid", ] [[package]] name = "sea-schema" -version = "0.17.0-rc.16" +version = "0.17.0-rc.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "845b7ed3e7a4f4458fe7218931b54e92be0dce01fc3c310d996c7b76d9a37ea5" +checksum = "b363dd21c20fe4d1488819cb2bc7f8d4696c62dd9f39554f97639f54d57dd0ab" dependencies = [ "async-trait", "sea-query", @@ -5466,7 +5901,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -5496,7 +5931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct 0.2.0", - "der 0.7.9", + "der 0.7.10", "generic-array", "pkcs8 0.10.2", "subtle", @@ -5527,12 +5962,12 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -5540,9 +5975,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -5550,9 +5985,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -5595,7 +6030,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -5606,30 +6041,31 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -5649,28 +6085,28 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] [[package]] name = "serde_tokenstream" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64060d864397305347a78851c51588fd283767e7e7589829e8121d65512340f1" +checksum = "d7c49585c52c01f13c5c2ebb333f14f6885d76daa768d8a037d28017ec538c69" dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -5687,17 +6123,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.16.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1" +checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.8.0", + "indexmap 2.14.0", "schemars 0.9.0", - "schemars 1.0.4", + "schemars 1.2.1", "serde_core", "serde_json", "serde_with_macros", @@ -5706,14 +6142,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.16.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b" +checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" dependencies = [ - "darling 0.21.3", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -5722,7 +6158,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.14.0", "itoa", "ryu", "serde", @@ -5794,10 +6230,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -5835,24 +6272,21 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_asn1" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -5865,9 +6299,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5875,12 +6309,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5927,7 +6361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der 0.7.9", + "der 0.7.10", ] [[package]] @@ -5950,7 +6384,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ "base64 0.22.1", - "bigdecimal", "bytes", "chrono", "crc", @@ -5961,27 +6394,27 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.2", + "hashbrown 0.15.5", "hashlink", - "indexmap 2.8.0", + "indexmap 2.14.0", "log", "memchr", "once_cell", "percent-encoding", "rust_decimal", - "rustls 0.23.35", + "rustls 0.23.38", "serde", "serde_json", "sha2", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tokio", "tokio-stream", "tracing", "url", "uuid", - "webpki-roots 0.26.8", + "webpki-roots 0.26.11", ] [[package]] @@ -5994,7 +6427,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -6017,7 +6450,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.107", + "syn 2.0.117", "tokio", "url", ] @@ -6030,7 +6463,6 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", "base64 0.22.1", - "bigdecimal", "bitflags", "byteorder", "bytes", @@ -6062,7 +6494,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tracing", "uuid", @@ -6077,7 +6509,6 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64 0.22.1", - "bigdecimal", "bitflags", "byteorder", "chrono", @@ -6095,7 +6526,6 @@ dependencies = [ "log", "md-5", "memchr", - "num-bigint", "once_cell", "rand 0.8.5", "rust_decimal", @@ -6105,7 +6535,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tracing", "uuid", @@ -6132,7 +6562,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tracing", "url", @@ -6141,9 +6571,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -6183,7 +6613,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -6194,16 +6624,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", -] - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros 0.26.4", + "syn 2.0.117", ] [[package]] @@ -6212,33 +6633,25 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ - "strum_macros 0.27.1", + "strum_macros", ] [[package]] -name = "strum_macros" -version = "0.26.4" +name = "strum" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.107", -] +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" [[package]] name = "strum_macros" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "rustversion", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -6260,9 +6673,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.107" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -6292,20 +6705,20 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ "bitflags", "core-foundation 0.9.4", @@ -6345,7 +6758,7 @@ dependencies = [ "opentelemetry-otlp", "opentelemetry-semantic-conventions", "opentelemetry_sdk", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "tracing-opentelemetry", @@ -6355,15 +6768,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6381,7 +6794,7 @@ dependencies = [ "etcetera 0.11.0", "ferroid", "futures", - "http 1.3.1", + "http 1.4.0", "itertools 0.14.0", "log", "memchr", @@ -6391,7 +6804,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-util", @@ -6409,11 +6822,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -6424,28 +6837,27 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -6479,11 +6891,20 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -6491,9 +6912,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -6506,9 +6927,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776" dependencies = [ "bytes", "libc", @@ -6516,20 +6937,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.0", + "socket2 0.6.3", "tokio-macros", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -6554,19 +6975,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.35", + "rustls 0.23.38", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -6575,33 +6996,33 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.21.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.21.0", + "tungstenite 0.28.0", ] [[package]] name = "tokio-tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.28.0", + "tungstenite 0.29.0", ] [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -6614,58 +7035,95 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.14.0", "serde", "serde_spanned", - "toml_datetime", - "winnow", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.1", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.1", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tonic" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" dependencies = [ "async-trait", "axum", "base64 0.22.1", "bytes", - "h2 0.4.8", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-timeout", "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.0", + "socket2 0.6.3", "sync_wrapper", "tokio", "tokio-stream", @@ -6677,9 +7135,9 @@ dependencies = [ [[package]] name = "tonic-prost" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" dependencies = [ "bytes", "prost", @@ -6701,14 +7159,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", "hdrhistogram", - "indexmap 2.8.0", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -6728,7 +7186,7 @@ dependencies = [ "axum-core", "cookie", "futures-util", - "http 1.3.1", + "http 1.4.0", "parking_lot", "pin-project-lite", "tower-layer", @@ -6743,7 +7201,7 @@ checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "bitflags", "bytes", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "pin-project-lite", @@ -6762,7 +7220,7 @@ dependencies = [ "bitflags", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "iri-string", "mime", @@ -6792,7 +7250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a05911f23e8fae446005fe9b7b97e66d95b6db589dc1c4d59f6a2d4d4927d3" dependencies = [ "async-trait", - "http 1.3.1", + "http 1.4.0", "time", "tokio", "tower-cookies", @@ -6813,12 +7271,12 @@ dependencies = [ "axum-core", "base64 0.22.1", "futures", - "http 1.3.1", + "http 1.4.0", "parking_lot", "rand 0.8.5", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tokio", "tracing", @@ -6838,9 +7296,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -6850,20 +7308,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -6882,16 +7340,13 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6e5658463dd88089aba75c7791e1d3120633b1bfde22478b28f625a9bb1b8e" +checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" dependencies = [ "js-sys", "opentelemetry", - "opentelemetry_sdk", - "rustversion", "smallvec", - "thiserror 2.0.17", "tracing", "tracing-core", "tracing-log", @@ -6901,9 +7356,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -6925,38 +7380,35 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.21.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ - "byteorder", "bytes", "data-encoding", - "http 1.3.1", + "http 1.4.0", "httparse", "log", - "rand 0.8.5", + "rand 0.9.4", "sha1", - "thiserror 1.0.69", - "url", + "thiserror 2.0.18", "utf-8", ] [[package]] name = "tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", - "http 1.3.1", + "http 1.4.0", "httparse", "log", - "rand 0.9.2", + "rand 0.9.4", "sha1", - "thiserror 2.0.17", - "utf-8", + "thiserror 2.0.18", ] [[package]] @@ -6967,9 +7419,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "typetag" @@ -6992,7 +7444,7 @@ checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] @@ -7020,8 +7472,8 @@ dependencies = [ "semver", "serde", "serde_json", - "syn 2.0.107", - "thiserror 2.0.17", + "syn 2.0.117", + "thiserror 2.0.18", "unicode-ident", ] @@ -7038,7 +7490,7 @@ dependencies = [ "serde", "serde_json", "serde_tokenstream", - "syn 2.0.107", + "syn 2.0.117", "typify-impl", ] @@ -7050,9 +7502,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-bidi" @@ -7062,24 +7514,30 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-xid" @@ -7114,7 +7572,7 @@ dependencies = [ "base64 0.22.1", "log", "percent-encoding", - "rustls 0.23.35", + "rustls 0.23.38", "rustls-pki-types", "ureq-proto", "utf8-zero", @@ -7127,21 +7585,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" dependencies = [ "base64 0.22.1", - "http 1.3.1", + "http 1.4.0", "httparse", "log", ] [[package]] name = "url" -version = "2.5.4" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -7150,12 +7609,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8-zero" version = "0.8.1" @@ -7176,11 +7629,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.4.2", "js-sys", "serde_core", "wasm-bindgen", @@ -7231,17 +7684,26 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -7252,48 +7714,33 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", "rustversion", + "serde", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.107", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7301,26 +7748,48 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.107", - "wasm-bindgen-backend", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasm-streams" version = "0.4.2" @@ -7334,11 +7803,23 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "semver", +] + [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -7356,11 +7837,11 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.8" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "rustls-pki-types", + "webpki-roots 1.0.6", ] [[package]] @@ -7374,11 +7855,11 @@ dependencies = [ [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall 0.5.10", + "libredox", "wasite", ] @@ -7400,11 +7881,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7415,78 +7896,72 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.1", + "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link 0.1.1", + "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.1.1", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.1.1", + "windows-link", ] [[package]] @@ -7507,31 +7982,22 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.4", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -7567,11 +8033,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.2.0", + "windows-link", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -7722,9 +8188,18 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" dependencies = [ "memchr", ] @@ -7739,9 +8214,9 @@ dependencies = [ "base64 0.22.1", "deadpool", "futures", - "http 1.3.1", + "http 1.4.0", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "log", "once_cell", @@ -7753,25 +8228,98 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.14.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ + "anyhow", "bitflags", + "indexmap 2.14.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", ] [[package]] -name = "write16" -version = "1.0.0" +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.14.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wyz" @@ -7823,11 +8371,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -7835,68 +8382,79 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", - "synstructure 0.13.1", + "syn 2.0.117", + "synstructure 0.13.2", ] [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", - "synstructure 0.13.1", + "syn 2.0.117", + "synstructure 0.13.2", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -7905,11 +8463,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.117", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"