diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..1fa1050 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,16 @@ +name: Update Changelog + +on: + workflow_dispatch: # manual trigger + # schedule: + # - cron: "0 0 * * 1" # every Monday (optional) + +jobs: + changelog: + permissions: + contents: write + uses: weekendsuperhero-io/platform-tools/.github/workflows/reusable-changelog.yml@main + with: + changelog-path: CHANGELOG.md + pr-branch-prefix: "chore/changelog-" + secrets: inherit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 711ff83..149a85c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,4 @@ -# CI — runs on push/PR to main -# -# Run locally before pushing: -# ./ci-check.sh --fix # auto-fix formatting + clippy -# ./ci-check.sh # check only (same as CI) - -name: CI +name: CI Agent Mail on: push: @@ -12,61 +6,12 @@ on: pull_request: branches: [main] -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - CARGO_TERM_COLOR: always - jobs: - check: - name: Check - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - steps: - - uses: actions/checkout@v6 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@1.94 - with: - components: rustfmt, clippy - - - name: Cache cargo registry - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - - name: Check formatting - run: cargo fmt --all -- --check - - - name: Run clippy - run: cargo clippy --all-targets --all-features -- -D warnings - - - name: Build - run: cargo build --all-features - - - name: Run tests - run: cargo test --all-features - - docs: - name: Documentation - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@1.94 - - - name: Build documentation - run: cargo doc --no-deps --all-features - env: - RUSTDOCFLAGS: -D warnings + ci: + uses: weekendsuperhero-io/platform-tools/.github/workflows/reusable-rust-ci.yml@main + with: + check-os-json: '["ubuntu-latest","macos-latest","windows-latest"]' + rust-cache-provider: github + docs-os: ubuntu-latest + linux-packages: "libdbus-1-dev pkg-config" + build-matrix-json: "[]" diff --git a/.github/workflows/pr-desc.yml b/.github/workflows/pr-desc.yml new file mode 100644 index 0000000..29721b0 --- /dev/null +++ b/.github/workflows/pr-desc.yml @@ -0,0 +1,12 @@ +name: Update PR Description + +on: + pull_request: + types: [opened, edited] + +jobs: + update-pr: + uses: weekendsuperhero-io/platform-tools/.github/workflows/reusable-pr-description.yml@main + with: + trigger-phrase: "@agent pr-title" # optional — only runs if this phrase is in the PR body + secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a8cd5f..850555c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,192 +5,27 @@ on: tags: - "v*" -concurrency: - group: release-${{ github.ref }} - cancel-in-progress: true - -env: - CARGO_TERM_COLOR: always - jobs: - validate: - name: Validate Release - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@1.94 - with: - components: rustfmt, clippy - - - name: Cache cargo registry - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-release-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-release-cargo- - - - name: Check formatting - run: cargo fmt --all -- --check - - - name: Run clippy - run: cargo clippy --all-targets --all-features -- -D warnings - - - name: Run tests - run: cargo test --all-features - - build-binaries: - name: Build (${{ matrix.name }}) - needs: validate - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - name: linux-x86_64 - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - binary: agentmail - archive: agentmail-linux-x86_64.tar.gz - - name: linux-aarch64 - os: ubuntu-24.04-arm - target: aarch64-unknown-linux-gnu - binary: agentmail - archive: agentmail-linux-aarch64.tar.gz - - name: macos-x86_64 - os: macos-latest - target: x86_64-apple-darwin - binary: agentmail - archive: agentmail-macos-x86_64.tar.gz - - name: macos-aarch64 - os: macos-latest - target: aarch64-apple-darwin - binary: agentmail - archive: agentmail-macos-aarch64.tar.gz - - name: windows-x86_64 - os: windows-latest - target: x86_64-pc-windows-msvc - binary: agentmail.exe - archive: agentmail-windows-x86_64.zip - steps: - - uses: actions/checkout@v6 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@1.94 - with: - targets: ${{ matrix.target }} - - - name: Cache cargo registry - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-${{ matrix.target }}-release-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.target }}-release-cargo- - - - name: Build release binary - run: cargo build --release --target ${{ matrix.target }} - - - name: Package (unix) - if: runner.os != 'Windows' - run: | - cd target/${{ matrix.target }}/release - tar czf ../../../${{ matrix.archive }} ${{ matrix.binary }} - cd ../../.. - - - name: Package (windows) - if: runner.os == 'Windows' - shell: pwsh - run: | - Compress-Archive -Path "target/${{ matrix.target }}/release/${{ matrix.binary }}" -DestinationPath "${{ matrix.archive }}" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.name }} - path: ${{ matrix.archive }} - - # Build macOS universal binary from the two arch-specific builds - build-macos-universal: - name: Build (macos-universal) - needs: build-binaries - runs-on: macos-latest - steps: - - name: Download macOS artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: Create universal binary - run: | - mkdir -p work - cd work - tar xzf ../artifacts/macos-aarch64/agentmail-macos-aarch64.tar.gz - mv agentmail agentmail-arm64 - tar xzf ../artifacts/macos-x86_64/agentmail-macos-x86_64.tar.gz - mv agentmail agentmail-x86_64 - lipo -create -output agentmail agentmail-arm64 agentmail-x86_64 - file agentmail - tar czf ../agentmail-macos-universal.tar.gz agentmail - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: macos-universal - path: agentmail-macos-universal.tar.gz - - create-release: - name: Create GitHub Release - needs: [build-binaries, build-macos-universal] - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v6 - - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: Collect release assets - run: | - mkdir -p release - cp artifacts/linux-x86_64/*.tar.gz release/ - cp artifacts/linux-aarch64/*.tar.gz release/ - cp artifacts/macos-x86_64/*.tar.gz release/ - cp artifacts/macos-aarch64/*.tar.gz release/ - cp artifacts/macos-universal/*.tar.gz release/ - cp artifacts/windows-x86_64/*.zip release/ - ls -lh release/ - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - generate_release_notes: true - files: release/* - - publish-crates-io: - name: Publish to crates.io - needs: validate - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@1.94 - - - name: Update lockfile - run: cargo generate-lockfile - - - name: Publish agentmail (library + binary + mcp) - run: cargo publish -p agentmail - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + release: + uses: weekendsuperhero-io/platform-tools/.github/workflows/reusable-rust-release.yml@main + with: + validate-runs-on: ubuntu-latest + rust-cache-provider: github + validate-linux-packages: "libdbus-1-dev pkg-config" + # Optional override if binary cannot be inferred from Cargo.toml + # binary-name: agentmail + binary-matrix-json: >- + [ + {"name":"linux-x86_64","os":"ubuntu-latest","target":"x86_64-unknown-linux-gnu"}, + {"name":"linux-aarch64","os":"ubuntu-24.04-arm","target":"aarch64-unknown-linux-gnu"}, + {"name":"macos-x86_64","os":"macos-latest","target":"x86_64-apple-darwin"}, + {"name":"macos-aarch64","os":"macos-latest","target":"aarch64-apple-darwin"}, + {"name":"windows-x86_64","os":"windows-latest","target":"x86_64-pc-windows-msvc"} + ] + enable-macos-universal: true + # Optional overrides if your artifact names differ: + # macos-universal-arm64-artifact: macos-aarch64 + # macos-universal-x86_64-artifact: macos-x86_64 + publish-crates-io: true + cargo-publish-command: cargo publish + secrets: inherit diff --git a/Cargo.lock b/Cargo.lock index 94fddf7..9070d03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,20 +23,22 @@ dependencies = [ name = "agentmail" version = "0.1.8" dependencies = [ + "apple-native-keyring-store", "async-imap", "chrono", "clap", + "dbus-secret-service-keyring-store", "dirs", "fast_html2md", "futures", - "hashbrown 0.16.1", + "hashbrown 0.17.0", + "keyring-core", "lettre", "mail-parser", "native-tls", "reqwest", "rmcp", "schemars", - "secret-lib", "serde", "serde_json", "thiserror 2.0.18", @@ -46,6 +48,7 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", + "windows-native-keyring-store", ] [[package]] @@ -129,15 +132,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] -name = "async-broadcast" -version = "0.7.2" +name = "apple-native-keyring-store" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +checksum = "9cdab02b2a5e47c080382cb729e8fc53bedf4a498200fc72a4e6c691033a3f7b" dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", - "futures-core", - "pin-project-lite", + "keyring-core", + "log", + "security-framework", ] [[package]] @@ -175,31 +177,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-executor" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - [[package]] name = "async-imap" version = "0.11.2" @@ -223,88 +200,6 @@ dependencies = [ "tokio", ] -[[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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-process" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" -dependencies = [ - "async-channel 2.5.0", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener 5.4.1", - "futures-lite", - "rustix", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-signal" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix", - "signal-hook-registry", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.89" @@ -392,19 +287,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel 2.5.0", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - [[package]] name = "bumpalo" version = "3.20.2" @@ -434,9 +316,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.58" +version = "1.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" dependencies = [ "find-msvc-tools", "jobserver", @@ -752,6 +634,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "dbus-secret-service-keyring-store" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec3a0f31addb56ee6d5c55599068d2093bc737469a448b34e426603ef61f93e" +dependencies = [ + "dbus-secret-service", + "keyring-core", +] + [[package]] name = "derive_more" version = "2.1.1" @@ -874,33 +766,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "endi" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" - -[[package]] -name = "enumflags2" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -946,9 +811,9 @@ dependencies = [ [[package]] name = "fast_html2md" -version = "0.0.60" +version = "0.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c1e4d8883c0f56e3f0fbfd1c8a7d6278cca0313b7b52fc2f58ad630d0edd4f" +checksum = "bd40b2369f490dc05d0efaa9301cafb160fe19aa86f1cfbb2cab186c852060ee" dependencies = [ "auto_encoder", "futures-util", @@ -961,9 +826,9 @@ 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 = "find-msvc-tools" @@ -1077,19 +942,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "futures-macro" version = "0.3.32" @@ -1213,6 +1065,17 @@ 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" dependencies = [ "allocator-api2", "equivalent", @@ -1224,10 +1087,11 @@ dependencies = [ [[package]] name = "hashify" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "149e3ea90eb5a26ad354cfe3cb7f7401b9329032d0235f2687d03a35f30e5d4c" +checksum = "dd1246c0e5493286aeb2dde35b1f4eb9c4ce00e628641210a5e553fc001a1f26" dependencies = [ + "indexmap", "proc-macro2", "quote", "syn", @@ -1239,18 +1103,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "hkdf" version = "0.12.4" @@ -1316,9 +1168,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[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", @@ -1330,7 +1182,6 @@ dependencies = [ "httparse", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1403,12 +1254,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1416,9 +1268,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -1429,9 +1281,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1443,15 +1295,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -1463,15 +1315,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -1526,9 +1378,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -1630,9 +1482,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.92" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ "cfg-if", "futures-util", @@ -1641,35 +1493,12 @@ dependencies = [ ] [[package]] -name = "keyring" -version = "3.6.3" +name = "keyring-core" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" +checksum = "2d8286c3ab222af2fa9e57874fe419893d967f739c7bf1743f98a88678edbf08" dependencies = [ - "byteorder", - "dbus-secret-service", - "linux-keyutils", "log", - "secret-service", - "security-framework 2.11.1", - "security-framework 3.7.0", - "windows-sys 0.60.2", - "zbus", - "zeroize", -] - -[[package]] -name = "keyring-lib" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5f40cf9f03fc57cc1fd38378559b416ba1c525158cdb093f7a5cedabf10940" -dependencies = [ - "keyring", - "once_cell", - "serde", - "thiserror 2.0.18", - "tokio", - "tracing", ] [[package]] @@ -1686,9 +1515,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lettre" -version = "0.11.20" +version = "0.11.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471816f3e24b85e820dee02cde962379ea1a669e5242f19c61bcbcffedf4c4fb" +checksum = "dabda5859ee7c06b995b9d1165aa52c39110e079ef609db97178d86aeb051fa7" dependencies = [ "email-encoding", "email_address", @@ -1702,9 +1531,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.183" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libdbus-sys" @@ -1724,16 +1553,6 @@ dependencies = [ "libc", ] -[[package]] -name = "linux-keyutils" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83270a18e9f90d0707c41e9f35efada77b64c0e6f3f1810e71c8368a864d5590" -dependencies = [ - "bitflags", - "libc", -] - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -1742,9 +1561,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" @@ -1810,15 +1629,6 @@ 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 = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -1864,7 +1674,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "tempfile", ] @@ -1875,19 +1685,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[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" @@ -2051,16 +1848,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "parking" version = "2.2.1" @@ -2229,42 +2016,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[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 = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -2294,15 +2056,6 @@ dependencies = [ "syn", ] -[[package]] -name = "proc-macro-crate" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" -dependencies = [ - "toml_edit", -] - [[package]] name = "proc-macro2" version = "1.0.106" @@ -2312,18 +2065,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "process-lib" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb47ed33aeaf6b32cecbbde6f56dde6c8740f2dac4a146179cc82f797918c46" -dependencies = [ - "serde", - "thiserror 1.0.69", - "tokio", - "tracing", -] - [[package]] name = "quinn" version = "0.11.9" @@ -2413,8 +2154,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", - "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -2424,20 +2163,10 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" @@ -2453,9 +2182,6 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] [[package]] name = "rand_core" @@ -2696,7 +2422,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.7.0", + "security-framework", ] [[package]] @@ -2724,7 +2450,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -2804,51 +2530,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "secret-lib" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba34b385def61154faed219ac86f80ad8c72877a278208bac2ecdd85d68f962f" -dependencies = [ - "keyring-lib", - "process-lib", - "serde", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "secret-service" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4d35ad99a181be0a60ffcbe85d680d98f87bdc4d7644ade319b87076b9dbfd4" -dependencies = [ - "aes", - "cbc", - "futures-util", - "generic-array", - "hkdf", - "num", - "once_cell", - "rand 0.8.5", - "serde", - "sha2", - "zbus", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.7.0" @@ -2899,9 +2580,9 @@ checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" [[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" [[package]] name = "serde" @@ -2957,22 +2638,11 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "serde_spanned" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -2986,17 +2656,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sha2" version = "0.10.9" @@ -3073,12 +2732,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stop-token" version = "0.7.0" @@ -3219,9 +2872,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -3244,9 +2897,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" dependencies = [ "bytes", "libc", @@ -3256,15 +2909,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "tracing", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -3317,9 +2969,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ "indexmap", "serde_core", @@ -3332,39 +2984,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] -[[package]] -name = "toml_edit" -version = "0.25.8+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" -dependencies = [ - "indexmap", - "toml_datetime", - "toml_parser", - "winnow", -] - [[package]] name = "toml_parser" -version = "1.1.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.1.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tower" @@ -3484,17 +3124,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "uds_windows" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" -dependencies = [ - "memoffset", - "tempfile", - "windows-sys 0.61.2", -] - [[package]] name = "unicode-ident" version = "1.0.24" @@ -3611,9 +3240,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.115" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" dependencies = [ "cfg-if", "once_cell", @@ -3624,9 +3253,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.65" +version = "0.4.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" dependencies = [ "js-sys", "wasm-bindgen", @@ -3634,9 +3263,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.115" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3644,9 +3273,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.115" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ "bumpalo", "proc-macro2", @@ -3657,9 +3286,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.115" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" dependencies = [ "unicode-ident", ] @@ -3700,9 +3329,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.92" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84cde8507f4d7cfcb1185b8cb5890c494ffea65edbe1ba82cfd63661c805ed94" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" dependencies = [ "js-sys", "wasm-bindgen", @@ -3777,6 +3406,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-native-keyring-store" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e26ac29479a4b7f49d46afc9893122fc345430c6307d1fb7ac0d8d066c3f54" +dependencies = [ + "byteorder", + "keyring-core", + "regex", + "windows-sys 0.61.2", + "zeroize", +] + [[package]] name = "windows-registry" version = "0.6.1" @@ -4039,12 +3681,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" -dependencies = [ - "memchr", -] +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" [[package]] name = "wit-bindgen" @@ -4136,25 +3775,15 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "xdg-home" -version = "1.3.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4163,9 +3792,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -4173,69 +3802,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zbus" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" -dependencies = [ - "async-broadcast", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener 5.4.1", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix", - "ordered-stream", - "rand 0.8.5", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tokio", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - [[package]] name = "zerocopy" version = "0.8.48" @@ -4258,18 +3824,18 @@ dependencies = [ [[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", @@ -4299,9 +3865,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -4310,9 +3876,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -4321,9 +3887,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", @@ -4335,40 +3901,3 @@ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zvariant" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" -dependencies = [ - "endi", - "enumflags2", - "serde", - "static_assertions", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml index c82c963..7823a42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,5 @@ +[workspace] + [package] name = "agentmail" version = "0.1.8" @@ -30,20 +32,14 @@ clap = { version = "4", features = ["derive"] } dirs = "6" fast_html2md = "0.0" futures = "0.3" -hashbrown = { version = "0.16", features = ["rayon", "serde"] } +hashbrown = { version = "0.17", features = ["rayon", "serde"] } lettre = { version = "0.11", default-features = false, features = ["builder"] } mail-parser = "0.11" native-tls = "0.2" reqwest = { version = "0.13", features = ["json"] } rmcp = { version = "1.3", features = ["transport-async-rw", "transport-worker"] } schemars = { version = "1.2", features = ["chrono04"] } -secret-lib = { version = "1", features = [ - "command", - "derive", - "keyring", - "rustls", - "tokio" -] } +keyring-core = "0.7" serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "2" @@ -54,6 +50,15 @@ tracing = { version = "0.1", features = ["release_max_level_info"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } uuid = { version = "1", features = ["v4"] } +[target.'cfg(target_os = "macos")'.dependencies] +apple-native-keyring-store = { version = "0.2", features = ["keychain"] } + +[target.'cfg(target_os = "windows")'.dependencies] +windows-native-keyring-store = "0.5" + +[target.'cfg(target_os = "linux")'.dependencies] +dbus-secret-service-keyring-store = { version = "0.3", features = ["crypto-rust"] } + [lints.clippy] await_holding_lock = "deny" cloned_instead_of_copied = "warn" diff --git a/src/config.rs b/src/config.rs index 962ca10..fd27a68 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use hashbrown::HashMap; -use secret::Secret; use serde::Deserialize; + +use crate::secret::Secret; use std::path::PathBuf; /// Top-level configuration file. @@ -39,9 +40,7 @@ impl AccountConfig { /// Password is resolved via keyring using the username. pub fn new(host: impl Into, username: impl Into) -> Self { let username = username.into(); - let password = secret::keyring::KeyringEntry::try_new(&username) - .ok() - .map(Secret::new_keyring_entry); + let password = Some(Secret::new_keyring(format!("mail.{}", username))); Self { host: host.into(), port: 993, diff --git a/src/credentials.rs b/src/credentials.rs index 990afd8..b5ca561 100644 --- a/src/credentials.rs +++ b/src/credentials.rs @@ -1,25 +1,12 @@ use crate::config::AccountConfig; -use secret::Secret; - -/// Initialize the keyring backend with the default "agentmail" service name. -/// Call once at startup before any password operations. -pub fn init_keyring() { - init_keyring_with_service("agentmail"); -} - -/// Initialize the keyring backend with a custom service name. -/// Use this when embedding agentmail in another app (e.g. agent) so credentials -/// are stored under the host app's keyring service, not "agentmail". -pub fn init_keyring_with_service(name: &'static str) { - secret::keyring::set_global_service_name(name); -} +use crate::secret::Secret; /// Retrieve the password for an IMAP account. /// /// Lookup order: /// 1. Environment variable `AGENTMAIL_PASSWORD_{ACCOUNT_NAME}` (override for CI/Docker) /// 2. `password` field in config (Secret: raw, command, or keyring) -/// 3. Default keyring entry under "agentmail" service with username as key (backward compat) +/// 3. Default keyring entry with username as key (backward compat) pub async fn get_password(account_name: &str, config: &AccountConfig) -> crate::Result { // 1. Environment variable override let env_key = format!( @@ -43,13 +30,7 @@ pub async fn get_password(account_name: &str, config: &AccountConfig) -> crate:: // 3. Default keyring fallback (backward compat: handles passwords stored via set-password // before the config had a password field) - let default_entry = secret::keyring::KeyringEntry::try_new(&config.username).map_err(|e| { - crate::AgentmailError::Credential(format!( - "Failed to create default keyring entry for '{}': {}", - config.username, e - )) - })?; - let default_secret = Secret::new_keyring_entry(default_entry); + let default_secret = Secret::new_keyring(format!("mail.{}", config.username)); if let Ok(pw) = default_secret.get().await { return Ok(pw); } @@ -67,7 +48,7 @@ pub async fn get_password(account_name: &str, config: &AccountConfig) -> crate:: /// Store a password for an account in the system keyring. /// /// If the config has a Keyring secret, stores into that entry. -/// Otherwise, stores under the default "agentmail" service with the username as key. +/// Otherwise, stores under the default service with the username as key. pub async fn set_password( account_name: &str, config: &AccountConfig, @@ -75,15 +56,7 @@ pub async fn set_password( ) -> crate::Result<()> { let mut secret = match config.password { Some(ref s @ Secret::Keyring(_)) => s.clone(), - _ => { - let entry = secret::keyring::KeyringEntry::try_new(&config.username).map_err(|e| { - crate::AgentmailError::Credential(format!( - "Failed to create keyring entry for '{}': {}", - config.username, e - )) - })?; - Secret::new_keyring_entry(entry) - } + _ => Secret::new_keyring(format!("mail.{}", config.username)), }; secret.set(password).await.map_err(|e| { diff --git a/src/lib.rs b/src/lib.rs index aca827c..e94340c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,14 +8,15 @@ pub mod imap_client; pub mod mcp; pub mod parser; pub mod provider; +pub mod secret; pub mod types; pub use config::{AccountConfig, Config}; pub use connection::ConnectionPool; -pub use credentials::init_keyring_with_service; pub use error::{AgentmailError, Result}; pub use imap_client::ProgressFn; pub use provider::MailProvider; +pub use secret::init_service_name; pub use types::*; /// High-level facade for IMAP operations. diff --git a/src/main.rs b/src/main.rs index c14e12f..8f84850 100644 --- a/src/main.rs +++ b/src/main.rs @@ -167,7 +167,26 @@ async fn main() -> Result<(), Box> { ) .init(); - agentmail::credentials::init_keyring(); + agentmail::secret::init_service_name("agentmail"); + // Initialize platform keyring store for standalone mode + #[cfg(target_os = "macos")] + { + if let Ok(store) = apple_native_keyring_store::keychain::Store::new() { + keyring_core::set_default_store(store); + } + } + #[cfg(target_os = "windows")] + { + if let Ok(store) = windows_native_keyring_store::Store::new() { + keyring_core::set_default_store(store); + } + } + #[cfg(target_os = "linux")] + { + if let Ok(store) = dbus_secret_service_keyring_store::Store::new() { + keyring_core::set_default_store(store); + } + } let cli = Cli::parse(); match cli.command.unwrap_or(CliCommand::Serve) { @@ -481,7 +500,7 @@ async fn configure_account(provider: Option<&str>) -> Result<(), Box { // keyring (default) - (format!("password.keyring = {:?}", username), true) + (format!("password.keyring = \"mail.{}\"", username), true) } }; @@ -532,9 +551,7 @@ async fn configure_account(provider: Option<&str>) -> Result<(), Box AccountConfig { - let password = secret::keyring::KeyringEntry::try_new(username) - .ok() - .map(Secret::new_keyring_entry); + let password = Some(Secret::new_keyring(format!("mail.{}", username))); AccountConfig { host: self.host().to_string(), diff --git a/src/secret.rs b/src/secret.rs new file mode 100644 index 0000000..c05a4fd --- /dev/null +++ b/src/secret.rs @@ -0,0 +1,138 @@ +//! Secret type for password/credential storage. +//! +//! Replaces the `secret::Secret` type from the `secret-lib` crate. +//! Supports three storage backends: +//! - `Raw` — plaintext value (for testing/config) +//! - `Keyring` — OS keyring entry (macOS Keychain, etc.) +//! - `Command` — shell command whose stdout is the password + +use std::sync::OnceLock; + +use serde::Deserialize; + +/// Keyring service name. Set at app startup. Falls back to `"agentmail"` for standalone use. +static SERVICE_NAME: OnceLock = OnceLock::new(); + +/// Initialize the keyring service name. +/// +/// When embedded in the Agent app, this is set to the app's bundle identifier. +/// When running standalone, this defaults to `"agentmail"`. +pub fn init_service_name(name: &str) { + SERVICE_NAME.set(name.to_string()).ok(); +} + +/// Returns the current keyring service name. +pub fn service_name() -> &'static str { + SERVICE_NAME + .get() + .map(|s| s.as_str()) + .unwrap_or("agentmail") +} + +/// A secret value that can be stored in different backends. +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum Secret { + /// Plaintext value. + Raw(String), + /// OS keyring entry key (the service name is implicit from [`service_name()`]). + Keyring(String), + /// Shell command whose stdout is the secret. + #[serde(alias = "cmd")] + Command(String), +} + +impl Secret { + /// Create a raw (plaintext) secret. + pub fn new_raw(value: impl Into) -> Self { + Self::Raw(value.into()) + } + + /// Create a keyring-backed secret. + pub fn new_keyring(key: impl Into) -> Self { + Self::Keyring(key.into()) + } + + /// Retrieve the secret value. + pub async fn get(&self) -> Result { + match self { + Secret::Raw(v) => Ok(v.clone()), + Secret::Keyring(key) => { + let service = service_name().to_string(); + let key = key.clone(); + tokio::task::spawn_blocking(move || { + let entry = keyring_core::Entry::new(&service, &key) + .map_err(|e| format!("keyring entry error: {e}"))?; + entry + .get_password() + .map_err(|e| format!("keyring get_password error: {e}")) + }) + .await + .map_err(|e| format!("spawn_blocking error: {e}"))? + } + Secret::Command(cmd) => { + let output = tokio::process::Command::new("sh") + .args(["-c", cmd]) + .output() + .await + .map_err(|e| format!("command error: {e}"))?; + if !output.status.success() { + return Err(format!( + "command failed ({}): {}", + output.status, + String::from_utf8_lossy(&output.stderr).trim() + )); + } + Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()) + } + } + } + + /// Store a value into this secret's backend. + pub async fn set(&mut self, value: &str) -> Result<(), String> { + match self { + Secret::Raw(v) => { + *v = value.to_string(); + Ok(()) + } + Secret::Keyring(key) => { + let service = service_name().to_string(); + let key = key.clone(); + let value = value.to_string(); + tokio::task::spawn_blocking(move || { + let entry = keyring_core::Entry::new(&service, &key) + .map_err(|e| format!("keyring entry error: {e}"))?; + entry + .set_password(&value) + .map_err(|e| format!("keyring set_password error: {e}")) + }) + .await + .map_err(|e| format!("spawn_blocking error: {e}"))? + } + Secret::Command(_) => Err("Cannot set a command-based secret".to_string()), + } + } + + /// Delete this secret from its backend. + pub async fn delete(&mut self) -> Result<(), String> { + match self { + Secret::Raw(v) => { + v.clear(); + Ok(()) + } + Secret::Keyring(key) => { + let service = service_name().to_string(); + let key = key.clone(); + tokio::task::spawn_blocking(move || { + if let Ok(entry) = keyring_core::Entry::new(&service, &key) { + let _ = entry.delete_credential(); + } + Ok(()) + }) + .await + .map_err(|e| format!("spawn_blocking error: {e}"))? + } + Secret::Command(_) => Ok(()), + } + } +}