diff --git a/.github/workflows/release-agent.yml b/.github/workflows/release-agent.yml index 9e2fa7b..2021f40 100644 --- a/.github/workflows/release-agent.yml +++ b/.github/workflows/release-agent.yml @@ -14,8 +14,119 @@ permissions: contents: write jobs: + prepare: + name: Verify sqlx cache + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:18-alpine + env: + POSTGRES_USER: lynx_ci + POSTGRES_PASSWORD: lynx_ci + POSTGRES_DB: lynx_ci + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 5s + --health-timeout 5s + --health-retries 10 + + defaults: + run: + working-directory: lynx + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable + with: + toolchain: stable + + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + workspaces: lynx + + - name: Install sqlx-cli + run: cargo install sqlx-cli --no-default-features --features postgres --locked + + - name: Run migrations + env: + DATABASE_URL: postgres://lynx_ci:lynx_ci@localhost:5432/lynx_ci + run: | + sqlx migrate run --source agent/migrations + sqlx migrate run --source dashboard/server/migrations + + - name: Verify sqlx cache is up-to-date + env: + DATABASE_URL: postgres://lynx_ci:lynx_ci@localhost:5432/lynx_ci + run: cargo sqlx prepare --check --workspace + + ci: + name: CI checks + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:18-alpine + env: + POSTGRES_USER: lynx_ci + POSTGRES_PASSWORD: lynx_ci + POSTGRES_DB: lynx_ci + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 5s + --health-timeout 5s + --health-retries 10 + + defaults: + run: + working-directory: lynx + + env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + DATABASE_URL: postgres://lynx_ci:lynx_ci@localhost:5432/lynx_ci + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable + with: + toolchain: stable + components: rustfmt, clippy + + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + workspaces: lynx + + - name: Install sqlx-cli + run: cargo install sqlx-cli --no-default-features --features postgres --locked + + - name: Install cargo-audit + run: cargo install cargo-audit --locked + + - name: Run agent migrations + run: sqlx migrate run --source agent/migrations + + - name: fmt + run: cargo fmt --package lynx-agent -- --check + + - name: clippy + run: cargo clippy --package lynx-agent -- -D warnings + + - name: test + run: cargo test --package lynx-agent --bin lynx-agent + + - name: audit + run: cargo audit --ignore RUSTSEC-2023-0071 + build: name: Build ${{ matrix.arch }} + needs: [prepare, ci] runs-on: ubuntu-latest strategy: @@ -79,7 +190,7 @@ jobs: cp "$BINARY" "$ARTIFACT" python3 .github/scripts/sign.py "$RELEASE_SIGN_KEY" "$ARTIFACT" - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: agent-${{ matrix.arch }} path: | @@ -95,7 +206,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: merge-multiple: true diff --git a/.github/workflows/release-dashboard.yml b/.github/workflows/release-dashboard.yml index 7bb0c72..69814a7 100644 --- a/.github/workflows/release-dashboard.yml +++ b/.github/workflows/release-dashboard.yml @@ -20,17 +20,17 @@ jobs: services: postgres: - image: postgres:18 + image: postgres:18-alpine env: - POSTGRES_DB: lynx_dashboard - POSTGRES_USER: postgres - POSTGRES_PASSWORD: ci_test + POSTGRES_USER: lynx_ci + POSTGRES_PASSWORD: lynx_ci + POSTGRES_DB: lynx_ci ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 5s - --health-timeout 3s + --health-timeout 5s --health-retries 10 defaults: @@ -53,17 +53,117 @@ jobs: - name: Run migrations env: - DATABASE_URL: postgresql://postgres:ci_test@localhost:5432/lynx_dashboard - run: sqlx migrate run --source dashboard/server/migrations + DATABASE_URL: postgres://lynx_ci:lynx_ci@localhost:5432/lynx_ci + run: | + sqlx migrate run --source dashboard/server/migrations + sqlx migrate run --source agent/migrations - name: Verify sqlx cache is up-to-date env: - DATABASE_URL: postgresql://postgres:ci_test@localhost:5432/lynx_dashboard + DATABASE_URL: postgres://lynx_ci:lynx_ci@localhost:5432/lynx_ci run: cargo sqlx prepare --check --workspace + ci-server: + name: CI server (Rust) + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:18-alpine + env: + POSTGRES_USER: lynx_ci + POSTGRES_PASSWORD: lynx_ci + POSTGRES_DB: lynx_ci + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 5s + --health-timeout 5s + --health-retries 10 + redis: + image: redis:8-alpine + ports: + - 6379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval 5s + --health-timeout 5s + --health-retries 10 + + defaults: + run: + working-directory: lynx + + env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + DATABASE_URL: postgres://lynx_ci:lynx_ci@localhost:5432/lynx_ci + REDIS_URL: redis://localhost:6379 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable + with: + toolchain: stable + components: rustfmt, clippy + + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + workspaces: lynx + + - name: Install sqlx-cli + run: cargo install sqlx-cli --no-default-features --features postgres --locked + + - name: Install cargo-audit + run: cargo install cargo-audit --locked + + - name: Run migrations + run: sqlx migrate run --source dashboard/server/migrations + + - name: fmt + run: cargo fmt --package lynx-dashboard-server -- --check + + - name: clippy + run: cargo clippy --package lynx-dashboard-server -- -D warnings + + - name: test + run: cargo test --package lynx-dashboard-server -- --test-threads=1 + + - name: audit + run: cargo audit --ignore RUSTSEC-2023-0071 + + ci-ui: + name: CI UI (frontend) + runs-on: ubuntu-latest + + defaults: + run: + working-directory: lynx/dashboard/ui + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: typecheck + run: bun run typecheck + + - name: test + run: bun run test + + - name: audit + run: bun audit --audit-level high + build: name: Build ${{ matrix.arch }} - needs: prepare + needs: [prepare, ci-server, ci-ui] runs-on: ubuntu-latest strategy: @@ -187,7 +287,7 @@ jobs: # --- Upload artifacts --------------------------------------------------- - name: Upload release artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: dashboard-${{ matrix.arch }} path: | @@ -207,7 +307,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: merge-multiple: true diff --git a/lynx/Cargo.lock b/lynx/Cargo.lock index 3d94be1..ab30d7d 100644 --- a/lynx/Cargo.lock +++ b/lynx/Cargo.lock @@ -14,7 +14,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "generic-array", ] @@ -132,6 +132,12 @@ dependencies = [ "rustversion", ] +[[package]] +name = "arcstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" + [[package]] name = "argon2" version = "0.5.3" @@ -146,9 +152,9 @@ dependencies = [ [[package]] name = "asn1-rs" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -156,15 +162,15 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", @@ -184,14 +190,14 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.89" +name = "async-lock" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "proc-macro2", - "quote", - "syn", + "event-listener", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -267,7 +273,7 @@ dependencies = [ "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite 0.29.0", + "tokio-tungstenite", "tower", "tower-layer", "tower-service", @@ -354,10 +360,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] -name = "bitflags" -version = "1.3.2" +name = "bit-vec" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] [[package]] name = "bitflags" @@ -374,7 +383,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -386,11 +395,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bollard" -version = "0.17.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41711ad46fda47cd701f6908e59d1bd6b9a2b7464c0d0aeab95c6d37096ff8a" +checksum = "c9d0a013e3d3ee4edd61e779adf117944c08902d375f18630a0c5b8f95659734" dependencies = [ "base64", "bollard-stubs", @@ -409,9 +427,8 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_repr", "serde_urlencoded", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-util", "tower-service", @@ -421,22 +438,13 @@ dependencies = [ [[package]] name = "bollard-stubs" -version = "1.45.0-rc.26.0.1" +version = "1.53.1-rc.29.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7c5415e3a6bc6d3e99eff6268e488fd4ee25e7b28c10f08fa6760bd9de16e4" +checksum = "ce412eb6f7096743011dc3cb5c674caeb24ced61d8c498fe07cf7998a4fea889" dependencies = [ "serde", + "serde_json", "serde_repr", - "serde_with", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", ] [[package]] @@ -518,7 +526,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "inout", ] @@ -606,6 +614,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cookie" version = "0.18.1" @@ -674,15 +688,6 @@ dependencies = [ "cfg-if", ] -[[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-queue" version = "0.3.12" @@ -709,6 +714,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + [[package]] name = "ctr" version = "0.9.2" @@ -727,7 +741,7 @@ dependencies = [ "cfg-if", "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest", + "digest 0.10.7", "fiat-crypto", "rustc_version", "subtle", @@ -757,16 +771,16 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "pem-rfc7468", "zeroize", ] [[package]] name = "der-parser" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ "asn1-rs", "displaydoc", @@ -783,7 +797,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", - "serde_core", ] [[package]] @@ -798,12 +811,23 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -827,12 +851,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - [[package]] name = "ed25519" version = "2.2.3" @@ -852,7 +870,7 @@ dependencies = [ "curve25519-dalek", "ed25519", "serde", - "sha2", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -924,6 +942,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "expect-json" version = "1.10.1" @@ -937,7 +965,7 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror", "typetag", "uuid", ] @@ -1207,12 +1235,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.15.5" @@ -1266,7 +1288,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -1323,6 +1345,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.9.0" @@ -1392,7 +1423,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2", "tokio", "tower-service", "tracing", @@ -1546,17 +1577,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - [[package]] name = "indexmap" version = "2.14.0" @@ -1571,11 +1591,11 @@ dependencies = [ [[package]] name = "inotify" -version = "0.9.6" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 1.3.2", + "bitflags", "inotify-sys", "libc", ] @@ -1628,15 +1648,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.18" @@ -1666,7 +1677,7 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror", "time", ] @@ -1698,7 +1709,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" dependencies = [ - "bitflags 2.11.1", + "bitflags", "libc", ] @@ -1735,7 +1746,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.11.1", + "bitflags", "libc", "plain", "redox_syscall 0.7.5", @@ -1806,19 +1817,19 @@ dependencies = [ "hyper-util", "lynx-compose", "nix", - "rand 0.8.6", + "rand 0.10.1", "rcgen", "reqwest", "rustls", "serde", "serde_json", - "sha2", + "sha2 0.11.0", "sqlx", "subtle", - "thiserror 2.0.18", + "thiserror", "tokio", "tokio-rustls", - "tokio-tungstenite 0.24.0", + "tokio-tungstenite", "tower", "tower-http", "tracing", @@ -1838,13 +1849,13 @@ dependencies = [ "clap", "flate2", "futures", - "indexmap 2.14.0", + "indexmap", "libc", "notify", "serde", "tar", "tempfile", - "thiserror 2.0.18", + "thiserror", "tokio", "tracing", "tracing-subscriber", @@ -1867,17 +1878,17 @@ dependencies = [ "ed25519-dalek", "futures-util", "josekit", - "rand 0.8.6", + "rand 0.10.1", "rcgen", "redis", "reqwest", "rustls", "serde", "serde_json", - "sha2", + "sha2 0.11.0", "sqlx", "subtle", - "thiserror 2.0.18", + "thiserror", "tokio", "tokio-rustls", "tower", @@ -1913,7 +1924,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -1944,18 +1955,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", -] - [[package]] name = "mio" version = "1.2.0" @@ -1963,17 +1962,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.61.2", ] [[package]] name = "nix" -version = "0.29.0" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.11.1", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -1991,21 +1991,29 @@ dependencies = [ [[package]] name = "notify" -version = "6.1.1" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.1", - "crossbeam-channel", - "filetime", + "bitflags", "fsevent-sys", "inotify", "kqueue", "libc", "log", - "mio 0.8.11", + "mio", + "notify-types", "walkdir", - "windows-sys 0.48.0", + "windows-sys 0.60.2", +] + +[[package]] +name = "notify-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags", ] [[package]] @@ -2068,9 +2076,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -2115,9 +2123,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" dependencies = [ "asn1-rs", ] @@ -2146,7 +2154,7 @@ version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ - "bitflags 2.11.1", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -2365,8 +2373,8 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.3", - "thiserror 2.0.18", + "socket2", + "thiserror", "tokio", "tracing", "web-time", @@ -2387,7 +2395,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.18", + "thiserror", "tinyvec", "tracing", "web-time", @@ -2402,7 +2410,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -2506,9 +2514,9 @@ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" dependencies = [ "pem", "ring", @@ -2520,28 +2528,30 @@ dependencies = [ [[package]] name = "redis" -version = "0.27.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d8f99a4090c89cc489a94833c901ead69bfbf3877b4867d5482e321ee875bc" +checksum = "72d32a1ac9123f0d84fda64bfc02a271d9868483162dd2d9099b5c362ece064c" dependencies = [ "arc-swap", - "async-trait", + "arcstr", + "async-lock", "backon", "bytes", + "cfg-if", "combine", - "futures", + "futures-channel", "futures-util", - "itertools", "itoa", "num-bigint", "percent-encoding", "pin-project-lite", "ryu", "sha1_smol", - "socket2 0.5.10", + "socket2", "tokio", "tokio-util", "url", + "xxhash-rust", ] [[package]] @@ -2550,7 +2560,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags", ] [[package]] @@ -2559,27 +2569,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4666a1a60d8412eab19d94f6d13dcc9cea0a5ef4fdf6a5db306537413c661b1b" dependencies = [ - "bitflags 2.11.1", -] - -[[package]] -name = "ref-cast" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "bitflags", ] [[package]] @@ -2658,7 +2648,7 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94070964579245eb2f76e62a7668fe87bd9969ed6c41256f3bf614e3323dd3cc" dependencies = [ - "thiserror 2.0.18", + "thiserror", ] [[package]] @@ -2681,8 +2671,8 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", @@ -2707,7 +2697,7 @@ dependencies = [ "http", "mime", "rand 0.10.1", - "thiserror 2.0.18", + "thiserror", ] [[package]] @@ -2740,7 +2730,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -2827,30 +2817,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -2863,7 +2829,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.1", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -2922,7 +2888,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.14.0", + "indexmap", "itoa", "memchr", "serde", @@ -2964,25 +2930,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" -dependencies = [ - "base64", - "bs58", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.14.0", - "schemars 0.9.0", - "schemars 1.2.1", - "serde_core", - "serde_json", - "time", -] - [[package]] name = "sha1" version = "0.10.6" @@ -2991,7 +2938,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", ] [[package]] @@ -3008,7 +2955,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -3042,7 +3000,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -3067,16 +3025,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.3" @@ -3138,7 +3086,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.5", "hashlink", - "indexmap 2.14.0", + "indexmap", "ipnetwork", "log", "memchr", @@ -3147,9 +3095,9 @@ dependencies = [ "rustls", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", - "thiserror 2.0.18", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -3186,7 +3134,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -3204,12 +3152,12 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", "base64", - "bitflags 2.11.1", + "bitflags", "byteorder", "bytes", "chrono", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -3230,11 +3178,11 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.18", + "thiserror", "tracing", "uuid", "whoami", @@ -3248,7 +3196,7 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64", - "bitflags 2.11.1", + "bitflags", "byteorder", "chrono", "crc", @@ -3270,11 +3218,11 @@ dependencies = [ "rand 0.8.6", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.18", + "thiserror", "tracing", "uuid", "whoami", @@ -3300,7 +3248,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.18", + "thiserror", "tracing", "url", "uuid", @@ -3368,9 +3316,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.45" +version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" dependencies = [ "filetime", "libc", @@ -3390,33 +3338,13 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.18", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "thiserror-impl", ] [[package]] @@ -3503,11 +3431,11 @@ checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", - "mio 1.2.0", + "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -3546,9 +3474,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.24.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", @@ -3557,19 +3485,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite 0.24.0", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.29.0", + "tungstenite", ] [[package]] @@ -3603,11 +3519,11 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.1", + "bitflags", "bytes", "futures-util", "http", @@ -3701,26 +3617,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.8.6", - "rustls", - "rustls-pki-types", - "sha1", - "thiserror 1.0.69", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.29.0" @@ -3733,8 +3629,10 @@ dependencies = [ "httparse", "log", "rand 0.9.4", + "rustls", + "rustls-pki-types", "sha1", - "thiserror 2.0.18", + "thiserror", ] [[package]] @@ -3812,7 +3710,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "subtle", ] @@ -3834,12 +3732,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4003,7 +3895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.14.0", + "indexmap", "wasm-encoder", "wasmparser", ] @@ -4027,9 +3919,9 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags", "hashbrown 0.15.5", - "indexmap 2.14.0", + "indexmap", "semver", ] @@ -4427,7 +4319,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap 2.14.0", + "indexmap", "prettyplease", "syn", "wasm-metadata", @@ -4457,8 +4349,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", - "indexmap 2.14.0", + "bitflags", + "indexmap", "log", "serde", "serde_derive", @@ -4477,7 +4369,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.14.0", + "indexmap", "log", "semver", "serde", @@ -4507,9 +4399,9 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", "data-encoding", @@ -4519,7 +4411,7 @@ dependencies = [ "oid-registry", "ring", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] @@ -4533,13 +4425,19 @@ dependencies = [ "rustix", ] +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yaml_serde" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c7c1b1a6a7c8a6b2741a6c21a4f8918e51899b111cfa08d1288202656e3975" dependencies = [ - "indexmap 2.14.0", + "indexmap", "itoa", "libyaml-rs", "ryu", @@ -4554,10 +4452,11 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] diff --git a/lynx/Cargo.toml b/lynx/Cargo.toml index cc76433..33a3f98 100644 --- a/lynx/Cargo.toml +++ b/lynx/Cargo.toml @@ -26,7 +26,7 @@ tower-http = { version = "0.6", features = ["trace", "cors", "set-header", "limi sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio-rustls", "postgres", "uuid", "chrono", "migrate", "ipnetwork", "macros"] } # cache -redis = { version = "0.27", features = ["tokio-comp", "connection-manager"] } +redis = { version = "1.2", features = ["tokio-comp", "connection-manager"] } # auth argon2 = "0.5" @@ -35,14 +35,14 @@ subtle = "2" zeroize = { version = "1", features = ["derive"] } # crypto primitives -rand = "0.8" -sha2 = "0.10" +rand = "0.10" +sha2 = "0.11" aes-gcm = "0.10" base64ct = { version = "1", features = ["alloc"] } ed25519-dalek = { version = "2", features = ["pkcs8", "zeroize"] } x25519-dalek = { version = "2", features = ["static_secrets", "zeroize"] } -rcgen = { version = "0.13", features = ["x509-parser"] } -x509-parser = "0.16" +rcgen = { version = "0.14", features = ["x509-parser"] } +x509-parser = "0.18" rustls = { version = "0.23", default-features = false, features = ["ring"] } tokio-rustls = "0.26" @@ -51,7 +51,7 @@ uuid = { version = "1", features = ["v7", "serde"] } chrono = { version = "0.4", features = ["serde"] } # WebSocket (agent client) -tokio-tungstenite = { version = "0.24", features = ["rustls-tls-native-roots"] } +tokio-tungstenite = { version = "0.29", features = ["rustls-tls-native-roots"] } futures-util = "0.3" [profile.release] diff --git a/lynx/agent/Cargo.toml b/lynx/agent/Cargo.toml index 90fa76d..1d62886 100644 --- a/lynx/agent/Cargo.toml +++ b/lynx/agent/Cargo.toml @@ -50,6 +50,6 @@ chrono = { workspace = true } uuid = { workspace = true } # system interaction -nix = { version = "0.29", features = ["process", "signal", "fs"] } +nix = { version = "0.31", features = ["process", "signal", "fs"] } lynx-compose = { path = "../translators/compose" } diff --git a/lynx/agent/src/config.rs b/lynx/agent/src/config.rs index c7326b7..c03799e 100644 --- a/lynx/agent/src/config.rs +++ b/lynx/agent/src/config.rs @@ -103,7 +103,8 @@ fn load_key32_or_dev(env: &str) -> Result<[u8; 32]> { if std::env::var(env).is_err() && std::env::var(format!("{env}_FILE")).is_err() { tracing::warn!("{env} not configured — using ephemeral dev key (INSECURE)"); let mut key = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut key); + use rand::Rng; + rand::rng().fill_bytes(&mut key); return Ok(key); } load_key32(env) diff --git a/lynx/agent/src/handlers/system.rs b/lynx/agent/src/handlers/system.rs index f8b3ba3..14a7edd 100644 --- a/lynx/agent/src/handlers/system.rs +++ b/lynx/agent/src/handlers/system.rs @@ -313,10 +313,10 @@ async fn handle_db_rotate_password( )); } - use rand::RngCore; + use rand::Rng; use zeroize::Zeroizing; let mut buf = [0u8; 24]; - rand::rngs::OsRng.fill_bytes(&mut buf); + rand::rng().fill_bytes(&mut buf); let new_pass = Zeroizing::new(buf.iter().map(|b| format!("{b:02x}")).collect::()); // Dollar-quoting ($$...$$) avoids any quote-based injection. diff --git a/lynx/agent/src/ws_client.rs b/lynx/agent/src/ws_client.rs index 7207d27..920b56f 100644 --- a/lynx/agent/src/ws_client.rs +++ b/lynx/agent/src/ws_client.rs @@ -85,7 +85,7 @@ async fn run_session( _ = hb_ticker.tick() => { let hb = heartbeat_payload(state); let text = serde_json::to_string(&hb).unwrap_or_default(); - if sink.send(Message::Text(text)).await.is_err() { + if sink.send(Message::Text(text.into())).await.is_err() { break; } } @@ -96,7 +96,7 @@ async fn run_session( "data": m, }); let text = serde_json::to_string(&frame).unwrap_or_default(); - if sink.send(Message::Text(text)).await.is_err() { + if sink.send(Message::Text(text.into())).await.is_err() { break; } } @@ -108,7 +108,7 @@ async fn run_session( "data": m, }); let text = serde_json::to_string(&frame).unwrap_or_default(); - if sink.send(Message::Text(text)).await.is_err() { + if sink.send(Message::Text(text.into())).await.is_err() { break; } } @@ -120,7 +120,7 @@ async fn run_session( let reply = handle_message(state, text.as_str()).await; if let Some(frame) = reply { let text = serde_json::to_string(&frame).unwrap_or_default(); - if sink.send(Message::Text(text)).await.is_err() { + if sink.send(Message::Text(text.into())).await.is_err() { break; } } diff --git a/lynx/dashboard/server/src/admin/handlers/rotation.rs b/lynx/dashboard/server/src/admin/handlers/rotation.rs index 552df5e..4a8d0cc 100644 --- a/lynx/dashboard/server/src/admin/handlers/rotation.rs +++ b/lynx/dashboard/server/src/admin/handlers/rotation.rs @@ -274,11 +274,11 @@ async fn rotate_agent_certs(state: &AppState) -> Result<(), AppError> { /// Existing pool connections remain valid until they close; new connections will /// use the updated secret on the next backend start. pub async fn rotate_pg_app_password(state: &AppState) -> Result<(), AppError> { - use rand::RngCore; + use rand::Rng; use zeroize::Zeroizing; let mut buf = [0u8; 24]; - rand::rngs::OsRng.fill_bytes(&mut buf); + rand::rng().fill_bytes(&mut buf); let new_pass = Zeroizing::new(buf.iter().map(|b| format!("{b:02x}")).collect::()); // Dollar-quoting ($$...$$) avoids any quote-based injection. @@ -330,11 +330,11 @@ pub async fn rotate_pg_app_password(state: &AppState) -> Result<(), AppError> { /// connections remain valid until they are recycled; the Podman secret is updated /// so the new password is used after the next backend restart. pub async fn rotate_redis_password(state: &AppState) -> Result<(), AppError> { - use rand::RngCore; + use rand::Rng; use zeroize::Zeroizing; let mut buf = [0u8; 24]; - rand::rngs::OsRng.fill_bytes(&mut buf); + rand::rng().fill_bytes(&mut buf); let new_pass = Zeroizing::new(buf.iter().map(|b| format!("{b:02x}")).collect::()); let mut redis = state.redis.clone(); diff --git a/lynx/dashboard/server/src/agents/wg.rs b/lynx/dashboard/server/src/agents/wg.rs index 46be9e6..a64272a 100644 --- a/lynx/dashboard/server/src/agents/wg.rs +++ b/lynx/dashboard/server/src/agents/wg.rs @@ -20,9 +20,9 @@ fn psk_secret_path(agent_id: Uuid) -> String { /// Returns the PSK value (caller must zeroize when done). pub fn create_psk(agent_id: Uuid) -> Result> { use base64ct::Encoding as _; - use rand::RngCore; + use rand::Rng; let mut raw = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut raw); + rand::rng().fill_bytes(&mut raw); let psk = Zeroizing::new(base64ct::Base64::encode_string(&raw)); raw.fill(0); diff --git a/lynx/dashboard/server/src/auth/session.rs b/lynx/dashboard/server/src/auth/session.rs index 2bc0bbe..6ea25a3 100644 --- a/lynx/dashboard/server/src/auth/session.rs +++ b/lynx/dashboard/server/src/auth/session.rs @@ -1,6 +1,6 @@ use anyhow::{Context, Result}; use chrono::{DateTime, Utc}; -use rand::rngs::OsRng; +use rand::Rng; use redis::{aio::ConnectionManager, AsyncCommands}; use sqlx::PgPool; use uuid::Uuid; @@ -25,7 +25,7 @@ pub struct SessionRecord { pub fn gen_refresh_token() -> Vec { let mut buf = vec![0u8; 32]; - rand::RngCore::fill_bytes(&mut OsRng, &mut buf); + rand::rng().fill_bytes(&mut buf); buf } diff --git a/lynx/dashboard/server/src/config.rs b/lynx/dashboard/server/src/config.rs index d7c0904..75b789f 100644 --- a/lynx/dashboard/server/src/config.rs +++ b/lynx/dashboard/server/src/config.rs @@ -123,7 +123,10 @@ fn load_or_gen_ed25519() -> Result<(Zeroizing<[u8; 32]>, [u8; 32])> { tracing::warn!("JWT signing keys not configured — using ephemeral keys (dev only)"); let mut seed = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut seed); + { + use rand::Rng; + rand::rng().fill_bytes(&mut seed); + } let signing_key = ed25519_dalek::SigningKey::from_bytes(&seed); let pub_bytes = signing_key.verifying_key().to_bytes(); @@ -149,7 +152,10 @@ fn load_or_gen_x25519() -> Result<(Zeroizing<[u8; 32]>, [u8; 32])> { tracing::warn!("JWT encryption keys not configured — using ephemeral keys (dev only)"); let mut priv_bytes = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut priv_bytes); + { + use rand::Rng; + rand::rng().fill_bytes(&mut priv_bytes); + } let secret = x25519_dalek::StaticSecret::from(priv_bytes); let public = x25519_dalek::PublicKey::from(&secret); @@ -189,7 +195,10 @@ fn load_or_gen_ca_ed25519() -> Result<(Zeroizing<[u8; 32]>, [u8; 32])> { tracing::warn!("CA keypair not configured — using ephemeral CA (dev only, agents will reject certs on restart)"); let mut seed = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut seed); + { + use rand::Rng; + rand::rng().fill_bytes(&mut seed); + } let signing_key = ed25519_dalek::SigningKey::from_bytes(&seed); let pub_bytes = signing_key.verifying_key().to_bytes(); Ok((Zeroizing::new(seed), pub_bytes)) diff --git a/lynx/dashboard/server/src/crypto/kek.rs b/lynx/dashboard/server/src/crypto/kek.rs index ae23a3b..d5409b5 100644 --- a/lynx/dashboard/server/src/crypto/kek.rs +++ b/lynx/dashboard/server/src/crypto/kek.rs @@ -3,12 +3,12 @@ use aes_gcm::{ Aes256Gcm, Key, Nonce, }; use anyhow::Result; -use rand::rngs::OsRng; +use rand::Rng; use zeroize::Zeroizing; pub fn gen_dek() -> Zeroizing<[u8; 32]> { let mut dek = [0u8; 32]; - rand::RngCore::fill_bytes(&mut OsRng, &mut dek); + rand::rng().fill_bytes(&mut dek); Zeroizing::new(dek) } @@ -35,7 +35,7 @@ pub fn decrypt_with_dek(ciphertext: &[u8], dek: &[u8; 32]) -> Result> { fn encrypt_aes_gcm(plaintext: &[u8], key_bytes: &[u8; 32]) -> Result> { let key = Key::::from_slice(key_bytes); let cipher = Aes256Gcm::new(key); - let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + let nonce = Aes256Gcm::generate_nonce(&mut aes_gcm::aead::OsRng); let ciphertext = cipher .encrypt(&nonce, plaintext) .map_err(|e| anyhow::anyhow!("AES-GCM encrypt: {e}"))?; diff --git a/lynx/dashboard/server/src/crypto/pki.rs b/lynx/dashboard/server/src/crypto/pki.rs index e0a2ad8..bb1d946 100644 --- a/lynx/dashboard/server/src/crypto/pki.rs +++ b/lynx/dashboard/server/src/crypto/pki.rs @@ -9,8 +9,8 @@ use base64ct::{Base64UrlUnpadded, Encoding}; use chrono::{Duration, Utc}; use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; use rcgen::{ - BasicConstraints, CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, KeyPair, SanType, - PKCS_ED25519, + BasicConstraints, CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, Issuer, KeyPair, + SanType, PKCS_ED25519, }; use rustls::pki_types::CertificateDer as RustlsCertDer; use serde::{Deserialize, Serialize}; @@ -95,7 +95,10 @@ pub fn verify_cert( /// Generate a new CA Ed25519 keypair (for startup when not configured). pub fn gen_ca_keypair() -> (Zeroizing<[u8; 32]>, [u8; 32]) { let mut seed = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut seed); + { + use rand::Rng; + rand::rng().fill_bytes(&mut seed); + } let signing_key = SigningKey::from_bytes(&seed); let pub_bytes = signing_key.verifying_key().to_bytes(); (Zeroizing::new(seed), pub_bytes) @@ -126,19 +129,6 @@ pub fn generate_x509_ca() -> Result<(Vec, Zeroizing>)> { Ok((cert_der, key_der)) } -/// Reconstruct an `rcgen::Certificate` from stored DER bytes. -/// Used as the issuer when signing leaf certs. -fn load_ca_rcgen(ca_cert_der: &[u8], ca_key_der: &[u8]) -> Result<(rcgen::Certificate, KeyPair)> { - let ca_key = KeyPair::try_from(ca_key_der).context("load CA key from DER")?; - let cert_der = RustlsCertDer::from(ca_cert_der.to_vec()); - let ca_params = - CertificateParams::from_ca_cert_der(&cert_der).context("parse CA cert params from DER")?; - let ca_cert = ca_params - .self_signed(&ca_key) - .context("reconstruct CA cert")?; - Ok((ca_cert, ca_key)) -} - /// Issue an X.509 server certificate for an agent (Ed25519). /// The cert includes the agent's WireGuard IP as a SAN. /// Returns `(cert_der, key_der_pkcs8)`. @@ -148,14 +138,17 @@ pub fn issue_x509_agent_cert( agent_id: Uuid, wg_ip: &str, ) -> Result<(Vec, Zeroizing>)> { - let (ca_cert, ca_key) = load_ca_rcgen(ca_cert_der, ca_key_der)?; + let ca_key = KeyPair::try_from(ca_key_der).context("load CA key from DER")?; + let cert_der_owned = RustlsCertDer::from(ca_cert_der.to_vec()); + let issuer = + Issuer::from_ca_cert_der(&cert_der_owned, ca_key).context("parse CA cert as issuer")?; + let leaf_key = KeyPair::generate_for(&PKCS_ED25519).context("generate agent Ed25519 key")?; let mut params = CertificateParams::new(vec![]).context("create agent cert params")?; params .distinguished_name .push(DnType::CommonName, format!("lynx-agent-{agent_id}")); - // Extended key usages: both server auth (listener) and client auth (future) params.extended_key_usages = vec![ ExtendedKeyUsagePurpose::ServerAuth, ExtendedKeyUsagePurpose::ClientAuth, @@ -165,7 +158,7 @@ pub fn issue_x509_agent_cert( } let cert = params - .signed_by(&leaf_key, &ca_cert, &ca_key) + .signed_by(&leaf_key, &issuer) .context("sign agent cert")?; let cert_der = cert.der().to_vec(); let key_der = Zeroizing::new(leaf_key.serialize_der()); @@ -180,7 +173,11 @@ pub fn issue_x509_dashboard_client_cert( ca_cert_der: &[u8], ca_key_der: &[u8], ) -> Result<(Vec, Zeroizing>)> { - let (ca_cert, ca_key) = load_ca_rcgen(ca_cert_der, ca_key_der)?; + let ca_key = KeyPair::try_from(ca_key_der).context("load CA key from DER")?; + let cert_der_owned = RustlsCertDer::from(ca_cert_der.to_vec()); + let issuer = + Issuer::from_ca_cert_der(&cert_der_owned, ca_key).context("parse CA cert as issuer")?; + let leaf_key = KeyPair::generate_for(&PKCS_ED25519).context("generate dashboard client Ed25519 key")?; @@ -192,7 +189,7 @@ pub fn issue_x509_dashboard_client_cert( params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ClientAuth]; let cert = params - .signed_by(&leaf_key, &ca_cert, &ca_key) + .signed_by(&leaf_key, &issuer) .context("sign dashboard client cert")?; let cert_der = cert.der().to_vec(); let key_der = Zeroizing::new(leaf_key.serialize_der()); diff --git a/lynx/dashboard/server/src/main.rs b/lynx/dashboard/server/src/main.rs index feaf16d..42a8a63 100644 --- a/lynx/dashboard/server/src/main.rs +++ b/lynx/dashboard/server/src/main.rs @@ -222,13 +222,13 @@ async fn run_cli_command(cmd: Command, db: &sqlx::PgPool) -> anyhow::Result<()> } fn generate_random_password() -> String { - use rand::Rng; - let mut rng = rand::thread_rng(); + use rand::RngExt; + let mut rng = rand::rng(); let charset: Vec = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*" .chars() .collect(); (0..24) - .map(|_| charset[rng.gen_range(0..charset.len())]) + .map(|_| charset[rng.random_range(0..charset.len())]) .collect() } diff --git a/lynx/translators/compose/Cargo.toml b/lynx/translators/compose/Cargo.toml index c1808e3..59fa83b 100644 --- a/lynx/translators/compose/Cargo.toml +++ b/lynx/translators/compose/Cargo.toml @@ -19,7 +19,7 @@ anyhow = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } serde_yaml = { package = "yaml_serde", version = "0.10" } -bollard = "0.17" +bollard = "0.21" clap = { version = "4", features = ["derive", "env"] } indexmap = { version = "2", features = ["serde"] } futures = "0.3" @@ -28,7 +28,7 @@ tar = "0.4" flate2 = "1.0" bytes = "1" walkdir = "2" -notify = "6" +notify = "8" [dev-dependencies] tempfile = "3" diff --git a/lynx/translators/compose/internal/engine/build.rs b/lynx/translators/compose/internal/engine/build.rs index acb917a..49a8794 100644 --- a/lynx/translators/compose/internal/engine/build.rs +++ b/lynx/translators/compose/internal/engine/build.rs @@ -7,7 +7,8 @@ use std::path::Path; -use bollard::image::{BuildImageOptions, CreateImageOptions, TagImageOptions}; +use bollard::body_full; +use bollard::query_parameters::{BuildImageOptions, CreateImageOptions, TagImageOptions}; use bytes::Bytes; use flate2::write::GzEncoder; use flate2::Compression; @@ -32,8 +33,8 @@ impl Engine { let mut stream = self.docker.create_image( Some(CreateImageOptions { - from_image: image.as_str(), - platform: service.platform.as_deref().unwrap_or(""), + from_image: Some(image.clone()), + platform: service.platform.clone().unwrap_or_default(), ..Default::default() }), None, @@ -116,28 +117,54 @@ impl Engine { .unwrap_or(0); let extrahosts = build.extra_hosts().join(","); - let options = BuildImageOptions:: { + let options = BuildImageOptions { dockerfile: dockerfile_name, - t: tag.clone(), + t: Some(tag.clone()), rm: true, nocache: build.no_cache(), - pull: build.pull(), - buildargs: build_args, - labels, - networkmode: network_owned, + pull: if build.pull() { + Some("1".to_string()) + } else { + None + }, + buildargs: if build_args.is_empty() { + None + } else { + Some(build_args) + }, + labels: if labels.is_empty() { + None + } else { + Some(labels) + }, + networkmode: if network_owned.is_empty() { + None + } else { + Some(network_owned) + }, platform: platform_owned, - shmsize: if shmsize > 0 { Some(shmsize) } else { None }, + shmsize: if shmsize > 0 { + Some(shmsize as i32) + } else { + None + }, extrahosts: if extrahosts.is_empty() { None } else { Some(extrahosts) }, - cachefrom: build.cache_from().to_vec(), + cachefrom: if build.cache_from().is_empty() { + None + } else { + Some(build.cache_from().to_vec()) + }, ..Default::default() }; let body = Bytes::from(tar_bytes); - let mut stream = self.docker.build_image(options, None, Some(body)); + let mut stream = self + .docker + .build_image(options, None, Some(body_full(body))); while let Some(result) = stream.next().await { match result { @@ -145,7 +172,7 @@ impl Engine { if let Some(stream_msg) = info.stream { print!("{stream_msg}"); } - if let Some(err) = info.error { + if let Some(err) = info.error_detail.and_then(|e| e.message) { return Err(ComposeError::Build(err)); } } @@ -161,7 +188,13 @@ impl Engine { .unwrap_or_else(|| (extra_tag.clone(), "latest".to_string())); if let Err(e) = self .docker - .tag_image(&tag, Some(TagImageOptions { repo, tag: tag_str })) + .tag_image( + &tag, + Some(TagImageOptions { + repo: Some(repo), + tag: Some(tag_str), + }), + ) .await { warn!("failed to apply extra tag {extra_tag}: {e}"); diff --git a/lynx/translators/compose/internal/engine/container.rs b/lynx/translators/compose/internal/engine/container.rs index eba216d..803ee91 100644 --- a/lynx/translators/compose/internal/engine/container.rs +++ b/lynx/translators/compose/internal/engine/container.rs @@ -9,14 +9,13 @@ use std::collections::HashMap; use std::path::Path; -use bollard::container::NetworkingConfig; -use bollard::container::{ - Config, CreateContainerOptions, RemoveContainerOptions, StartContainerOptions, -}; use bollard::models::{ - DeviceMapping, DeviceRequest, HealthConfig, HostConfig, HostConfigLogConfig, - ResourcesBlkioWeightDevice, ResourcesUlimits, RestartPolicy as BollardRestart, - RestartPolicyNameEnum, ThrottleDevice, + ContainerCreateBody, DeviceMapping, DeviceRequest, HealthConfig, HostConfig, + HostConfigLogConfig, NetworkingConfig, ResourcesBlkioWeightDevice, ResourcesUlimits, + RestartPolicy as BollardRestart, RestartPolicyNameEnum, ThrottleDevice, +}; +use bollard::query_parameters::{ + CreateContainerOptions, RemoveContainerOptions, StartContainerOptions, }; use tracing::warn; @@ -56,15 +55,18 @@ impl Engine { .collect(); let parsed_ports = ports::parse_ports(&service.ports)?; - let (port_bindings, mut exposed_ports) = ports::to_bollard(&parsed_ports); + let (port_bindings, exposed_ports_map) = ports::to_bollard(&parsed_ports); + let mut exposed_port_keys: Vec = exposed_ports_map.into_keys().collect(); for raw in &service.expose { let key = if raw.contains('/') { raw.clone() } else { format!("{raw}/tcp") }; - exposed_ports.entry(key).or_default(); + if !exposed_port_keys.contains(&key) { + exposed_port_keys.push(key); + } } let restart_policy = build_restart_policy(service); @@ -227,21 +229,20 @@ impl Engine { let svc_net_cfg = service.networks.config_for(net); endpoints.insert(net.clone(), build_endpoint_settings(svc_net_cfg, file)); NetworkingConfig { - endpoints_config: endpoints, + endpoints_config: Some(endpoints), } }); let healthcheck = service.healthcheck.as_ref().map(build_healthcheck); - let exposed_ports_json: HashMap> = exposed_ports; - let config = Config:: { + let config = ContainerCreateBody { image: Some(image.to_string()), env: opt_vec(env), cmd, entrypoint, host_config: Some(host_config), labels: opt_map(labels), - exposed_ports: opt_map(exposed_ports_json), + exposed_ports: opt_vec(exposed_port_keys), tty: service.tty, open_stdin: service.stdin_open, user: service.user.clone(), @@ -254,7 +255,6 @@ impl Engine { .map(|s| s as i64), hostname: service.hostname.clone(), domainname: service.domainname.clone(), - mac_address: service.mac_address.clone(), networking_config, healthcheck, ..Default::default() @@ -274,16 +274,16 @@ impl Engine { self.docker .create_container( - Some(CreateContainerOptions::<&str> { - name: container_name, - platform: service.platform.as_deref(), + Some(CreateContainerOptions { + name: Some(container_name.to_string()), + platform: service.platform.clone().unwrap_or_default(), }), config, ) .await?; self.docker - .start_container(container_name, None::>) + .start_container(container_name, None::) .await?; Ok(()) diff --git a/lynx/translators/compose/internal/engine/mod.rs b/lynx/translators/compose/internal/engine/mod.rs index 3fbbaf5..19d7e18 100644 --- a/lynx/translators/compose/internal/engine/mod.rs +++ b/lynx/translators/compose/internal/engine/mod.rs @@ -13,11 +13,12 @@ mod watch; use std::collections::HashMap; use std::path::PathBuf; -use bollard::container::{ - ListContainersOptions, LogOutput, LogsOptions, RemoveContainerOptions, StartContainerOptions, +use bollard::container::LogOutput; +use bollard::exec::{CreateExecOptions, StartExecResults}; +use bollard::query_parameters::{ + ListContainersOptions, LogsOptions, RemoveContainerOptions, StartContainerOptions, StopContainerOptions, }; -use bollard::exec::{CreateExecOptions, StartExecResults}; use bollard::Docker; use futures::StreamExt; use tracing::info; @@ -168,7 +169,13 @@ impl Engine { let _ = self .docker - .stop_container(&container_name, Some(StopContainerOptions { t: 10 })) + .stop_container( + &container_name, + Some(StopContainerOptions { + t: Some(10), + ..Default::default() + }), + ) .await; let _ = self @@ -198,9 +205,9 @@ impl Engine { let containers = self .docker - .list_containers(Some(ListContainersOptions:: { + .list_containers(Some(ListContainersOptions { all: true, - filters, + filters: Some(filters), ..Default::default() })) .await?; @@ -257,7 +264,7 @@ impl Engine { for container_name in targets { let mut stream = self.docker.logs( &container_name, - Some(LogsOptions:: { + Some(LogsOptions { stdout: true, stderr: true, follow, @@ -334,7 +341,7 @@ impl Engine { /// Services with `attach: false` are excluded. Respects the compose spec: /// when not detaching, all attached services have their output forwarded. pub async fn attach_logs(&self, file: &ComposeFile) -> Result<()> { - use bollard::container::LogsOptions; + use bollard::query_parameters::LogsOptions; use futures::StreamExt; let attached: Vec<(String, String)> = file @@ -354,7 +361,7 @@ impl Engine { let prefix = name.clone(); let mut stream = self.docker.logs( cname, - Some(LogsOptions:: { + Some(LogsOptions { stdout: true, stderr: true, follow: true, @@ -393,9 +400,9 @@ impl Engine { let running = self .docker - .list_containers(Some(ListContainersOptions:: { + .list_containers(Some(ListContainersOptions { all: true, - filters, + filters: Some(filters), ..Default::default() })) .await?; @@ -459,11 +466,17 @@ impl Engine { let _ = self .docker - .stop_container(&container_name, Some(StopContainerOptions { t: 10 })) + .stop_container( + &container_name, + Some(StopContainerOptions { + t: Some(10), + ..Default::default() + }), + ) .await; self.docker - .start_container(&container_name, None::>) + .start_container(&container_name, None::) .await?; info!("restarted {container_name}"); @@ -474,11 +487,17 @@ impl Engine { let dep_container = self.container_name(dep_name, dep_service); let _ = self .docker - .stop_container(&dep_container, Some(StopContainerOptions { t: 10 })) + .stop_container( + &dep_container, + Some(StopContainerOptions { + t: Some(10), + ..Default::default() + }), + ) .await; if let Err(e) = self .docker - .start_container(&dep_container, None::>) + .start_container(&dep_container, None::) .await { tracing::warn!("cascade restart of {dep_name} failed: {e}"); diff --git a/lynx/translators/compose/internal/engine/network.rs b/lynx/translators/compose/internal/engine/network.rs index da49860..a0416a1 100644 --- a/lynx/translators/compose/internal/engine/network.rs +++ b/lynx/translators/compose/internal/engine/network.rs @@ -10,8 +10,8 @@ use std::collections::HashMap; use bollard::models::{ EndpointIpamConfig, EndpointSettings, Ipam, IpamConfig as BollardIpamConfig, + NetworkConnectRequest, NetworkCreateRequest, }; -use bollard::network::{ConnectNetworkOptions, CreateNetworkOptions}; use tracing::{debug, info}; use crate::compose::types::{ComposeFile, IpamConfig, Service, ServiceNetworkConfig}; @@ -53,19 +53,27 @@ impl Engine { .and_then(|c| c.ipam.as_ref()) .map(build_ipam); - let options = CreateNetworkOptions:: { + let request = NetworkCreateRequest { name: network_name.to_string(), - driver: driver.clone(), - internal: config.as_ref().and_then(|c| c.internal).unwrap_or(false), - attachable: config.as_ref().and_then(|c| c.attachable).unwrap_or(false), - enable_ipv6: config.as_ref().and_then(|c| c.enable_ipv6).unwrap_or(false), - options: driver_opts, - labels, - ipam: ipam.unwrap_or_default(), + driver: Some(driver.clone()), + internal: config.as_ref().and_then(|c| c.internal), + attachable: config.as_ref().and_then(|c| c.attachable), + enable_ipv6: config.as_ref().and_then(|c| c.enable_ipv6), + options: if driver_opts.is_empty() { + None + } else { + Some(driver_opts) + }, + labels: if labels.is_empty() { + None + } else { + Some(labels) + }, + ipam, ..Default::default() }; - match self.docker.create_network(options).await { + match self.docker.create_network(request).await { Ok(_) => info!("created network {network_name}"), Err(bollard::errors::Error::DockerResponseServerError { status_code: 409, .. @@ -94,9 +102,9 @@ impl Engine { self.docker .connect_network( &full_name, - ConnectNetworkOptions { - container: container_name, - endpoint_config, + NetworkConnectRequest { + container: container_name.to_string(), + endpoint_config: Some(endpoint_config), }, ) .await?; diff --git a/lynx/translators/compose/internal/engine/volume.rs b/lynx/translators/compose/internal/engine/volume.rs index 5202976..9d55d72 100644 --- a/lynx/translators/compose/internal/engine/volume.rs +++ b/lynx/translators/compose/internal/engine/volume.rs @@ -11,10 +11,9 @@ use std::collections::HashMap; use std::path::Path; use bollard::models::{ - Mount, MountBindOptions, MountTmpfsOptions, MountTypeEnum, MountVolumeOptions, - MountVolumeOptionsDriverConfig, + Mount, MountBindOptions, MountTmpfsOptions, MountType, MountVolumeOptions, + MountVolumeOptionsDriverConfig, VolumeCreateRequest, }; -use bollard::volume::CreateVolumeOptions; use tracing::info; use crate::compose::types::{ @@ -54,11 +53,20 @@ impl Engine { .map(|c| c.driver_opts.clone()) .unwrap_or_default(); - let options = CreateVolumeOptions:: { - name: volume_name.to_string(), - driver: driver.clone(), - driver_opts, - labels, + let options = VolumeCreateRequest { + name: Some(volume_name.to_string()), + driver: Some(driver.clone()), + driver_opts: if driver_opts.is_empty() { + None + } else { + Some(driver_opts) + }, + labels: if labels.is_empty() { + None + } else { + Some(labels) + }, + ..Default::default() }; match self.docker.create_volume(options).await { @@ -162,11 +170,12 @@ pub(crate) fn build_mounts(service: &Service) -> Vec { let tmpfs_options = tmpfs.as_ref().map(|t| MountTmpfsOptions { size_bytes: t.size.map(|s| s as i64), mode: t.mode.map(|m| m as i64), + options: None, }); out.push(Mount { target: Some(target.clone()), source: source.clone(), - typ: Some(MountTypeEnum::TMPFS), + typ: Some(MountType::TMPFS), read_only: *read_only, consistency: consistency.clone(), tmpfs_options, @@ -178,10 +187,10 @@ pub(crate) fn build_mounts(service: &Service) -> Vec { continue; } let mount_type = match volume_type { - VolumeType::Bind => MountTypeEnum::BIND, - VolumeType::Volume => MountTypeEnum::VOLUME, - VolumeType::Npipe => MountTypeEnum::NPIPE, - VolumeType::Cluster => MountTypeEnum::CLUSTER, + VolumeType::Bind => MountType::BIND, + VolumeType::Volume => MountType::VOLUME, + VolumeType::Npipe => MountType::NPIPE, + VolumeType::Cluster => MountType::CLUSTER, VolumeType::Tmpfs => unreachable!(), }; let bind_options = bind.as_ref().map(|b| MountBindOptions { diff --git a/lynx/translators/compose/internal/engine/watch.rs b/lynx/translators/compose/internal/engine/watch.rs index 71c7f9d..5cca7ea 100644 --- a/lynx/translators/compose/internal/engine/watch.rs +++ b/lynx/translators/compose/internal/engine/watch.rs @@ -12,9 +12,12 @@ use std::path::{Path, PathBuf}; use std::time::Duration; +use bollard::body_full; use bollard::container::LogOutput; -use bollard::container::{StartContainerOptions, StopContainerOptions, UploadToContainerOptions}; use bollard::exec::{CreateExecOptions, StartExecResults}; +use bollard::query_parameters::{ + StartContainerOptions, StopContainerOptions, UploadToContainerOptions, +}; use bytes::Bytes; use flate2::write::GzEncoder; use flate2::Compression; @@ -217,9 +220,10 @@ impl Engine { container, Some(UploadToContainerOptions { path: dest_dir, - no_overwrite_dir_non_dir: String::new(), + no_overwrite_dir_non_dir: None, + copy_uidgid: None, }), - Bytes::from(tar_bytes), + body_full(Bytes::from(tar_bytes)), ) .await .map_err(ComposeError::Podman)?; @@ -244,10 +248,16 @@ impl Engine { info!("restarting {container_name}"); let _ = self .docker - .stop_container(container_name, Some(StopContainerOptions { t: 5 })) + .stop_container( + container_name, + Some(StopContainerOptions { + t: Some(5), + ..Default::default() + }), + ) .await; self.docker - .start_container(container_name, None::>) + .start_container(container_name, None::) .await?; Ok(()) }