diff --git a/.gitignore b/.gitignore
index 3a8cabc9e988187922461e910f02cd5813d0d10c..8fc81bef9d08e567790df6b001fb98cf59e6c705 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 /target
 .idea
+.cargo
diff --git a/.gitlab-ci-local/.gitignore b/.gitlab-ci-local/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d6b7ef32c8478a48c3994dcadc86837f4371184d
--- /dev/null
+++ b/.gitlab-ci-local/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 95fa3fa47d9256a49ef783733d03bfa8f2a394bf..adc9436f6ff774d0f6b48939e5814418c6139f2e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,3 +1,21 @@
+variables:
+  RUST_VERSION: 1.76 # slim or alpine not adapted because of openSSL dependency
+  TARGET_ARCH: default
+  CARGO_HOME: .cargo
+
+default:
+  cache:
+    key: rust-$TARGET_ARCH
+    paths:
+      - .cargo
+      - target/debug/deps
+      - target/debug/build
+      - target/release/deps
+      - target/release/build
+      - target/$TARGET_ARCH/release/deps
+      - target/$TARGET_ARCH/release/build
+    policy: pull-push
+
 stages:
   - build_test
   - release
@@ -5,44 +23,56 @@ stages:
 
 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'
 
 check-format:
   stage: build_test
-  image: rust:latest
+  image: rust:$RUST_VERSION
   script:
     - rustup component add rustfmt
+    - rustup component add clippy
     - cargo fmt --all -- --check
+    - cargo clippy -- -D warnings
+  allow_failure: true
 
-test-rust-latest:
+gitleaks:
   stage: build_test
-  image: rust:latest
+
+test-rust-current:
+  stage: build_test
+  image: rust:$RUST_VERSION
   script:
     - cargo test --verbose
+  rules:
+    - if: $CI_COMMIT_REF_NAME == 'main'
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
 
 test-rust-nightly:
-  stage: build_test
+  extends: test-rust-current
   image: rustlang/rust:nightly
-  script:
-    - cargo test --verbose
-  allow_failure: true
 
 .rust-release:
   stage: release
   variables:
     TARGET: target/$TARGET_ARCH/release/gitlab-project-doctor
+    PKG_VERSION: ${CI_COMMIT_TAG:-latest}
   script:
     - rustup target add $TARGET_ARCH
     - cargo build $CARGO_OPTS --target $TARGET_ARCH --release
     - strip $TARGET
     - $LDD_CMD $TARGET
     - $TARGET --help
+    - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/$TARGET_ARCH/$PKG_VERSION/gitlab-project-doctor" -O'
   artifacts:
     paths:
       - $TARGET
+  rules:
+    - if: $CI_COMMIT_REF_NAME == 'main'
+    - if: $CI_COMMIT_TAG
 
 release-linux:
   extends: .rust-release
-  image: rust:latest
+  image: rust:$RUST_VERSION
   variables:
     TARGET_ARCH: x86_64-unknown-linux-musl
     LDD_CMD: ldd
@@ -70,9 +100,25 @@ release-macos-x86:
 
 docker_build:
   stage: deploy
+  variables:
+    COMMIT_CREATE_LATEST: "false"
+    IMAGE_TAG: "v1.19.2-debug"
+  retry: 2
+  needs:
+    - release-linux
+  cache: []
+  rules:
+    - if: $CI_COMMIT_REF_NAME == 'main'
+
+docker_build-prod:
+  stage: deploy
+  extends: docker_build
   variables:
     COMMIT_CREATE_LATEST: "true"
     IMAGE_TAG: "v1.19.2-debug"
   retry: 2
   needs:
     - release-linux
+  cache: []
+  rules:
+    - if: $CI_COMMIT_TAG
\ No newline at end of file
diff --git a/src/api/packages.rs b/src/api/packages.rs
index 85239dfbdc142bf1af8ce5b528ab75546e354b88..9739d80f405d01912af18ab585e478b1164b4ba4 100644
--- a/src/api/packages.rs
+++ b/src/api/packages.rs
@@ -18,4 +18,7 @@ pub use self::packages::Packages;
 mod delete_file;
 mod package;
 mod package_files;
+
+// Naming convention extends gitlab crate
+#[allow(clippy::module_inception)]
 mod packages;
diff --git a/src/diagnosis/container_analysis.rs b/src/diagnosis/container_analysis.rs
index 13f14a8d6017fae9031f672d939cf492f8c8fa6a..ba95504bef3d1ba2c98eb951848fe68f37642071 100644
--- a/src/diagnosis/container_analysis.rs
+++ b/src/diagnosis/container_analysis.rs
@@ -54,7 +54,7 @@ impl Reportable for ContainerAnalysisReport {
 }
 
 impl ContainerAnalysisJob {
-    fn to_report(
+    fn into_report(
         self,
         report_status: Vec<ReportStatus>,
         containers: Vec<GitlabContainerRepository>,
@@ -108,7 +108,7 @@ impl ReportJob for ContainerAnalysisJob {
             pending_msg: fl!("container-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 = api::registry::Repositories::builder()
@@ -119,7 +119,7 @@ impl ReportJob for ContainerAnalysisJob {
                 let query: Result<Vec<GitlabRawContainerRepository>, _> =
                     gitlab::api::paged(endpoint, Pagination::All).query(&self.gitlab);
                 match query {
-                    Err(e) => self.to_report(
+                    Err(e) => self.into_report(
                         vec![ReportStatus::ERROR(format!(
                             "{} {}",
                             fl!("error"),
@@ -144,7 +144,7 @@ impl ReportJob for ContainerAnalysisJob {
                             .iter()
                             .map(|cr| cr.tags.iter().filter(|t| t.created_at < ref_date).count())
                             .sum();
-                        self.to_report(
+                        self.into_report(
                             vec![
                                 warning_if(
                                     registry_size > CONTAINER_REGISTRY_LIMIT,