From 2702c385558f942df29e3b1f1f330046e97ca267 Mon Sep 17 00:00:00 2001 From: Ibrahim Rahhal Date: Sat, 19 Jul 2025 10:24:42 +0300 Subject: [PATCH] Adding Sentry/ Improved loggign reporting --- .github/workflows/release-binaries.yml | 16 +- .github/workflows/release.yml | 8 + .gitignore | 2 + Cargo.lock | 963 ++++++++++++++++++++++++- Cargo.toml | 11 +- src/config.rs | 7 +- src/main.rs | 95 ++- src/scanners/blast.rs | 8 +- src/utils/api.rs | 148 +++- src/utils/err.rs | 119 +++ src/utils/generic.rs | 15 + 11 files changed, 1288 insertions(+), 104 deletions(-) create mode 100644 src/utils/err.rs diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index e267960..cc92674 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -39,14 +39,28 @@ jobs: run: rustup target add ${{ matrix.target }} - name: Build Binary + env: + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} run: cargo build --release --target ${{ matrix.target }} - - name: Archive Binary + - name: Install Sentry CLI + if: startsWith(github.ref, 'refs/tags/') + run: npm install -g @sentry/cli + + - name: Upload Debug Files to Sentry + if: startsWith(github.ref, 'refs/tags/') + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: | + npx @sentry/cli upload-dif --org ${{ secrets.SENTRY_ORG }} --project ${{ secrets.SENTRY_PROJECT }} ./target/${{ matrix.target }}/release + + - name: Archive Binary (excluding debug files) run: | BIN_NAME="corgea${{ matrix.ext }}" TARGET_DIR="target/${{ matrix.target }}/release" ARCHIVE_NAME="${BIN_NAME}-${{ matrix.target }}.zip" cd $TARGET_DIR + # Only include the binary, exclude debug files zip -j "../../../$ARCHIVE_NAME" "$BIN_NAME" shell: bash diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4d8c03..45f2e4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,8 @@ jobs: - uses: actions/checkout@v4 - name: Build wheels uses: PyO3/maturin-action@v1 + env: + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} with: target: ${{ matrix.platform.target }} args: --release --out dist @@ -64,6 +66,8 @@ jobs: - uses: actions/checkout@v4 - name: Build wheels uses: PyO3/maturin-action@v1 + env: + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} with: target: ${{ matrix.platform.target }} args: --release --out dist @@ -86,6 +90,8 @@ jobs: - uses: actions/checkout@v4 - name: Build wheels uses: PyO3/maturin-action@v1 + env: + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} with: target: ${{ matrix.platform.target }} args: --release --out dist @@ -101,6 +107,8 @@ jobs: - uses: actions/checkout@v4 - name: Build sdist uses: PyO3/maturin-action@v1 + env: + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} with: command: sdist args: --out dist diff --git a/.gitignore b/.gitignore index 894c98c..80cf8bf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ .DS_Store .dccache *.zip +.env +.vscode \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index dfe2dc2..47ff5e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,158 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "actix-codec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "base64", + "bitflags", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "foldhash", + "futures-core", + "http 0.2.12", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand 0.9.1", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-router" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" +dependencies = [ + "bytestring", + "cfg-if", + "http 0.2.12", + "regex-lite", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e3b15b3dc6c6ed996e4032389e9849d4ab002b1e92fbfe85b5f307d1479b4d" +dependencies = [ + "actix-codec", + "actix-http", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "bytes", + "bytestring", + "cfg-if", + "derive_more", + "encoding_rs", + "foldhash", + "futures-core", + "futures-util", + "impl-more", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex-lite", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "tracing", + "url", +] + [[package]] name = "addr2line" version = "0.24.2" @@ -138,6 +290,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + [[package]] name = "bitflags" version = "2.8.0" @@ -181,6 +339,15 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "bytestring" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +dependencies = [ + "bytes", +] + [[package]] name = "bzip2" version = "0.5.2" @@ -299,6 +466,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.0" @@ -317,23 +494,28 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "corgea" -version = "1.6.2" +version = "1.6.5" dependencies = [ "chrono", "clap", "dirs", + "dotenv", "git2", "globset", "ignore", - "quick-xml", + "quick-xml 0.36.2", "regex", "reqwest", + "sentry", + "sentry-tracing", "serde", "serde_derive", "serde_json", "tempfile", "termcolor", "toml", + "tracing", + "tracing-subscriber", "uuid", "which", "zip", @@ -407,12 +589,32 @@ dependencies = [ "typenum", ] +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + [[package]] name = "deflate64" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.11" @@ -433,6 +635,27 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "digest" version = "0.10.7" @@ -476,12 +699,27 @@ dependencies = [ "syn", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -504,6 +742,18 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + [[package]] name = "flate2" version = "1.0.35" @@ -520,6 +770,27 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -660,6 +931,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hmac" version = "0.12.1" @@ -678,6 +955,28 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "hostname" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.2.0" @@ -696,7 +995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.2.0", ] [[package]] @@ -707,7 +1006,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http", + "http 1.2.0", "http-body", "pin-project-lite", ] @@ -718,6 +1017,12 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hyper" version = "1.6.0" @@ -727,7 +1032,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", + "http 1.2.0", "http-body", "httparse", "itoa", @@ -744,7 +1049,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http", + "http 1.2.0", "hyper", "hyper-util", "rustls", @@ -756,6 +1061,22 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.10" @@ -765,7 +1086,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", + "http 1.2.0", "http-body", "hyper", "pin-project-lite", @@ -953,6 +1274,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "impl-more" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" + [[package]] name = "indexmap" version = "2.7.1" @@ -1009,6 +1336,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.169" @@ -1061,6 +1400,33 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "lockfree-object-pool" version = "0.1.6" @@ -1132,10 +1498,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1167,10 +1561,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "openssl-probe" -version = "0.1.6" +name = "openssl" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "option-ext" @@ -1178,6 +1610,47 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "os_info" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0e1ac5fde8d43c34139135df8ea9ee9465394b2d8d20f032d38998f64afffc3" +dependencies = [ + "log", + "plist", + "serde", + "windows-sys 0.52.0", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "pbkdf2" version = "0.12.2" @@ -1188,6 +1661,15 @@ dependencies = [ "hmac", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1212,6 +1694,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plist" +version = "1.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" +dependencies = [ + "base64", + "indexmap", + "quick-xml 0.38.0", + "serde", + "time", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1245,6 +1740,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.6" @@ -1258,7 +1762,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -1271,13 +1775,13 @@ checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", "getrandom 0.2.15", - "rand", + "rand 0.8.5", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tracing", "web-time", @@ -1313,8 +1817,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -1324,7 +1838,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -1336,6 +1860,24 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.6" @@ -1370,6 +1912,12 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.8.5" @@ -1387,17 +1935,19 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", + "http 1.2.0", "http-body", "http-body-util", "hyper", "hyper-rustls", + "hyper-tls", "hyper-util", "ipnet", "js-sys", "log", "mime", "mime_guess", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -1411,6 +1961,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-native-tls", "tokio-rustls", "tower", "tower-service", @@ -1448,6 +1999,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1484,7 +2044,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.2.0", ] [[package]] @@ -1546,6 +2106,25 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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.2.0" @@ -1553,7 +2132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -1569,6 +2148,132 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "sentry" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507ac2be9bf2da56c831da57faf1dadd81f434bd282935cdb06193d0c94e8811" +dependencies = [ + "httpdate", + "native-tls", + "reqwest", + "sentry-actix", + "sentry-backtrace", + "sentry-contexts", + "sentry-core", + "sentry-debug-images", + "sentry-panic", + "sentry-tracing", + "tokio", + "ureq", +] + +[[package]] +name = "sentry-actix" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8402c142005ee560ae361c73ebece13a299ec3e9cce5b8654479ea9aac8dc8df" +dependencies = [ + "actix-http", + "actix-web", + "bytes", + "futures-util", + "sentry-core", +] + +[[package]] +name = "sentry-backtrace" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb4416302fa5325181a120e0fe7d4afd83cd95e52a9b86afa34a8161383fe0dc" +dependencies = [ + "backtrace", + "regex", + "sentry-core", +] + +[[package]] +name = "sentry-contexts" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936752f42b6f651dcb257da0bfa235ecc79e82011c49ed3383c212cc582263ff" +dependencies = [ + "hostname", + "libc", + "os_info", + "rustc_version", + "sentry-core", + "uname", +] + +[[package]] +name = "sentry-core" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e9bd2cadaeda3af41e9fa5d14645127d6f6a4aec73da3ae38e477ecafd3682" +dependencies = [ + "rand 0.9.1", + "sentry-types", + "serde", + "serde_json", +] + +[[package]] +name = "sentry-debug-images" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e074fe9a0970c91999b23ed3195e6e30990d589fba3a68f20a1686af0f5cda" +dependencies = [ + "findshlibs", + "sentry-core", +] + +[[package]] +name = "sentry-panic" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4651d34f3ba649d9e6dc1268443cae6728b8f741c2f0264004f8ecf5b247330d" +dependencies = [ + "sentry-backtrace", + "sentry-core", +] + +[[package]] +name = "sentry-tracing" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c25c47d36bc80c74d26d568ffe970c37b337c061b7234ad6f2d159439c16f000" +dependencies = [ + "bitflags", + "sentry-backtrace", + "sentry-core", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sentry-types" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08e7154abe2cd557f26fd70038452810748aefdf39bc973f674421224b147c1" +dependencies = [ + "debugid", + "hex", + "rand 0.9.1", + "serde", + "serde_json", + "thiserror 2.0.12", + "time", + "url", + "uuid", +] + [[package]] name = "serde" version = "1.0.217" @@ -1633,12 +2338,30 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -1753,11 +2476,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -1773,15 +2496,24 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.37" @@ -1789,10 +2521,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", "time-core", + "time-macros", ] [[package]] @@ -1801,6 +2535,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -1836,11 +2580,23 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", "windows-sys 0.52.0", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.1" @@ -1851,6 +2607,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.19" @@ -1918,10 +2687,23 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.33" @@ -1929,6 +2711,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -1943,6 +2751,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uname" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" +dependencies = [ + "libc", +] + [[package]] name = "unicase" version = "2.8.1" @@ -1955,12 +2772,48 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "3.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0fde9bc91026e381155f8c67cb354bcd35260b2f4a29bcc84639f762760c39" +dependencies = [ + "base64", + "der", + "log", + "native-tls", + "percent-encoding", + "rustls-pemfile", + "rustls-pki-types", + "ureq-proto", + "utf-8", + "webpki-root-certs 0.26.11", +] + +[[package]] +name = "ureq-proto" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59db78ad1923f2b1be62b6da81fe80b173605ca0d57f85da2e005382adf693f7" +dependencies = [ + "base64", + "http 1.2.0", + "httparse", + "log", +] + [[package]] name = "url" version = "2.5.4" @@ -1970,8 +2823,15 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -1997,8 +2857,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "getrandom 0.2.15", + "serde", ] +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" @@ -2136,6 +3003,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.2", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.26.8" @@ -2157,6 +3042,22 @@ dependencies = [ "winsafe", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -2166,6 +3067,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.52.0" @@ -2175,6 +3082,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-registry" version = "0.2.0" @@ -2528,7 +3441,7 @@ dependencies = [ "memchr", "pbkdf2", "sha1", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "xz2", "zeroize", diff --git a/Cargo.toml b/Cargo.toml index d005968..3c89546 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,15 @@ [package] name = "corgea" -version = "1.6.4" +version = "1.6.5" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +sentry = { version = "0.41.0", features = ["tracing"] } +sentry-tracing = "0.41.0" +tracing = "0.1" +tracing-subscriber = "0.3" clap = { version = "4.4.13", features = ["derive"] } dirs = "5.0.1" reqwest = { version = "0.12", default-features = false, features = [ @@ -30,3 +34,8 @@ termcolor = "1.1" git2 = { version = "0.20.0", default-features = false } regex = "1" chrono = "0.4" +dotenv = "0.15" + +[profile.release] +debug = true +split-debuginfo = "packed" \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 8976c61..d089ca3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; use std::{env, fs, io}; use toml; +use crate::utils::generic; #[derive(Serialize, Deserialize, Clone)] pub struct Config { @@ -83,11 +84,7 @@ impl Config { self.url.clone() }; - if url.ends_with('/') { - url.trim_end_matches('/').to_string() - } else { - url - } + generic::process_url(&url) } pub fn get_token(&self) -> String { diff --git a/src/main.rs b/src/main.rs index 24421c7..1c7ff50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ mod utils { pub mod terminal; pub mod generic; pub mod api; + pub mod err; } use std::str::FromStr; @@ -155,39 +156,36 @@ impl FromStr for Scanner { } fn main() { + dotenv::dotenv().ok(); let cli = Cli::parse(); - let mut corgea_config = Config::load().expect("Failed to load config"); - fn verify_token_and_exit_when_fail (config: &Config) { - if config.get_token().is_empty() { - eprintln!("No token set.\nPlease run 'corgea login' to authenticate.\nFor more info checkout our docs at Check out our docs at https://docs.corgea.app/install_cli#login-with-the-cli"); - std::process::exit(1); - } - match utils::api::verify_token(config.get_token().as_str(), config.get_url().as_str()) { - Ok(true) => { - return; - } - Ok(false) => { - println!("Invalid token provided.\nPlease run 'corgea login' to authenticate.\nFor more info checkout our docs at Check out our docs at https://docs.corgea.app/install_cli#login-with-the-cli"); - std::process::exit(1); - }, - Err(e) => { - eprintln!("Error occurred: {}", e); - std::process::exit(1); - } - } - } + let corgea_config = Config::load().expect("Failed to load config"); + let _guard = utils::err::init_error_reporting(); + execute_command(cli, corgea_config); + + utils::err::wait_for_sentry_to_flush(); + +} + + +fn execute_command(cli: Cli, mut corgea_config: Config) { match &cli.command { Some(Commands::Login { token, url }) => { - match utils::api::verify_token(token, url.as_deref().unwrap_or(corgea_config.get_url().as_str())) { - Ok(true) => { + match utils::api::verify_token(token, utils::generic::process_url(url.as_deref().unwrap_or(corgea_config.get_url().as_str())).as_str()) { + Ok(_ ) => { corgea_config.set_token(token.clone()).expect("Failed to set token"); if let Some(url) = url { corgea_config.set_url(url.clone()).expect("Failed to set url"); } println!("Successfully authenticated to Corgea.") } - Ok(false) => println!("Invalid token provided."), - Err(e) => eprintln!("Error occurred: {}", e), + Err(e) => { + if e.to_string().contains("401") || e.to_string().contains("403") { + println!("Invalid token provided."); + return; + } else { + panic!("[CUSTOM] Something went wrong validating your API token. Please try again later.\nDetails: {}", e.to_string()); + } + } } } Some(Commands::Upload { report }) => { @@ -210,68 +208,68 @@ fn main() { if let Some(level) = fail_on { if *scanner != Scanner::Blast { eprintln!("fail_on is only supported with blast scanner."); - std::process::exit(1); + return; } if !["CR", "HI", "LO", "ME"].contains(&level.as_str()) { eprintln!("Invalid fail_on option. Expected one of 'CR', 'HI', 'ME', 'LO'."); - std::process::exit(1); + return; } } if *fail && *scanner != Scanner::Blast { eprintln!("fail is only supported with blast scanner."); - std::process::exit(1); + return; } if *only_uncommitted && *scanner != Scanner::Blast { eprintln!("only_uncommitted is only supported with blast scanner."); - std::process::exit(1); + return; } if out_file.is_some() && *scanner != Scanner::Blast { eprintln!("out_file is only supported with blast scanner."); - std::process::exit(1); + return; } if out_format.is_some() && *scanner != Scanner::Blast { eprintln!("out_format is only supported with blast scanner."); - std::process::exit(1); + return; } if out_file.is_some() && !out_format.is_some() || !out_file.is_some() && out_format.is_some() { eprintln!("out_file and out_format must be used together."); - std::process::exit(1); + return; } if *fail && fail_on.is_some() { eprintln!("fail and fail_on cannot be used together."); - std::process::exit(1); + return; } if let Some(scan_type) = scan_type { if scan_type.is_empty() { eprintln!("scan_type cannot be empty."); - std::process::exit(1); + return; } let supported_scan_types = ["blast", "malicious", "policy", "secrets", "pii"]; let scan_types: Vec<_> = scan_type.split(',').map(|t| t.trim()).collect(); for scan in scan_types { if !supported_scan_types.contains(&scan) { eprintln!("Invalid scan_type: {}. Supported types are: blast, malicious, policy, secrets, pii.", scan); - std::process::exit(1); + return; } } } if let Some(policy) = policy { if policy.is_empty() { eprintln!("policy cannot be empty."); - std::process::exit(1); + return; } let policy_ids: Vec<_> = policy.split(',').map(|t| t.trim()).collect(); for policy_id in policy_ids { if policy_id.is_empty() { eprintln!("One of the policy ids passed is empty."); - std::process::exit(1); + return; } } if scan_type.is_none() { @@ -292,11 +290,11 @@ fn main() { verify_token_and_exit_when_fail(&corgea_config); if *issues && *sca_issues { eprintln!("Cannot use both --issues and --sca-issues at the same time."); - std::process::exit(1); + return; } if scan_id.is_some() && !*issues && !*sca_issues { println!("scan_id option is only supported for issues list command."); - std::process::exit(1); + return; } list::run(&corgea_config, issues, sca_issues, json, page, page_size, scan_id); } @@ -314,3 +312,24 @@ fn main() { } } } + +fn verify_token_and_exit_when_fail (config: &Config) { + if config.get_token().is_empty() { + eprintln!("No token set.\nPlease run 'corgea login' to authenticate.\nFor more info checkout our docs at Check out our docs at https://docs.corgea.app/install_cli#login-with-the-cli"); + std::process::exit(1); + } + match utils::api::verify_token(config.get_token().as_str(), config.get_url().as_str()) { + Ok(response ) => { + utils::err::attach_user_info_to_error_reporting(&response.user); + return; + } + Err(err) => { + if err.to_string().contains("401") || err.to_string().contains("403") { + println!("Invalid token provided.\nPlease run 'corgea login' to authenticate.\nFor more info checkout our docs at Check out our docs at https://docs.corgea.app/install_cli#login-with-the-cli"); + std::process::exit(1); + } else { + panic!("[CUSTOM] Something went wrong validating your API token. Please try again later.\nDetails: {}", err.to_string()); + } + } + } +} \ No newline at end of file diff --git a/src/scanners/blast.rs b/src/scanners/blast.rs index 77912ed..20a4cc5 100644 --- a/src/scanners/blast.rs +++ b/src/scanners/blast.rs @@ -22,7 +22,7 @@ pub fn run( ) { if *only_uncommitted && !utils::generic::is_git_repo("./") { eprintln!("This is not a git repository. Without a git repository Corgea CLI can't determine which files have been modified or added thus only a full scan is possible."); - std::process::exit(1); + return; } println!( "\nScanning with BLAST 🚀🚀🚀" @@ -52,7 +52,7 @@ pub fn run( "\n\nOops! Something went wrong while creating the directory at '{}'.\nPlease check if you have the necessary permissions or if the path is valid.\nError details:\n{}\n\n", temp_dir.display(), e ); - std::process::exit(1); + return; } } @@ -126,7 +126,7 @@ pub fn run( let scan_id = match utils::api::upload_zip(&zip_path, &config.get_token(), &config.get_url(), &project_name, repo_info, scan_type, policy) { Ok(result) => result, Err(e) => { - eprintln!("\n\nOh no! We encountered an issue while uploading the zip file '{}' to the server.\nPlease ensure that: + let error_message = format!("[CUSTOM]\n\nOh no! We encountered an issue while uploading the zip file '{}' to the server.\nPlease ensure that: - Blast is enabled on your Corgea account. - Your network connection is stable. - The server URL '{}' is correct. @@ -139,7 +139,7 @@ pub fn run( config.get_url(), e ); - std::process::exit(1); + panic!("{}", error_message); }, }; diff --git a/src/utils/api.rs b/src/utils/api.rs index 466d6a4..98c370c 100644 --- a/src/utils/api.rs +++ b/src/utils/api.rs @@ -11,26 +11,28 @@ use std::path::Path; use reqwest::{blocking::multipart, blocking::multipart::{Form, Part}}; use serde_json::Value; use crate::log::debug; - +use tracing::instrument; const CHUNK_SIZE: usize = 50 * 1024 * 1024; // 50 MB const API_BASE: &str = "/api/v1"; +#[instrument] fn check_for_warnings(headers: &HeaderMap, status: StatusCode) { if let Some(warning) = headers.get("warning") { let warnings = warning.to_str().unwrap().split(','); for warning in warnings { let code = warning.trim().split(' ').next().unwrap(); if code == "299" { - eprintln!("This version of the Corgea plugin is deprecated. Please upgrade to the latest version to ensure continued support and better performance."); + utils::err::log_info("This version of the Corgea plugin is deprecated. Please upgrade to the latest version to ensure continued support and better performance.", None); } } } if status == StatusCode::GONE { - eprintln!("Support for this extension version has dropped. Please upgrade Corgea extension immediately to continue using it."); + utils::err::log_warning("Support for this extension version has dropped. Please upgrade Corgea extension immediately to continue using it.", None); std::process::exit(1); } } +#[instrument] pub fn upload_zip( file_path: &str , token: &str, @@ -74,24 +76,34 @@ pub fn upload_zip( check_for_warnings(response.headers(), response.status()); response }, - Err(err) => return Err(format!("Network error: Unable to reach the server. Please try again later. Error: {}", err).into()), + Err(err) => { + utils::err::log_error(&err.to_string(), Some(false)); + return Err(format!("Network error: Unable to reach the server. Please try again later. Error: {}", err).into()); + }, }; let response_status = response_object.status(); let response: HashMap = match response_object.json() { Ok(json) => json, - Err(_) => return Err("Error getting server response, Please try again later.".into()), + Err(err) => { + utils::err::log_error(&err.to_string(), Some(false)); + return Err(format!("Error getting server response, Please try again later. Error: {}", err).into()); + }, }; if response_status != StatusCode::OK { let message = response.get("message") .and_then(Value::as_str) .unwrap_or("An unknown error occurred. Please try again or contact support."); + utils::err::log_error(&format!("Request failed: {}", message), Some(false)); return Err(format!("Request failed: {}", message).into()); } let transfer_id = match response["transfer_id"].as_str() { Some(transfer_id) => transfer_id, - None => return Err("Failed to retrieve transfer ID. Please check the request parameters and try again.".into()), + None => { + utils::err::log_error("Failed to retrieve transfer ID. Please check the request parameters and try again.", Some(false)); + return Err("Failed to retrieve transfer ID. Please check the request parameters and try again.".into()); + }, }; let mut file = File::open(file_path)?; let mut buffer = vec![0; CHUNK_SIZE]; @@ -158,9 +170,13 @@ pub fn upload_zip( }; if !response.status().is_success() { let status_code = response.status(); - if status_code.is_client_error() && response.text().unwrap().contains("Invalid policy ids") { + let response_text = response.text().unwrap_or_default(); + if status_code.is_client_error() && response_text.contains("Invalid policy ids") { return Err("Invalid policy ids passed. Please check the policy ids and try again.".into()); + } else { + utils::err::log_error(&format!("Failed to upload file: {}, response: {}", status_code, response_text), Some(false)); } + return Err(format!("Failed to upload file: {}", status_code).into()); } @@ -170,10 +186,12 @@ pub fn upload_zip( if bytes_read < CHUNK_SIZE { utils::terminal::show_progress_bar(1.0); print!("\n"); - let body: HashMap = response.json()?; + let response_text = response.text()?; + let body: HashMap = serde_json::from_str(&response_text)?; if let Some(scan_id_value) = body.get("scan_id") { return Ok(scan_id_value.as_str().unwrap().to_string()); } else { + utils::err::log_error(&format!("Failed to get scan_id from response: {}", response_text), Some(false)); return Err("Failed to get scan_id from response".into()); } } @@ -182,6 +200,7 @@ pub fn upload_zip( Err("Failed to upload file".into()) } +#[instrument] pub fn get_all_issues(url: &str, token: &str, project: &str, scan_id: Option) -> Result, Box> { let mut all_issues = Vec::new(); let mut current_page: u32 = 1; @@ -189,7 +208,10 @@ pub fn get_all_issues(url: &str, token: &str, project: &str, scan_id: Option response, - Err(e) => return Err(format!("Failed to get scan issues: {}", e).into()) + Err(e) => { + utils::err::log_error(&format!("Failed to get scan issues: {}, project: {}, scan_id: {}", e, project, scan_id.unwrap_or("None".to_string())), Some(false)); + return Err(format!("Failed to get scan issues: {}", e).into()); + } }; if let Some(mut issues) = response.issues { @@ -211,6 +233,7 @@ pub fn get_all_issues(url: &str, token: &str, project: &str, scan_id: Option, scan_id: Option ) -> Result> { + let scan_id_clone = scan_id.clone(); let mut seperator = "?"; let mut url = match scan_id { Some(scan_id) => format!("{}{}/scan/{}/issues", url, API_BASE, scan_id), @@ -252,11 +276,16 @@ pub fn get_scan_issues( check_for_warnings(res.headers(), res.status()); res }, - Err(e) => return Err(format!("Failed to send request: {}", e).into()), + Err(e) => { + utils::err::log_error(&format!("Failed to send request: {}, project: {}, scan_id: {}", e, project, scan_id_clone.as_ref().unwrap_or(&"None".to_string())), Some(false)); + return Err(format!("Failed to send request: {}", e).into()); + }, }; let response_text = response.text()?; let project_issues_response: ProjectIssuesResponse = serde_json::from_str(&response_text).map_err(|e| { - debug(&format!("Failed to parse response: {}. Response body: {}", e, response_text)); + let debug_message = format!("Failed to parse response: {}. Response body: {}", e, response_text); + utils::err::log_error(&debug_message, Some(false)); + debug(&debug_message); format!("Failed to parse response: {}", e) })?; @@ -265,12 +294,14 @@ pub fn get_scan_issues( } else if project_issues_response.status == "no_project_found" { Err("Project not found 404".into()) } else { + utils::err::log_error(&format!("Server error 500, response: {}", response_text), Some(false)); Err("Server error 500".into()) } } +#[instrument] pub fn get_scan(url: &str, token: &str, scan_id: &str) -> Result> { - let url = format!("{}{}/scan/{}", url, API_BASE, scan_id); + let url: String = format!("{}{}/scan/{}", url, API_BASE, scan_id); let client = reqwest::blocking::Client::new(); @@ -294,10 +325,14 @@ pub fn get_scan(url: &str, token: &str, scan_id: &str) -> Result Result> { let url = format!("{}{}/scan/{}/report", url, API_BASE, scan_id); @@ -319,10 +354,14 @@ pub fn get_scan_report(url: &str, token: &str, scan_id: &str) -> Result Result> { let url = format!( "{}{}/issue/{}", @@ -346,14 +385,15 @@ pub fn get_issue(url: &str, token: &str, issue: &str) -> Result(&response_text) { Ok(body) => Ok(body), Err(e) => { - debug(&format!("Failed to parse response: {}. Response body: {}", e, response_text)); + let debug_message = format!("Failed to parse response: {}. Response body: {}", e, response_text); + utils::err::log_error(&debug_message, Some(false)); + debug(&debug_message); Err(format!("Failed to parse response: {}", e).into()) }, }; } - - +#[instrument] pub fn query_scan_list( url: &str, token: &str, @@ -393,21 +433,26 @@ pub fn query_scan_list( if response.status().is_success() { let response_text = response.text()?; let api_response: ScansResponse = serde_json::from_str(&response_text).map_err(|e| { - debug(&format!("Failed to parse response: {}. Response body: {}", e, response_text)); + let debug_message = format!("Failed to parse response: {}. Response body: {}", e, response_text); + utils::err::log_error(&debug_message, Some(false)); + debug(&debug_message); format!("Failed to parse response: {}", e) })?; Ok(api_response) } else { + let status = response.status(); + let response_text = response.text().unwrap_or_default(); + utils::err::log_error(&format!("Request failed with status: {}, response: {}", status, response_text), Some(false)); Err(format!( "API request failed with status: {}", - response.status() + status ).into()) } } - -pub fn verify_token(token: &str, corgea_url: &str) -> Result> { - let url = format!("{}{}/verify", corgea_url, API_BASE); +#[instrument(skip(token))] +pub fn verify_token(token: &str, corgea_url: &str) -> Result> { + let url = format!("{}{}/verify?user_info=true", corgea_url, API_BASE); let client = reqwest::blocking::Client::new(); let mut headers = HeaderMap::new(); headers.insert("CORGEA-TOKEN", token.parse().unwrap()); @@ -423,7 +468,7 @@ pub fn verify_token(token: &str, corgea_url: &str) -> Result = match serde_json::from_str(&body_text) { + let body: VerifyTokenResponse = match serde_json::from_str(&body_text) { Ok(json) => json, Err(e) => { debug(&format!("Failed to parse response as JSON: {}. Response body: {}", e, body_text)); @@ -431,12 +476,18 @@ pub fn verify_token(token: &str, corgea_url: &str) -> Result return Err(format!("API request failed: {}", e).into()), + Err(e) => { + utils::err::log_error(&format!("API request failed: {}", e), Some(false)); + return Err(format!("API request failed: {}", e).into()); + }, }; if response.status().is_success() { @@ -479,6 +533,7 @@ pub fn check_blocking_rules( let status = response.status(); let response_text = response.text()?; debug(&format!("Response body: {}", response_text)); + utils::err::log_error(&format!("API request failed with status: {}, response: {}", status, response_text), Some(false)); Err(format!( "API request failed with status: {}", status @@ -486,7 +541,7 @@ pub fn check_blocking_rules( } } - +#[instrument] pub fn get_sca_issues( url: &str, token: &str, @@ -530,13 +585,20 @@ pub fn get_sca_issues( debug(&format!("Response headers: {:?}", response.headers())); response }, - Err(err) => return Err(format!("Network error: Unable to reach the server. Please try again later. Error: {}", err).into()), + Err(err) => { + utils::err::log_error(&format!("Network error: Unable to reach the server. Please try again later. Error: {}", err), Some(false)); + return Err(format!("Network error: Unable to reach the server. Please try again later. Error: {}", err).into()); + }, }; let status = response.status(); if !status.is_success() { if status == StatusCode::NOT_FOUND { return Err("SCA issues not found. Please check the scan ID or ensure the scan has SCA issues.".into()); + } else { + let status = response.status(); + let response_text = response.text().unwrap_or_default(); + utils::err::log_error(&format!("Request failed with status: {}, response: {}", status, response_text), Some(false)); } return Err(format!("Request failed with status: {}", status).into()); } @@ -545,7 +607,9 @@ pub fn get_sca_issues( let response_data: SCAIssuesResponse = match serde_json::from_str(&response_text) { Ok(json) => json, Err(e) => { - debug(&format!("Failed to parse response: {}. Response body: {}", e, response_text)); + let debug_message = format!("Failed to parse response: {}. Response body: {}", e, response_text); + utils::err::log_error(&debug_message, Some(false)); + debug(&debug_message); return Err("Error parsing server response. Please try again later.".into()) }, }; @@ -553,6 +617,7 @@ pub fn get_sca_issues( Ok(response_data) } +#[instrument] pub fn get_all_sca_issues( url: &str, token: &str, @@ -565,7 +630,10 @@ pub fn get_all_sca_issues( loop { let response = match get_sca_issues(url, token, Some(current_page as u16), Some(30), scan_id.clone()) { Ok(response) => response, - Err(e) => return Err(format!("Failed to get SCA issues: {}", e).into()) + Err(e) => { + utils::err::log_error(&format!("Failed to get SCA issues: {}", e), Some(false)); + return Err(format!("Failed to get SCA issues: {}", e).into()); + }, }; if response.issues.is_empty() { @@ -583,6 +651,26 @@ pub fn get_all_sca_issues( Ok(all_issues) } +#[derive(Deserialize, Serialize, Debug)] +pub struct User { + pub id: u32, + pub email: String, + pub name: String, + pub company: Company, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct Company { + pub id: u32, + pub name: String, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct VerifyTokenResponse { + pub status: String, + pub user: User, +} + #[derive(Deserialize, Serialize, Debug)] pub struct ScanResponse { pub id: String, diff --git a/src/utils/err.rs b/src/utils/err.rs new file mode 100644 index 0000000..2a2c7a3 --- /dev/null +++ b/src/utils/err.rs @@ -0,0 +1,119 @@ +use sentry::{self, configure_scope}; +use std::env; +use crate::utils::api::User; + +pub fn init_error_reporting() -> sentry::ClientInitGuard { + let sentry_dsn = env!("SENTRY_DSN"); + let guard = sentry::init((sentry_dsn, sentry::ClientOptions { + release: sentry::release_name!(), + traces_sample_rate: 1.0, + // Capture user IPs and potentially sensitive headers when using HTTP server integrations + // see https://docs.sentry.io/platforms/rust/data-management/data-collected for more info + send_default_pii: true, + ..Default::default() + })); + + attach_cli_args_to_sentry_scope(); + set_custom_panic_hook(); + guard +} + +pub fn log_error(error: &str, should_log_to_console: Option) { + + sentry::capture_message(error, sentry::Level::Error); + if should_log_to_console.unwrap_or(true) { + eprintln!( + "Unexpected error occurred: {}\nDon't worry, we've already reported it to our team.", + error + ); + } + +} + +pub fn log_warning(warning: &str, should_log_to_console: Option) { + sentry::capture_message(warning, sentry::Level::Warning); + if should_log_to_console.unwrap_or(true) { + eprintln!("Warning: {}", warning); + } +} + + + +pub fn wait_for_sentry_to_flush() { + if let Some(client) = sentry::Hub::current().client() { + client.flush(Some(std::time::Duration::from_secs(3))); + } +} + +pub fn log_info(info: &str, should_log_to_console: Option) { + sentry::capture_message(info, sentry::Level::Info); + if should_log_to_console.unwrap_or(true) { + eprintln!("Info: {}", info); + } +} + +fn attach_cli_args_to_sentry_scope() { + let args: Vec = env::args().collect(); + let full_cmd = args.join(" "); + + configure_scope(|scope| { + scope.set_extra("cli_command", full_cmd.into()); + }); +} + +fn set_custom_panic_hook() { + std::panic::set_hook(Box::new(|panic_info| { + let panic_message = if let Some(s) = panic_info.payload().downcast_ref::<&str>() { + *s + } else if let Some(s) = panic_info.payload().downcast_ref::() { + s.as_str() + } else { + "Unknown panic message" + }; + + let location = panic_info + .location() + .map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column())) + .unwrap_or_else(|| "unknown location".to_string()); + let mut is_custom_error = false; + let mut cleaned_message = String::new(); + if panic_message.contains("[CUSTOM]") { + cleaned_message = panic_message.replace("[CUSTOM]", ""); + is_custom_error = true; + } + if is_custom_error { + eprintln!("Error: {cleaned_message}\nDon't worry, we've already reported it to our team."); + } else { + eprintln!("Fatal error occurred at {location}: {cleaned_message}\nDon't worry, we've already reported it to our team."); + } + + sentry::with_scope(|scope| { + scope.set_level(Some(sentry::Level::Fatal)); + scope.set_extra("panic_location", location.clone().into()); + }, || { + sentry::capture_message( + &format!("Panic occurred: {cleaned_message}"), + sentry::Level::Fatal, + ); + }); + + wait_for_sentry_to_flush(); + + std::process::exit(1); + })); +} + +pub fn attach_user_info_to_error_reporting(user_info: &User) { + configure_scope(|scope| { + scope.set_user(Some(sentry::User { + id: Some(user_info.id.to_string()), + email: Some(user_info.email.clone()), + username: Some(user_info.name.clone()), + ..Default::default() + })); + + // Also set company info as extra context + scope.set_extra("company_id", user_info.company.id.into()); + scope.set_extra("company_name", user_info.company.name.clone().into()); + }); +} \ No newline at end of file diff --git a/src/utils/generic.rs b/src/utils/generic.rs index ed239e4..ba8cb14 100644 --- a/src/utils/generic.rs +++ b/src/utils/generic.rs @@ -6,6 +6,7 @@ use globset::{GlobSetBuilder, Glob}; use std::fs::{self, File}; use std::env; use git2::Repository; +use tracing::instrument; pub fn create_zip_from_filtered_files>( directory: P, @@ -144,6 +145,8 @@ pub fn get_current_working_directory() -> Option { .and_then(|path| path.file_name().map(|name| name.to_string_lossy().to_string())) } + +#[instrument] pub fn get_repo_info(dir: &str) -> Result, git2::Error> { let repo = match Repository::open(Path::new(dir)) { Ok(repo) => repo, @@ -181,7 +184,19 @@ pub fn get_status(status: &str) -> &str { _ => status, } } +pub fn process_url(url: &str) -> String { + let mut processed_url = if url.ends_with('/') { + url.trim_end_matches('/').to_string() + } else { + url.to_string() + }; + if !processed_url.starts_with("http://") && !processed_url.starts_with("https://") { + processed_url = format!("https://{}", processed_url); + } + + processed_url +} #[derive(Debug)] pub struct RepoInfo { pub branch: Option,