diff --git a/.gitlab-ci-local-variables.yml b/.gitlab-ci-local-variables.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ccf211b131fd4289066c4363a3f599677a23082e
--- /dev/null
+++ b/.gitlab-ci-local-variables.yml
@@ -0,0 +1,4 @@
+---
+
+DEBUG: 'true'
+TEST_OPTIONS: '--help'
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 122cb08d7b6f282b4d625fd6038d80570c8c4349..154b4be14fe63500de284f1af70f94bfe0d57a83 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,18 +2,15 @@ variables:
   RUST_VERSION: "1.76" # slim or alpine not adapted because of openSSL dependency
   TARGET_ARCH: default
   CARGO_HOME: .cargo
+  TEST_OPTIONS: --url $CI_PROJECT_URL -a
+  CLEAN_OPTIONS: --url $CI_PROJECT_URL -b
 
 default:
   cache:
-    key: rust-$TARGET_ARCH
+    key: rust-$CI_JOB_NAME
     paths:
       - .cargo
-      - target/debug/deps
-      - target/debug/build
-      - target/release/deps
-      - target/release/build
-      - target/$TARGET_ARCH/release/deps
-      - target/$TARGET_ARCH/release/build
+      - target
     policy: pull-push
 
 stages:
@@ -22,8 +19,12 @@ stages:
   - deploy
 
 include:
-  - remote: 'https://api.r2devops.io/job/r/gitlab/r2devops/hub/docker_build@latest.yaml'
-  - remote: 'https://api.r2devops.io/job/r/gitlab/r2devops/hub/gitleaks@latest.yaml'
+  - remote: 'https://gitlab.com/r2devops/hub/-/raw/docker_build@2.0.2/jobs/docker_build/docker_build.yml'
+  - remote: 'https://gitlab.com/r2devops/hub/-/raw/gitleaks@1.2.2/jobs/gitleaks/gitleaks.yml'
+
+gitleaks:
+  stage: build_test
+  cache: [ ]
 
 check-format:
   stage: build_test
@@ -34,15 +35,17 @@ check-format:
     - cargo fmt --all -- --check
     - cargo clippy -- -D warnings
   allow_failure: true
-
-gitleaks:
-  stage: build_test
+  rules:
+    - if: $CI_COMMIT_REF_NAME == 'main'
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
 
 test-rust-current:
   stage: build_test
   image: rust:$RUST_VERSION
   script:
     - cargo test --verbose
+    - cargo run -- $TEST_OPTIONS
+  allow_failure: true
   rules:
     - if: $CI_COMMIT_REF_NAME == 'main'
     - if: $CI_PIPELINE_SOURCE == "merge_request_event"
@@ -51,6 +54,11 @@ test-rust-nightly:
   extends: test-rust-current
   image: rustlang/rust:nightly
 
+test-clean-rust-current:
+  extends: test-rust-current
+  variables:
+    TEST_OPTIONS: $CLEAN_OPTIONS
+
 .rust-release:
   stage: release
   variables:
@@ -59,11 +67,12 @@ test-rust-nightly:
   script:
     - rustup target add $TARGET_ARCH
     - cargo build $CARGO_OPTS --target $TARGET_ARCH --release
-    - if [ -z "$NO_POSTPROCESS" ]; then strip $TARGET; $LDD_CMD $TARGET; $TARGET --help; fi
+    - if [ -z "$NO_POSTPROCESS" ]; then strip $TARGET; $LDD_CMD $TARGET; $TARGET $TEST_OPTIONS; fi
     - 'if [ -z "$DEBUG" ]; then curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file $TARGET "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/$TARGET_ARCH/${CI_COMMIT_TAG:-latest}/$APP_NAME"; fi'
   artifacts:
     paths:
       - $TARGET
+  allow_failure: true
   rules:
     - if: $CI_COMMIT_REF_NAME == 'main'
     - if: $CI_COMMIT_TAG
@@ -115,7 +124,7 @@ docker_build:
   retry: 2
   needs:
     - release-linux
-  cache: []
+  cache: [ ]
   rules:
     - if: $CI_COMMIT_REF_NAME == 'main'
 
@@ -128,6 +137,6 @@ docker_build-prod:
   retry: 2
   needs:
     - release-linux
-  cache: []
+  cache: [ ]
   rules:
     - if: $CI_COMMIT_TAG
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 2362667252c6c16fbacfb184456ee613af573287..28a7a166a2ec2f3bb8e38aba023aaaf07d5e3997 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "aho-corasick"
-version = "1.1.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
 dependencies = [
  "memchr",
 ]
@@ -52,9 +52,9 @@ dependencies = [
 
 [[package]]
 name = "arc-swap"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
+checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f"
 
 [[package]]
 name = "ascii"
@@ -64,13 +64,13 @@ checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
 
 [[package]]
 name = "async-trait"
-version = "0.1.77"
+version = "0.1.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
+checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -79,7 +79,7 @@ version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 dependencies = [
- "hermit-abi 0.1.19",
+ "hermit-abi",
  "libc",
  "winapi",
 ]
@@ -92,9 +92,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
-version = "0.3.69"
+version = "0.3.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+checksum = "95d8e92cac0961e91dbd517496b00f7e9b92363dbe6d42c3198268323798860c"
 dependencies = [
  "addr2line",
  "cc",
@@ -125,9 +125,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.2"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
 
 [[package]]
 name = "block"
@@ -146,9 +146,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.15.3"
+version = "3.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
+checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
 
 [[package]]
 name = "byteorder"
@@ -164,10 +164,11 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
 
 [[package]]
 name = "cc"
-version = "1.0.88"
+version = "1.0.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
+checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
 dependencies = [
+ "jobserver",
  "libc",
 ]
 
@@ -179,9 +180,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.34"
+version = "0.4.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
+checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -189,7 +190,7 @@ dependencies = [
  "num-traits",
  "serde",
  "wasm-bindgen",
- "windows-targets 0.52.3",
+ "windows-targets 0.52.4",
 ]
 
 [[package]]
@@ -260,9 +261,9 @@ dependencies = [
 
 [[package]]
 name = "cron"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ff76b51e4c068c52bfd2866e1567bee7c567ae8f24ada09fd4307019e25eab7"
+checksum = "6f8c3e73077b4b4a6ab1ea5047c37c57aee77657bc8ecd6f29b0af082d0b0c07"
 dependencies = [
  "chrono",
  "nom",
@@ -324,7 +325,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim 0.10.0",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -346,7 +347,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
 dependencies = [
  "darling_core 0.20.8",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -401,7 +402,7 @@ dependencies = [
  "darling 0.20.8",
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -421,7 +422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
 dependencies = [
  "derive_builder_core 0.20.0",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -455,7 +456,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -661,11 +662,11 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
 [[package]]
 name = "git2"
-version = "0.18.2"
+version = "0.18.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd"
+checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "libc",
  "libgit2-sys",
  "log",
@@ -676,9 +677,9 @@ dependencies = [
 
 [[package]]
 name = "gitlab"
-version = "0.1609.0"
+version = "0.1609.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5640bb3c6ee4d4e53188329d2d424ea6d546b188b92e1cfe3785fcda3801b4c4"
+checksum = "6a6a894189e53db36e7bbbab410edfca301ee6414e4b83bdcd2a9a8e42190194"
 dependencies = [
  "async-trait",
  "base64 0.13.1",
@@ -786,9 +787,9 @@ dependencies = [
 
 [[package]]
 name = "h2"
-version = "0.3.24"
+version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
+checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb"
 dependencies = [
  "bytes",
  "fnv",
@@ -833,17 +834,11 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "hermit-abi"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60"
-
 [[package]]
 name = "http"
-version = "0.2.11"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
+checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
 dependencies = [
  "bytes",
  "fnv",
@@ -927,7 +922,7 @@ dependencies = [
  "serde",
  "serde_derive",
  "thiserror",
- "toml 0.8.10",
+ "toml 0.8.12",
  "unic-langid",
 ]
 
@@ -970,7 +965,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim 0.10.0",
- "syn 2.0.51",
+ "syn 2.0.53",
  "unic-langid",
 ]
 
@@ -984,7 +979,7 @@ dependencies = [
  "i18n-config",
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -1028,9 +1023,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.2.3"
+version = "2.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
+checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -1098,11 +1093,20 @@ version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 
+[[package]]
+name = "jobserver"
+version = "0.1.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "js-sys"
-version = "0.3.68"
+version = "0.3.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -1149,9 +1153,9 @@ dependencies = [
 
 [[package]]
 name = "libz-sys"
-version = "1.1.15"
+version = "1.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6"
+checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9"
 dependencies = [
  "cc",
  "libc",
@@ -1190,9 +1194,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.20"
+version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
 
 [[package]]
 name = "malloc_buf"
@@ -1232,9 +1236,9 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.8.10"
+version = "0.8.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
 dependencies = [
  "libc",
  "wasi",
@@ -1260,16 +1264,6 @@ dependencies = [
  "autocfg",
 ]
 
-[[package]]
-name = "num_cpus"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
-dependencies = [
- "hermit-abi 0.3.8",
- "libc",
-]
-
 [[package]]
 name = "number_prefix"
 version = "0.4.0"
@@ -1326,7 +1320,7 @@ version = "0.10.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cfg-if",
  "foreign-types",
  "libc",
@@ -1343,7 +1337,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -1453,9 +1447,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.78"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
 dependencies = [
  "unicode-ident",
 ]
@@ -1492,9 +1486,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.5"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
+checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1509,9 +1503,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
 [[package]]
 name = "reqwest"
-version = "0.11.24"
+version = "0.11.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
+checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
 dependencies = [
  "base64 0.21.7",
  "bytes",
@@ -1565,9 +1559,9 @@ dependencies = [
 
 [[package]]
 name = "rust-embed"
-version = "8.2.0"
+version = "8.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a82c0bbc10308ed323529fd3c1dce8badda635aa319a5ff0e6466f33b8101e3f"
+checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745"
 dependencies = [
  "rust-embed-impl",
  "rust-embed-utils",
@@ -1576,22 +1570,22 @@ dependencies = [
 
 [[package]]
 name = "rust-embed-impl"
-version = "8.2.0"
+version = "8.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6227c01b1783cdfee1bcf844eb44594cd16ec71c35305bf1c9fb5aade2735e16"
+checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8"
 dependencies = [
  "proc-macro2",
  "quote",
  "rust-embed-utils",
- "syn 2.0.51",
+ "syn 2.0.53",
  "walkdir",
 ]
 
 [[package]]
 name = "rust-embed-utils"
-version = "8.2.0"
+version = "8.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cb0a25bfbb2d4b4402179c2cf030387d9990857ce08a32592c6238db9fa8665"
+checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581"
 dependencies = [
  "sha2",
  "walkdir",
@@ -1611,11 +1605,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
 [[package]]
 name = "rustix"
-version = "0.38.31"
+version = "0.38.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
+checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -1716,7 +1710,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -1779,9 +1773,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.13.1"
+version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "socket2"
@@ -1848,9 +1842,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.51"
+version = "2.0.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c"
+checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1886,9 +1880,9 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.10.0"
+version = "3.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
+checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
 dependencies = [
  "cfg-if",
  "fastrand",
@@ -1907,22 +1901,22 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.57"
+version = "1.0.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
+checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.57"
+version = "1.0.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
 ]
 
 [[package]]
@@ -1959,7 +1953,6 @@ dependencies = [
  "bytes",
  "libc",
  "mio",
- "num_cpus",
  "pin-project-lite",
  "socket2",
  "windows-sys 0.48.0",
@@ -2000,9 +1993,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.8.10"
+version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290"
+checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2021,9 +2014,9 @@ dependencies = [
 
 [[package]]
 name = "toml_edit"
-version = "0.22.6"
+version = "0.22.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
+checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
 dependencies = [
  "indexmap",
  "serde",
@@ -2182,9 +2175,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 
 [[package]]
 name = "walkdir"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
 dependencies = [
  "same-file",
  "winapi-util",
@@ -2207,9 +2200,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.91"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -2217,24 +2210,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.91"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.41"
+version = "0.4.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
+checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -2244,9 +2237,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.91"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -2254,28 +2247,28 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.91"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.51",
+ "syn 2.0.53",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.91"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
 
 [[package]]
 name = "web-sys"
-version = "0.3.68"
+version = "0.3.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
+checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -2324,7 +2317,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.52.3",
+ "windows-targets 0.52.4",
 ]
 
 [[package]]
@@ -2342,7 +2335,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.3",
+ "windows-targets 0.52.4",
 ]
 
 [[package]]
@@ -2362,17 +2355,17 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
+checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.3",
- "windows_aarch64_msvc 0.52.3",
- "windows_i686_gnu 0.52.3",
- "windows_i686_msvc 0.52.3",
- "windows_x86_64_gnu 0.52.3",
- "windows_x86_64_gnullvm 0.52.3",
- "windows_x86_64_msvc 0.52.3",
+ "windows_aarch64_gnullvm 0.52.4",
+ "windows_aarch64_msvc 0.52.4",
+ "windows_i686_gnu 0.52.4",
+ "windows_i686_msvc 0.52.4",
+ "windows_x86_64_gnu 0.52.4",
+ "windows_x86_64_gnullvm 0.52.4",
+ "windows_x86_64_msvc 0.52.4",
 ]
 
 [[package]]
@@ -2383,9 +2376,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
+checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -2395,9 +2388,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
+checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -2407,9 +2400,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
+checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -2419,9 +2412,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
+checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -2431,9 +2424,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
+checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -2443,9 +2436,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
+checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -2455,15 +2448,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.3"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
+checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
 
 [[package]]
 name = "winnow"
-version = "0.6.2"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178"
+checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
 dependencies = [
  "memchr",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 48e1c8ef617c5783761d32a9e18050369adb3a78..9e244bbd84515c1be10cc844bf92231203014d71 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,8 +13,8 @@ chrono = "0.4.34"
 console = "0.15.2"
 derive_builder = "0.20.0"
 dialoguer = "0.11.0"
-git2 = { version="0.18.1", features = ["vendored-libgit2"] }
-gitlab = "0.1609.0"
+git2 = { version = "0.18.1", features = ["vendored-libgit2"] }
+gitlab = "0.1609.2"
 # Erreurs au passage de la version 0.13.0
 graphql_client = "~0.11.0"
 human_bytes = "0.4.3"
@@ -27,4 +27,3 @@ rust-embed = "8.0.0"
 serde = "1.0.190"
 serde_json = "1.0.107"
 structopt = "0.3.26"
-
diff --git a/i18n/en-GB/gitlab_project_doctor.ftl b/i18n/en-GB/gitlab_project_doctor.ftl
index bac24ce8c4f8a666935bf215ac272821967c2752..d9c58250cef68adc4ae32da3683b44c4286a7986 100644
--- a/i18n/en-GB/gitlab_project_doctor.ftl
+++ b/i18n/en-GB/gitlab_project_doctor.ftl
@@ -1,42 +1,48 @@
+ask-age-days = From which age in days ?
+ask-delete-files = Delete obsolete files ?
+ask-delete-pipelines = Delete old pipelines ?
+conf-analysing = Analysis of package configuration
+conf-fix = Fix this : {$url}
 connecting-to-gitlab = Connecting to Gitlab
-gitlab-repo = Gitlab repository : {$repo}
-error-gl-token = GL_TOKEN environment variable must contain a valid Gitlab private token
-error-not-gitlab-repo = This URL is not a gitlab repository
-error-not-git-repo = This dir is not a Git repository
+container-analysing = Analysis of container registry
+container-policy-disabled = The option "Clean up image tags" is disabled.
+container-policy-enabled = The option "Clean up image tags" is enabled
+container-report = {$image_count} images in container registry. {$old_image_count} are older than {$nb_days} days
+container-summary = Container registry size: {$registry_size}
+duplicate-assets-option-error = Cannot get the number of duplicate assets to keep option
+duplicate-assets-option-onepackage = The number of duplicate assets to keep is 1
+duplicate-assets-option-warn = The number of duplicate assets to keep is NOT 1
+error = Error:
+error-gl-token = No token found. Please set the GL_TOKEN variable or the command -t argument with a valid private token or run the program in a Gilab CI job
+error-insufficient-privileges = Your token has insufficient privileges
 error-no-gitlab-remote = This dir does not contain a gitlab remote
-size-storage = Storage size:
-size-git-repo = Git repository size:
-size-artifacts = Artifact jobs size:
-size-packages = Package registry size:
+error-not-git-repo = This dir is not a Git repository
+error-not-gitlab-repo = This URL is not a gitlab repository
+gitlab-repo = Gitlab repository : {$repo}
+help-analysis = Analysis mode : Output a detailed analysis in JSON format. No cleaning.
+help-batch = Batch mode : No questions, no progress bar, ideal for CI environment
+help-days = Number of days from which an element is considered "old", 30 by default
+help-git-path = Analyze the project from a local path of a Git repository. Ignored if url option is specified
+help-token = (Not recommended) Gitlab private token for authentication, maintainer role is needed for objects deletion. It is strongly advised to use the environment variable GL_TOKEN instead of this argument, for security reasons.
+help-url = Analyze the project from the URL of Gitlab repository
+no-cicd = No CI/CD configured for this project.
+no-permission-jobanalysis = The token has no permission for job analysis.
 package-analysing = Analysis of packages
-no-cicd = No CI/CD configured for this project
-error = Error:
-package-report = {$nb_packages} packages. {$nb_files} files are obsolete ({$size})
+package-clean-report = Deleted {$nb_packages} packages, {$size} saved.
 package-deleting = Deleting obsolete packages files
 package-no-deletion = No package has been deleted
-error-insufficient-privileges = Your token has insufficient privileges
-package-clean-report = Deleted {$nb_packages} packages, {$size} saved.
+package-report = {$nb_packages} packages. {$nb_files} files are obsolete ({$size})
 pipeline-analysing = Analysis of pipelines
-pipeline-report = {$total_pipelines} pipelines. {$old_pipelines} pipelines are older than {$nb_days} days
+pipeline-clean-report = Deleted {$nb_pipelines} pipelines.
+pipeline-clean-report-size = Deleted {$nb_pipelines} pipelines, {$size} saved.
 pipeline-deleting = Deleting old pipelines
-pipeline-clean-report = Deleted {$nb_pipelines} pipelines, {$size} saved.
 pipeline-last-notdeleted = Latest pipeline is not deleted.
 pipeline-no-deletion = No pipeline has been deleted
-ask-delete-pipelines = Delete old pipelines ?
-ask-delete-files = Delete obsolete files ?
-ask-age-days = From which age in days ?
-help-url = Analyze the project from the URL of Gitlab repository
-help-git-path = Analyze the project from a local path of a Git repository. Ignored if url option is specified
-help-batch = Batch mode : No questions, no progress bar, ideal for CI environment
-help-days = Number of days from which an element is considered "old", 30 by default
-help-analysis = Analysis mode : Output a detailed analysis in JSON format. No cleaning.
-container-policy-enabled = The option "Clean up image tags" is enabled
-container-policy-disabled = The option "Clean up image tags" is disabled.
-conf-analysing = Analysis of package configuration
-duplicate-assets-option-onepackage = The number of duplicate assets to keep is 1
-duplicate-assets-option-warn = The number of duplicate assets to keep is NOT 1
-duplicate-assets-option-error = Cannot get the number of duplicate assets to keep option
-conf-fix = Fix this : {$url}
-container-analysing = Analysis of container registry
-container-report = {$image_count} images in container registry. {$old_image_count} are older than {$nb_days} days
-container-summary = Container registry size: {$registry_size}
\ No newline at end of file
+pipeline-report = {$total_pipelines} pipelines. {$old_pipelines} pipelines are older than {$nb_days} days
+size-artifacts = Artifact jobs size:
+size-git-repo = Git repository size:
+size-packages = Package registry size:
+size-storage = Storage size:
+token-argument = Using the private token from the command argument
+token-environment = Using the private token provided in GL_TOKEN variable
+token-job = Using the job token from CI_JOB_TOKEN. Warning ! This token provides less permissions than private token !
diff --git a/i18n/fr-FR/gitlab_project_doctor.ftl b/i18n/fr-FR/gitlab_project_doctor.ftl
index 98d4720f5057f4e26de43914d4c1499661559ae3..43999a624d6d02dfd432d9f40b129839e92b9626 100644
--- a/i18n/fr-FR/gitlab_project_doctor.ftl
+++ b/i18n/fr-FR/gitlab_project_doctor.ftl
@@ -1,42 +1,49 @@
+ask-age-days = Datant de plus de combien de jours ?
+ask-delete-files = Supprimer fichiers obsolètes ?
+ask-delete-pipelines = Supprimer anciens pipelines ?
+conf-analysing = Analyse de la configuration des packages
+conf-fix = Pour corriger : {$url}
 connecting-to-gitlab = Connexion à Gitlab
-gitlab-repo = Dépôt Gitlab : {$repo}
-error-gl-token = GL_TOKEN environment variable must contain a valid Gitlab private tokenerror-not-gitlab-repo = "This URL is not a gitlab repository"
-error-not-git-repo = "Ce dossier n'est pas un dépôt Git"
+container-analysing = Analyse du container registry
+container-policy-disabled = L'option "Clean up image tags" est désactivée.
+container-policy-enabled = L'option "Clean up image tags" est activée
+container-report = {$image_count} images dans le container registry. {$old_image_count} datent de plus de {$nb_days} jours
+container-summary = Taille du container registry : {$registry_size}
+duplicate-assets-option-error = Cannot get the number of duplicate assets to keep option
+duplicate-assets-option-onepackage = L'option "The number of duplicate assets to keep" vaut 1
+duplicate-assets-option-warn = L'option "The number of duplicate assets to keep" ne vaut PAS 1
+error = Erreur :
+error-gl-token = Aucun token trouvé. Veuillez renseigner la variable GL_TOKEN contenant un token privée valide ou bien exécutez le programme dans un job Gilab CI.
+error-insufficient-privileges = Le token utilisé n'a pas les permissions requises
 error-no-gitlab-remote = Ce dépôt Git n'est pas lié à un dépôt Gitlab
-size-storage = Taille globale :
-size-git-repo = Taille du dépôt Git :
-size-artifacts = Taille des artefacts de jobs :
-size-packages = Taille du package registry :
-size-packages = Package registry size:
+error-not-git-repo = "Ce dossier n'est pas un dépôt Git"
+error-not-gitlab-repo = "This URL is not a gitlab repository"
+gitlab-repo = Dépôt Gitlab : {$repo}
+help-analysis = Mode analyse : Analyse détaillé au format JSON. Pas de nettoyage
+help-batch = Mode batch : pas de questions, pas de barre de progression, idéal pour du CI
+help-days = Nombre de jours d'ancienneté à partir duquel un élément est considéré "ancien"
+help-git-path = Analyse du projet à partir d'un chemin vers un dépôt Git. Ignoré si l'option url est spécifiée
+help-token = (Non recommandé) Token privé Gitlab d'authentification, avec le rôle maintainer nécessaire pour la suppression. Il est conseillé d'utiliser la variable GL_TOKEN à la place de cet argument, pour des raisons de sécurité.
+help-url = Analyse du projet à partir d'une URL Gitlab
+no-cicd = Aucun CI/CD configuré pour ce projet.
+no-permission-jobanalysis = Le token n'a pas la permission d'analyser les jobs.
 package-analysing = Analyse du package registry
-no-cicd = Aucun CI/CD configuré pour ce projet
-error = Erreur :
-package-report = {$nb_packages} packages. {$nb_files} fichiers sont obsolètes ({$size})
+package-clean-report = {$nb_packages} packages supprimés, {$size} récupérés.
 package-deleting = Suppression des fichiers de package obsolètes
 package-no-deletion = Aucun package n'a été supprimé
-error-insufficient-privileges = Le token utilisé n'a pas les permissions requises
-package-clean-report = {$nb_packages} packages supprimés, {$size} récupérés.
+package-report = {$nb_packages} packages. {$nb_files} fichiers sont obsolètes ({$size})
 pipeline-analysing = Analyse des pipelines
-pipeline-report = {$total_pipelines} pipelines. {$old_pipelines} pipelines datent de plus de {$nb_days} jours
+pipeline-clean-report = {$nb_pipelines} pipelines supprimés.
+pipeline-clean-report-size = {$nb_pipelines} pipelines supprimés, {$size} économisés.
 pipeline-deleting = Suppression des anciens pipelines
-pipeline-clean-report = {$nb_pipelines} pipelines supprimés, {$size} économisés.
 pipeline-last-notdeleted = Le dernier pipeline n'est pas supprimé.
 pipeline-no-deletion = Aucun pipeline n'a été supprimé.
-ask-delete-pipelines = Supprimer anciens pipelines ?
-ask-delete-files = Supprimer fichiers obsolètes ?
-ask-age-days = Datant de plus de combien de jours ?
-help-url = Analyse du projet à partir d'une URL Gitlab
-help-git-path = Analyse du projet à partir d'un chemin vers un dépôt Git. Ignoré si l'option url est spécifiée
-help-batch = Mode batch : pas de questions, pas de barre de progression, idéal pour du CI
-help-days = Nombre de jours d'ancienneté à partir duquel un élément est considéré "ancien"
-help-analysis = Mode analyse : Analyse détaillé au format JSON. Pas de nettoyage
-container-policy-enabled = L'option "Clean up image tags" est activée
-container-policy-disabled = L'option "Clean up image tags" est désactivée.
-conf-analysing = Analyse de la configuration des packages
-duplicate-assets-option-onepackage = L'option "The number of duplicate assets to keep" vaut 1
-duplicate-assets-option-warn = L'option "The number of duplicate assets to keep" ne vaut PAS 1
-duplicate-assets-option-error = Cannot get the number of duplicate assets to keep option
-conf-fix = Pour corriger : {$url}
-container-analysing = Analyse du container registry
-container-report = {$image_count} images dans le container registry. {$old_image_count} datent de plus de {$nb_days} jours
-container-summary = Taille du container registry : {$registry_size}
\ No newline at end of file
+pipeline-report = {$total_pipelines} pipelines. {$old_pipelines} pipelines datent de plus de {$nb_days} jours
+size-artifacts = Taille des artefacts de jobs :
+size-git-repo = Taille du dépôt Git :
+size-packages = Package registry size:
+size-packages = Taille du package registry :
+size-storage = Taille globale :
+token-argument = Utilisation du token privé fourni en argument de commande
+token-environment = Utilisation du token privé founi par la variable GL_TOKEN
+token-job = Utilisation du token de job CI_JOB_TOKEN. Attention ! Ce token offre moins de permissions qu'un token privé
diff --git a/src/cli.rs b/src/cli.rs
index 8a68eccda18866e1b7cb2eb0fc5c0f8d72c1145f..24816f0f80a93c0e47b597608b019ee7954e8da6 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,15 +1,16 @@
-use atty::Stream;
 use std::fmt::Write;
 use std::time::Duration;
 use std::{panic, process};
 
-use crate::{fl, ReportPending, ReportStatus, Reportable};
+use atty::Stream;
 use console::style;
 use dialoguer::{Confirm, Input};
 use indicatif::{ProgressBar, ProgressStyle};
 use lazy_static::lazy_static;
 use structopt::StructOpt;
 
+use crate::{fl, ReportPending, ReportStatus, Reportable};
+
 pub fn fatal_if_none<T>(result: Option<T>, msg: &str) -> T {
     match result {
         Some(x) => x,
@@ -23,21 +24,24 @@ lazy_static! {
     static ref HELP_URL: String = fl!("help-url");
     static ref HELP_GIT_PATH: String = fl!("help-git-path");
     static ref HELP_BATCH_MODE: String = fl!("help-batch");
+    static ref HELP_TOKEN: String = fl!("help-token");
     static ref HELP_DAYS: String = fl!("help-days");
     static ref HELP_ANALYSIS: String = fl!("help-analysis");
 }
 
 #[derive(StructOpt)]
 pub struct Args {
-    #[structopt(name = "url", long, help = &HELP_URL)]
+    #[structopt(name = "url", long, help = & HELP_URL)]
     pub url: Option<String>,
-    #[structopt(name = "git_path", required_unless = "url", help = &HELP_GIT_PATH)]
+    #[structopt(long = "token", short = "t", help = & HELP_TOKEN)]
+    pub token: Option<String>,
+    #[structopt(name = "git_path", required_unless = "url", help = & HELP_GIT_PATH)]
     pub git_path: Option<String>,
-    #[structopt(long = "batch", short = "b", help = &HELP_BATCH_MODE)]
+    #[structopt(long = "batch", short = "b", help = & HELP_BATCH_MODE)]
     pub batch_mode: bool,
-    #[structopt(long = "days", short = "d", default_value = "30", help = &HELP_DAYS)]
+    #[structopt(long = "days", short = "d", default_value = "30", help = & HELP_DAYS)]
     pub days: usize,
-    #[structopt(long = "analysis", short = "a", help = &HELP_ANALYSIS)]
+    #[structopt(long = "analysis", short = "a", help = & HELP_ANALYSIS)]
     pub analysis_mode: bool,
 }
 
diff --git a/src/diagnosis/container_analysis.rs b/src/diagnosis/container_analysis.rs
index ba95504bef3d1ba2c98eb951848fe68f37642071..a546619ac2f372219cd9947bf7dff2db547503aa 100644
--- a/src/diagnosis/container_analysis.rs
+++ b/src/diagnosis/container_analysis.rs
@@ -1,4 +1,4 @@
-use chrono::{DateTime, Duration, Local};
+use chrono::{DateTime, Local, TimeDelta};
 use gitlab::api::{Pagination, Query};
 use gitlab::Gitlab;
 use human_bytes::human_bytes;
@@ -120,17 +120,13 @@ impl ReportJob for ContainerAnalysisJob {
                     gitlab::api::paged(endpoint, Pagination::All).query(&self.gitlab);
                 match query {
                     Err(e) => self.into_report(
-                        vec![ReportStatus::ERROR(format!(
-                            "{} {}",
-                            fl!("error"),
-                            e.to_string()
-                        ))],
+                        vec![ReportStatus::ERROR(format!("{} {}", fl!("error"), e))],
                         vec![],
                     ),
                     Ok(containers) => {
                         let container_repos = self.get_detailed_repo(&containers);
                         let days = self.days;
-                        let ref_date = Local::now() - Duration::days(days as i64);
+                        let ref_date = Local::now() - TimeDelta::try_days(days as i64).unwrap();
                         let image_count: usize =
                             container_repos.iter().map(|cr| cr.tags.len()).sum();
                         let registry_size: u64 = container_repos
diff --git a/src/diagnosis/gitlab_connection.rs b/src/diagnosis/gitlab_connection.rs
index 06affbaec984977f61a5a25b5a54a5887e119620..3a436b30eff6639f6e363e50f038e70f468d8026 100644
--- a/src/diagnosis/gitlab_connection.rs
+++ b/src/diagnosis/gitlab_connection.rs
@@ -16,6 +16,14 @@ use crate::fl;
 
 type Result<T> = std::result::Result<T, Box<dyn error::Error>>;
 
+// An enum of a Gitlab token type : private or job token
+#[derive(Debug, Deserialize, Clone)]
+pub enum GitlabToken {
+    PrivateTokenFromArg(String),
+    PrivateTokenFromEnv(String),
+    JobToken(String),
+}
+
 #[derive(Debug, Deserialize, Clone, Serialize)]
 pub struct Statistics {
     pub commit_count: u64,
@@ -24,6 +32,7 @@ pub struct Statistics {
     pub job_artifacts_size: u64,
     pub packages_size: u64,
 }
+
 #[derive(Debug, Deserialize, Clone)]
 pub struct ContainerExpirationPolicy {
     pub enabled: bool,
@@ -33,7 +42,7 @@ pub struct ContainerExpirationPolicy {
 pub struct Project {
     pub id: u64,
     pub name: String,
-    pub statistics: Statistics,
+    pub statistics: Option<Statistics>,
     pub jobs_enabled: bool,
     pub container_registry_enabled: bool,
     pub container_expiration_policy: Option<ContainerExpirationPolicy>,
@@ -46,6 +55,7 @@ pub struct GitlabRepository {
     pub gitlab: Gitlab,
     pub project: Project,
     pub repo: Option<Repository>,
+    pub token: GitlabToken,
 }
 
 pub struct ConnectionReport {
@@ -54,8 +64,8 @@ pub struct ConnectionReport {
 }
 
 pub enum ConnectionJob {
-    FromUrl(String),
-    FromPath(String),
+    FromUrl(String, Option<String>),
+    FromPath(String, Option<String>),
 }
 
 impl ReportJob for ConnectionJob {
@@ -67,8 +77,10 @@ impl ReportJob for ConnectionJob {
             job: {
                 std::thread::spawn(|| {
                     ConnectionJob::_to_report_status(match self {
-                        ConnectionJob::FromUrl(url) => ConnectionJob::_from_url(&url),
-                        ConnectionJob::FromPath(path) => ConnectionJob::_from_git_path(&path),
+                        ConnectionJob::FromUrl(url, token) => ConnectionJob::_from_url(&url, token),
+                        ConnectionJob::FromPath(path, token) => {
+                            ConnectionJob::_from_git_path(&path, token)
+                        }
                     })
                 })
             },
@@ -87,24 +99,45 @@ impl Reportable for ConnectionReport {
 impl ConnectionJob {
     fn _to_report_status(result: Result<GitlabRepository>) -> ConnectionReport {
         match result {
-            Ok(gitlab) => ConnectionReport {
-                report_status: vec![
-                    ReportStatus::OK(fl!("gitlab-repo", repo = gitlab.url.as_str())),
-                    _report_global_storage(&gitlab.project),
-                    _report_repo_storage(&gitlab.project),
-                    _report_artifact_storage(&gitlab.project),
-                    _report_package_storage(&gitlab.project),
-                ],
-                data: Some(gitlab),
-            },
+            Ok(gitlab) => {
+                let token_status = match gitlab.token {
+                    GitlabToken::PrivateTokenFromArg(_) => ReportStatus::OK(fl!("token-argument")),
+                    GitlabToken::PrivateTokenFromEnv(_) => {
+                        ReportStatus::OK(fl!("token-environment"))
+                    }
+                    GitlabToken::JobToken(_) => ReportStatus::WARNING(fl!("token-job")),
+                };
+                let report_status = if let Some(stats) = &gitlab.project.statistics {
+                    vec![
+                        token_status,
+                        ReportStatus::OK(fl!("gitlab-repo", repo = gitlab.url.as_str())),
+                        _report_global_storage(stats),
+                        _report_repo_storage(stats),
+                        _report_artifact_storage(stats),
+                        _report_package_storage(stats),
+                    ]
+                } else {
+                    vec![
+                        token_status,
+                        ReportStatus::OK(fl!("gitlab-repo", repo = gitlab.url.as_str())),
+                    ]
+                };
+                ConnectionReport {
+                    report_status,
+                    data: Some(gitlab),
+                }
+            }
             Err(e) => ConnectionReport {
                 data: None,
                 report_status: vec![ReportStatus::ERROR(format!("{}", e))],
             },
         }
     }
-    fn _gitlab_project(server: &str, path: &str) -> Result<(Gitlab, Project)> {
-        let token = env::var("GL_TOKEN").map_err(|_| fl!("error-gl-token"))?;
+    fn _gitlab_project_private_token(
+        server: &str,
+        path: &str,
+        token: &str,
+    ) -> Result<(Gitlab, Project)> {
         let client = Gitlab::new(server, token)?;
         let endpoint = projects::Project::builder()
             .project(path)
@@ -116,75 +149,108 @@ impl ConnectionJob {
         Ok((client, project))
     }
 
-    fn _from_url(url: &str) -> Result<GitlabRepository> {
+    fn _gitlab_project_job_token(server: &str, token: &str) -> Result<(Gitlab, Project)> {
+        let client = Gitlab::new_job_token(server, token)?;
+        let project = Project {
+            id: env::var("CI_PROJECT_ID")?.parse()?,
+            name: env::var("CI_PROJECT_NAME")?,
+            statistics: None,
+            jobs_enabled: true,
+            container_expiration_policy: None,
+            container_registry_enabled: false, // TODO is there a way to find it out with job token?
+            web_url: env::var("CI_PROJECT_URL")?,
+            path_with_namespace: env::var("CI_PROJECT_PATH")?,
+        };
+        Ok((client, project))
+    }
+    fn _env_token(token: Option<String>) -> Result<GitlabToken> {
+        if let Some(token_value) = token {
+            Ok(GitlabToken::PrivateTokenFromArg(token_value))
+        } else if let Ok(token_value) = env::var("GL_TOKEN") {
+            Ok(GitlabToken::PrivateTokenFromEnv(token_value))
+        } else {
+            Ok(GitlabToken::JobToken(
+                env::var("CI_JOB_TOKEN").map_err(|_| fl!("error-gl-token"))?,
+            ))
+        }
+    }
+
+    fn _gitlab_project(server: &str, path: &str, token: &GitlabToken) -> Result<(Gitlab, Project)> {
+        match token {
+            GitlabToken::PrivateTokenFromArg(token) | GitlabToken::PrivateTokenFromEnv(token) => {
+                Self::_gitlab_project_private_token(server, path, token)
+            }
+            GitlabToken::JobToken(token) => Self::_gitlab_project_job_token(server, token),
+        }
+    }
+
+    fn _from_url(url: &str, token: Option<String>) -> Result<GitlabRepository> {
         let (server, path) = path_from_git_url(url).ok_or_else(|| fl!("error-not-gitlab-repo"))?;
-        let (gitlab, project) = ConnectionJob::_gitlab_project(server, path)?;
+        let used_token = Self::_env_token(token)?;
+        let (gitlab, project) = ConnectionJob::_gitlab_project(server, path, &used_token)?;
         Ok(GitlabRepository {
             url: String::from(path),
             gitlab,
             project,
             repo: None,
+            token: used_token,
         })
     }
 
-    fn _from_git_path(path: &str) -> Result<GitlabRepository> {
+    fn _from_git_path(path: &str, token: Option<String>) -> Result<GitlabRepository> {
         let repo = Repository::open(path).map_err(|_| fl!("error-not-git-repo"))?;
         let (server, url_path) = gitlab_url(&repo).ok_or_else(|| fl!("error-no-gitlab-remote"))?;
-        let (gitlab, project) = ConnectionJob::_gitlab_project(&server, &url_path)?;
+        let used_token = Self::_env_token(token)?;
+        let (gitlab, project) = ConnectionJob::_gitlab_project(&server, &url_path, &used_token)?;
         Ok(GitlabRepository {
             url: url_path,
             gitlab,
             project,
             repo: Some(repo),
+            token: used_token,
         })
     }
 }
 
-fn _report_global_storage(project: &Project) -> ReportStatus {
+fn _report_global_storage(stats: &Statistics) -> ReportStatus {
     let msg = format!(
         "{} {}",
         fl!("size-storage"),
-        human_bytes(project.statistics.storage_size as f64)
+        human_bytes(stats.storage_size as f64)
     );
 
-    warning_if(project.statistics.storage_size > STORAGE_LIMIT, msg)
+    warning_if(stats.storage_size > STORAGE_LIMIT, msg)
 }
 
-fn _report_repo_storage(project: &Project) -> ReportStatus {
+fn _report_repo_storage(stats: &Statistics) -> ReportStatus {
     let msg = format!(
         "{} {} ({} %)",
         fl!("size-git-repo"),
-        human_bytes(project.statistics.repository_size as f64),
-        100 * project.statistics.repository_size / project.statistics.storage_size
+        human_bytes(stats.repository_size as f64),
+        100 * stats.repository_size / stats.storage_size
     );
 
-    warning_if(project.statistics.repository_size > REPO_LIMIT, msg)
+    warning_if(stats.repository_size > REPO_LIMIT, msg)
 }
 
-fn _report_artifact_storage(project: &Project) -> ReportStatus {
+fn _report_artifact_storage(stats: &Statistics) -> ReportStatus {
     let msg = format!(
         "{} {} ({} %)",
         fl!("size-artifacts"),
-        human_bytes(project.statistics.job_artifacts_size as f64),
-        100 * project.statistics.job_artifacts_size / project.statistics.storage_size
+        human_bytes(stats.job_artifacts_size as f64),
+        100 * stats.job_artifacts_size / stats.storage_size
     );
-    warning_if(
-        project.statistics.job_artifacts_size > ARTIFACT_JOBS_LIMIT,
-        msg,
-    )
+    warning_if(stats.job_artifacts_size > ARTIFACT_JOBS_LIMIT, msg)
 }
 
-fn _report_package_storage(project: &Project) -> ReportStatus {
+fn _report_package_storage(stats: &Statistics) -> ReportStatus {
     let msg = format!(
         "{} {} ({} %)",
         fl!("size-packages"),
-        human_bytes(project.statistics.packages_size as f64),
-        100 * project.statistics.packages_size / project.statistics.storage_size
+        human_bytes(stats.packages_size as f64),
+        100 * stats.packages_size / stats.storage_size
     );
-    warning_if(
-        project.statistics.packages_size > PACKAGE_REGISTRY_LIMIT,
-        msg,
-    )
+    warning_if(stats.packages_size > PACKAGE_REGISTRY_LIMIT, msg)
 }
 
 fn gitlab_url(repo: &Repository) -> Option<(String, String)> {
diff --git a/src/diagnosis/job_analysis.rs b/src/diagnosis/job_analysis.rs
index c5a7e2588131d236915ce9ac46a57147e0319ab2..eed9e04469517c4fad818c45b9c9090f8bd6d134 100644
--- a/src/diagnosis/job_analysis.rs
+++ b/src/diagnosis/job_analysis.rs
@@ -1,4 +1,4 @@
-use chrono::{DateTime, Duration, Local};
+use chrono::{DateTime, Local, TimeDelta};
 use gitlab::api::paged;
 use gitlab::api::{projects, Pagination, Query};
 use gitlab::Gitlab;
@@ -7,7 +7,7 @@ use serde::Deserialize;
 
 use crate::diagnosis::gitlab_connection::{GitlabRepository, Project};
 use crate::diagnosis::ReportStatus;
-use crate::{ReportJob, ReportPending, Reportable};
+use crate::{fl, ReportJob, ReportPending, Reportable};
 
 #[derive(Debug, Deserialize)]
 pub struct Artifact {
@@ -38,6 +38,16 @@ impl Reportable for JobAnalysisReport {
     }
 }
 
+impl JobAnalysisReport {
+    pub fn simple(status: ReportStatus) -> JobAnalysisReport {
+        JobAnalysisReport {
+            gitlab_jobs: vec![],
+            report_status: vec![status],
+            savable_bytes: 0,
+        }
+    }
+}
+
 impl ReportJob for JobAnalysisJob {
     type Diagnosis = JobAnalysisReport;
 
@@ -47,27 +57,25 @@ impl ReportJob for JobAnalysisJob {
             job: {
                 std::thread::spawn(move || {
                     if !self.project.jobs_enabled {
-                        return JobAnalysisReport {
-                            report_status: vec![ReportStatus::NA(
-                                "No CI/CD configured on this project".to_string(),
-                            )],
-                            gitlab_jobs: vec![],
-                            savable_bytes: 0,
-                        };
+                        return JobAnalysisReport::simple(ReportStatus::NA(fl!("no-cicd")));
                     }
                     let endpoint = projects::jobs::Jobs::builder()
                         .project(self.project.id)
                         .build()
                         .unwrap();
-                    let jobs: Vec<GitlabJob> = paged(endpoint, Pagination::All)
-                        .query(&self.gitlab)
-                        .unwrap();
-                    let (report, bytes_savable) = self._number_jobs(&jobs);
-                    JobAnalysisReport {
-                        report_status: vec![report],
-                        gitlab_jobs: jobs,
-                        savable_bytes: bytes_savable,
-                    }
+                    paged(endpoint, Pagination::All).query(&self.gitlab).map_or(
+                        JobAnalysisReport::simple(ReportStatus::NA(fl!(
+                            "no-permission-jobanalysis"
+                        ))),
+                        |jobs| {
+                            let (report, bytes_savable) = self._number_jobs(&jobs);
+                            JobAnalysisReport {
+                                report_status: vec![report],
+                                gitlab_jobs: jobs,
+                                savable_bytes: bytes_savable,
+                            }
+                        },
+                    )
                 })
             },
             progress: None,
@@ -86,7 +94,7 @@ impl JobAnalysisJob {
     }
 
     fn _number_jobs(&self, jobs: &[GitlabJob]) -> (ReportStatus, u64) {
-        let ref_date = Local::now() - Duration::days(self.days as i64);
+        let ref_date = Local::now() - TimeDelta::try_days(self.days as i64).unwrap();
         let mut old_count: usize = 0;
         let mut old_size: u64 = 0;
         for job in jobs.iter() {
diff --git a/src/diagnosis/package_analysis.rs b/src/diagnosis/package_analysis.rs
index 6f8073fc4c8d6add51de8706710543f4df7eabe6..f1152f1050a64fd80a342c811afae57dd04859be 100644
--- a/src/diagnosis/package_analysis.rs
+++ b/src/diagnosis/package_analysis.rs
@@ -99,11 +99,9 @@ impl ReportJob for PackageAnalysisJob {
                 let query: Result<Vec<GitlabPackage>, _> =
                     gitlab::api::paged(endpoint, Pagination::All).query(&self.gitlab);
                 match query {
-                    Err(e) => self.default_report(ReportStatus::ERROR(format!(
-                        "{} {}",
-                        fl!("error"),
-                        e.to_string()
-                    ))),
+                    Err(e) => {
+                        self.default_report(ReportStatus::ERROR(format!("{} {}", fl!("error"), e)))
+                    }
                     Ok(mut packages) => {
                         packages.sort_by(|a, b| b.created_at.partial_cmp(&a.created_at).unwrap());
                         let mut savable_bytes = 0;
@@ -205,7 +203,7 @@ fn _get_extension(file_name: &str) -> &str {
 
 #[cfg(test)]
 mod tests {
-    use chrono::Duration;
+    use chrono::TimeDelta;
 
     use super::*;
 
@@ -216,36 +214,36 @@ mod tests {
             id: 42,
             name: "generic".to_string(),
             package_type: "".to_string(),
-            created_at: Local::now() - Duration::days(30),
+            created_at: Local::now() - TimeDelta::try_days(30).unwrap(),
         };
         let files = vec![
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(4),
+                created_at: Local::now() - TimeDelta::try_days(4).unwrap(),
                 file_name: "abc.txt".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 54,
-                created_at: Local::now() - Duration::days(5),
+                created_at: Local::now() - TimeDelta::try_days(5).unwrap(),
                 file_name: "abc.txt".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(6),
+                created_at: Local::now() - TimeDelta::try_days(6).unwrap(),
                 file_name: "zyx.txt".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 56,
-                created_at: Local::now() - Duration::days(7),
+                created_at: Local::now() - TimeDelta::try_days(7).unwrap(),
                 file_name: "abc.txt".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(8),
+                created_at: Local::now() - TimeDelta::try_days(8).unwrap(),
                 file_name: "zyx.txt".to_string(),
                 size: 13,
             },
@@ -265,7 +263,7 @@ mod tests {
             id: 42,
             name: "my-generic".to_string(),
             package_type: "generic".to_string(),
-            created_at: Local::now() - Duration::days(30),
+            created_at: Local::now() - TimeDelta::try_days(30).unwrap(),
         };
         let files = vec![];
 
@@ -283,42 +281,42 @@ mod tests {
             id: 42,
             name: "my-app".to_string(),
             package_type: "maven".to_string(),
-            created_at: Local::now() - Duration::days(30),
+            created_at: Local::now() - TimeDelta::try_days(30).unwrap(),
         };
         let files = vec![
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(4),
+                created_at: Local::now() - TimeDelta::try_days(4).unwrap(),
                 file_name: "my-app-1.5-20181107.152550-1.jar".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 54,
-                created_at: Local::now() - Duration::days(4),
+                created_at: Local::now() - TimeDelta::try_days(4).unwrap(),
                 file_name: "my-app-1.5-20181107.152550-1.pom".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(4),
+                created_at: Local::now() - TimeDelta::try_days(4).unwrap(),
                 file_name: "maven-metadata.xml".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(5),
+                created_at: Local::now() - TimeDelta::try_days(5).unwrap(),
                 file_name: "my-app-1.5-20181007.142550-1.jar".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 54,
-                created_at: Local::now() - Duration::days(5),
+                created_at: Local::now() - TimeDelta::try_days(5).unwrap(),
                 file_name: "my-app-1.5-20181007.142550-1.pom".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(5),
+                created_at: Local::now() - TimeDelta::try_days(5).unwrap(),
                 file_name: "maven-metadata.xml".to_string(),
                 size: 13,
             },
@@ -338,42 +336,42 @@ mod tests {
             id: 42,
             name: "my-app".to_string(),
             package_type: "generic".to_string(),
-            created_at: Local::now() - Duration::days(30),
+            created_at: Local::now() - TimeDelta::try_days(30).unwrap(),
         };
         let files = vec![
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(4),
+                created_at: Local::now() - TimeDelta::try_days(4).unwrap(),
                 file_name: "my-app-1.5-20181107.152550-1.jar".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 54,
-                created_at: Local::now() - Duration::days(4),
+                created_at: Local::now() - TimeDelta::try_days(4).unwrap(),
                 file_name: "my-app-1.5-20181107.152550-1.pom".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(4),
+                created_at: Local::now() - TimeDelta::try_days(4).unwrap(),
                 file_name: "maven-metadata.xml".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(5),
+                created_at: Local::now() - TimeDelta::try_days(5).unwrap(),
                 file_name: "my-app-1.5-20181007.142550-1.jar".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 54,
-                created_at: Local::now() - Duration::days(5),
+                created_at: Local::now() - TimeDelta::try_days(5).unwrap(),
                 file_name: "my-app-1.5-20181007.142550-1.pom".to_string(),
                 size: 13,
             },
             GitlabPackageFile {
                 id: 50,
-                created_at: Local::now() - Duration::days(5),
+                created_at: Local::now() - TimeDelta::try_days(5).unwrap(),
                 file_name: "maven-metadata.xml".to_string(),
                 size: 13,
             },
diff --git a/src/diagnosis/pipeline_analysis.rs b/src/diagnosis/pipeline_analysis.rs
index 06a1e5d600afe8047387c791f72a13b70132bbdb..062dba4d906f9b5ffc90b0fffe407b2f79d9ae1b 100644
--- a/src/diagnosis/pipeline_analysis.rs
+++ b/src/diagnosis/pipeline_analysis.rs
@@ -1,4 +1,4 @@
-use chrono::{DateTime, Duration, Local};
+use chrono::{DateTime, Local, TimeDelta};
 use gitlab::api::{Pagination, Query};
 use gitlab::Gitlab;
 use serde::Deserialize;
@@ -32,7 +32,7 @@ impl Reportable for PipelineAnalysisReport {
 }
 
 impl PipelineAnalysisJob {
-    fn to_report(
+    fn into_report(
         self,
         report_status: Vec<ReportStatus>,
         pipelines: Vec<GitlabPipeline>,
@@ -54,7 +54,7 @@ impl ReportJob for PipelineAnalysisJob {
             pending_msg: fl!("pipeline-analysing"),
             job: std::thread::spawn(move || {
                 if !self.project.jobs_enabled {
-                    return self.to_report(vec![ReportStatus::NA(fl!("no-cicd"))], vec![]);
+                    return self.into_report(vec![ReportStatus::NA(fl!("no-cicd"))], vec![]);
                 }
 
                 let endpoint = gitlab::api::projects::pipelines::Pipelines::builder()
@@ -64,19 +64,15 @@ impl ReportJob for PipelineAnalysisJob {
                 let query: Result<Vec<GitlabPipeline>, _> =
                     gitlab::api::paged(endpoint, Pagination::All).query(&self.gitlab);
                 match query {
-                    Err(e) => self.to_report(
-                        vec![ReportStatus::ERROR(format!(
-                            "{} {}",
-                            fl!("error"),
-                            e.to_string()
-                        ))],
+                    Err(e) => self.into_report(
+                        vec![ReportStatus::ERROR(format!("{} {}", fl!("error"), e))],
                         vec![],
                     ),
                     Ok(mut pipelines) => {
                         let days = self.days;
-                        let ref_date = Local::now() - Duration::days(days as i64);
+                        let ref_date = Local::now() - TimeDelta::try_days(days as i64).unwrap();
                         pipelines.sort_by(|a, b| a.created_at.partial_cmp(&b.created_at).unwrap());
-                        self.to_report(
+                        self.into_report(
                             vec![ReportStatus::NA(fl!(
                                 "pipeline-report",
                                 total_pipelines = pipelines.len(),
diff --git a/src/diagnosis/pipeline_clean.rs b/src/diagnosis/pipeline_clean.rs
index af6e3cc13f329af38472eddfb0183f7ba8f20f3a..501d0399ec74d4da28a4eae33a4ef648f894ca74 100644
--- a/src/diagnosis/pipeline_clean.rs
+++ b/src/diagnosis/pipeline_clean.rs
@@ -1,15 +1,15 @@
 use std::cmp::max;
 use std::sync::mpsc;
 
-use chrono::{Duration, Local};
+use chrono::{Local, TimeDelta};
 use gitlab::api::{ApiError, Query};
 use gitlab::Gitlab;
 use human_bytes::human_bytes;
 
-use crate::diagnosis::gitlab_connection::Project;
+use crate::{fl, Reportable, ReportPending, ReportStatus};
+use crate::diagnosis::{GITLAB_SCOPE_ERROR, RemedyJob};
+use crate::diagnosis::gitlab_connection::{Project, Statistics};
 use crate::diagnosis::pipeline_analysis::{GitlabPipeline, PipelineAnalysisReport};
-use crate::diagnosis::{RemedyJob, GITLAB_SCOPE_ERROR};
-use crate::{fl, ReportPending, ReportStatus, Reportable};
 
 pub struct PipelineCleanJob {
     pub pipeline_report: PipelineAnalysisReport,
@@ -17,7 +17,7 @@ pub struct PipelineCleanJob {
 }
 
 pub struct PipelineCleanReport {
-    pub saved_bytes: u64,
+    pub saved_bytes: Option<u64>,
     pub deleted_pipelines: Vec<GitlabPipeline>,
     pub report_status: Vec<ReportStatus>,
 }
@@ -31,7 +31,7 @@ impl Reportable for PipelineCleanReport {
 impl PipelineCleanReport {
     fn fatal_error(id: u64, msg: &str) -> Self {
         Self {
-            saved_bytes: 0,
+            saved_bytes: None,
             deleted_pipelines: vec![],
             report_status: vec![ReportStatus::ERROR(format!(
                 "Pipeline {} - Error : {}",
@@ -46,7 +46,7 @@ impl RemedyJob for PipelineCleanJob {
 
     fn remedy(self) -> ReportPending<Self::Report> {
         let (tx, rx) = mpsc::channel();
-        let ref_date = Local::now() - Duration::days(self.days as i64);
+        let ref_date = Local::now() - TimeDelta::try_days(self.days as i64).unwrap();
         let count = self
             .pipeline_report
             .pipelines
@@ -57,6 +57,13 @@ impl RemedyJob for PipelineCleanJob {
             pending_msg: fl!("pipeline-deleting"),
             job: std::thread::spawn(move || {
                 let mut deleted_pipelines = vec![];
+                if self.pipeline_report.pipelines.is_empty() {
+                    return PipelineCleanReport {
+                        saved_bytes: None,
+                        deleted_pipelines,
+                        report_status: vec![ReportStatus::NA(fl!("pipeline-no-deletion"))],
+                    };
+                }
                 let last_index = self.pipeline_report.pipelines.len() - 1;
                 let mut last_is_old = false;
                 for (i, pipeline) in self.pipeline_report.pipelines.into_iter().enumerate() {
@@ -115,15 +122,30 @@ impl RemedyJob for PipelineCleanJob {
                     }
                     let _ = tx.send(i);
                 }
-                let saved_bytes = PipelineCleanJob::_compute_saved_bytes(
-                    &self.pipeline_report.gitlab,
-                    &self.pipeline_report.project,
-                );
-                let mut report_status = vec![ReportStatus::OK(fl!(
-                    "pipeline-clean-report",
-                    nb_pipelines = deleted_pipelines.len(),
-                    size = human_bytes(saved_bytes as f64)
-                ))];
+
+                let mut report_status = vec![];
+
+                let saved_bytes =
+                    if let Some(stats) = self.pipeline_report.project.statistics.as_ref() {
+                        let saved_bytes_value = PipelineCleanJob::_compute_saved_bytes(
+                            &self.pipeline_report.gitlab,
+                            &self.pipeline_report.project,
+                            stats,
+                        );
+                        report_status.push(ReportStatus::OK(fl!(
+                            "pipeline-clean-report-size",
+                            nb_pipelines = deleted_pipelines.len(),
+                            size = human_bytes(saved_bytes_value as f64)
+                        )));
+                        Some(saved_bytes_value)
+                    } else {
+                        report_status.push(ReportStatus::OK(fl!(
+                            "pipeline-clean-report",
+                            nb_pipelines = deleted_pipelines.len()
+                        )));
+                        None
+                    };
+
                 if last_is_old {
                     report_status.push(ReportStatus::NA(fl!("pipeline-last-notdeleted")));
                 }
@@ -147,8 +169,8 @@ impl PipelineCleanJob {
         }
     }
 
-    fn _compute_saved_bytes(gitlab: &Gitlab, project: &Project) -> u64 {
-        let old_size = project.statistics.job_artifacts_size;
+    fn _compute_saved_bytes(gitlab: &Gitlab, project: &Project, stats: &Statistics) -> u64 {
+        let old_size = stats.job_artifacts_size;
         let endpoint = gitlab::api::projects::Project::builder()
             .project(project.id)
             .statistics(true)
@@ -157,7 +179,7 @@ impl PipelineCleanJob {
 
         let new_size = endpoint
             .query(gitlab)
-            .map(|p: Project| p.statistics.job_artifacts_size)
+            .map(|p: Project| p.statistics.unwrap().job_artifacts_size)
             .unwrap_or(old_size);
         max(0, old_size - new_size)
     }
diff --git a/src/main.rs b/src/main.rs
index 7c182ecb4d1c37ff95c918fc72970c46fb61289f..f9f64561fd5d83617cf3cdd4f717816c2a640a37 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,10 @@
+use i18n_embed::{
+    fluent::{fluent_language_loader, FluentLanguageLoader},
+    DesktopLanguageRequester,
+};
+use lazy_static::lazy_static;
+use rust_embed::RustEmbed;
+use serde::Serialize;
 use structopt::StructOpt;
 
 use cli::Args;
@@ -12,13 +19,6 @@ use crate::diagnosis::pipeline_analysis::{PipelineAnalysisJob, PipelineAnalysisR
 use crate::diagnosis::pipeline_clean::PipelineCleanJob;
 use crate::diagnosis::ReportStatus;
 use crate::diagnosis::{RemedyJob, ReportJob, ReportPending, Reportable};
-use i18n_embed::{
-    fluent::{fluent_language_loader, FluentLanguageLoader},
-    DesktopLanguageRequester,
-};
-use lazy_static::lazy_static;
-use rust_embed::RustEmbed;
-use serde::Serialize;
 
 pub mod api;
 pub mod cli;
@@ -68,7 +68,7 @@ macro_rules! fl {
 #[derive(Serialize)]
 struct AnalysisReport {
     pub url: String,
-    pub stats: Statistics,
+    pub stats: Option<Statistics>,
     pub savable_bytes_jobs: u64,
     pub savable_bytes_packages: u64,
     pub savable_bytes_containers: u64,
@@ -78,52 +78,52 @@ struct AnalysisReport {
 
 impl AnalysisReport {
     pub fn compute_values(&mut self) {
-        let rating_number = self._get_rating();
-        self.rating = Some(
-            RATING_ACRONYM[RATING_RANGE
-                .iter()
-                .position(|&e| rating_number < e)
-                .unwrap_or(RATING_ACRONYM.len() - 1)],
-        );
-
-        let impact_number = self._get_impact();
-        self.impact = Some(
-            IMPACT_ACRONYM[IMPACT_RANGE
-                .iter()
-                .position(|&e| impact_number < e)
-                .unwrap_or(IMPACT_ACRONYM.len() - 1)],
-        );
+        if let Some(stats) = &self.stats {
+            let rating_number = self._get_rating(stats);
+            self.rating = Some(
+                RATING_ACRONYM[RATING_RANGE
+                    .iter()
+                    .position(|&e| rating_number < e)
+                    .unwrap_or(RATING_ACRONYM.len() - 1)],
+            );
+
+            let impact_number = self._get_impact(stats);
+            self.impact = Some(
+                IMPACT_ACRONYM[IMPACT_RANGE
+                    .iter()
+                    .position(|&e| impact_number < e)
+                    .unwrap_or(IMPACT_ACRONYM.len() - 1)],
+            );
+        }
     }
 
-    pub fn _get_impact(&self) -> u64 {
+    pub fn _get_impact(&self, stats: &Statistics) -> u64 {
         // Impact == Disk impact. git repo is evaluated ten times
-        self.stats.repository_size * 9 + self.stats.storage_size
+        stats.repository_size * 9 + stats.storage_size
     }
 
-    pub fn _get_rating(&self) -> u64 {
+    pub fn _get_rating(&self, stats: &Statistics) -> u64 {
         // Rating == Margin of improvement (less is better)
         // Containers are ignored for now
         let repo_limit = 100 * 1024 * 1024;
-        let savable_repo = if self.stats.repository_size > repo_limit {
-            self.stats.repository_size - repo_limit
+        let savable_repo = if stats.repository_size > repo_limit {
+            stats.repository_size - repo_limit
         } else {
             0
         };
         (savable_repo * 9 + self.savable_bytes_jobs + self.savable_bytes_packages) * 100
-            / (self.stats.repository_size * 9
-                + self.stats.job_artifacts_size
-                + self.stats.packages_size)
+            / (stats.repository_size * 9 + stats.job_artifacts_size + stats.packages_size)
     }
 }
 
 fn _connect_to_gitlab(args: &Args) -> GitlabRepository {
     let connection_job = {
         if args.url.is_some() {
-            ConnectionJob::FromUrl(args.url.as_ref().unwrap().clone())
+            ConnectionJob::FromUrl(args.url.as_ref().unwrap().clone(), args.token.clone())
         } else {
             let default_path = String::from(".");
             let path: &str = args.git_path.as_ref().unwrap_or(&default_path);
-            ConnectionJob::FromPath(path.to_string())
+            ConnectionJob::FromPath(path.to_string(), args.token.clone())
         }
     };