This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal-reqsign.git


The following commit(s) were added to refs/heads/main by this push:
     new 1d5ac3d  Apply CI security best practices (#687)
1d5ac3d is described below

commit 1d5ac3d18b984f11f55ed2c14c18e43f7d03a082
Author: William Woodruff <[email protected]>
AuthorDate: Thu Feb 26 09:27:58 2026 -0500

    Apply CI security best practices (#687)
    
    Hi there! [uv](https://github.com/astral-sh/uv) is a downstream user of
    this crate, and as a result we have an interest in ensuring your CI/CD
    is as secure, hermetic, and reproducible as possible 🙂
    
    To that end, this PR has a series of commits (each of which can be
    reviewed separately) that will hopefully improve your default posture.
    These changes were made based on findings from
    [zizmor](https://docs.zizmor.sh).
    
    To summarize:
    
    1. All actions references are now hash-pinned, to prevent unexpected tag
    mutation. Dependabot will handle updating these hash-pins for you.
    2. Dependabot itself now enforces a seven-day cooldown, to reduce the
    risk of quickly adopting a compromised dependency.
    3. I've minimized all permissions and credential persistence risks in
    all workflows. This should be **reviewed carefully**, since it's hard to
    predict ahead-of-time whether some permissions were being used
    implicitly.
    4. I've eliminated all flagged template injection risks. Most of these
    are not exploitable in practice, but intermediating expressions with
    shell variables `${FOO}` instead of `${{ foo }}` is a best practice
    anyways.
    
    After all of that, the only remaining default finding is this:
    
    ```
    info[use-trusted-publishing]: prefer trusted publishing for authentication
      --> ./.github/workflows/release.yml:40:14
       |
    40 |       - run: cargo publish --workspace
       |         ---  ^^^^^^^^^^^^^^^^^^^^^^^^^ this command
       |         |
       |         this step
       |
       = note: audit confidence → High
    ```
    
    To fix that one, one of the maintainers will need to set up [Trusted
    Publishing](https://crates.io/docs/trusted-publishing) and remove your
    current manual crates.io token. I strongly recommend doing this as a way
    to reduce your credential exposure risk 🙂
    
    Finally, I've done all this without adding a workflow that will
    proactively catch new CI/CD issues. However, if you're interested in
    that, I'd be happy to add one.
    
    Signed-off-by: William Woodruff <[email protected]>
    
    ---------
    
    Signed-off-by: William Woodruff <[email protected]>
---
 .github/dependabot.yml                |   4 +
 .github/workflows/aliyun_oss.yml      |   4 +-
 .github/workflows/aws_v4.yml          | 140 ++++++++++++++++++++++++----------
 .github/workflows/azure_storage.yml   | 113 ++++++++++++++++++---------
 .github/workflows/ci.yml              |  28 +++++--
 .github/workflows/google.yml          | 137 +++++++++++++++++++++------------
 .github/workflows/huaweicloud_obs.yml |   8 +-
 .github/workflows/oracle.yml          |   6 +-
 .github/workflows/release.yml         |   8 +-
 .github/workflows/tencent_cos.yml     |  10 ++-
 10 files changed, 314 insertions(+), 144 deletions(-)

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index c1a4477..8745c6b 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -22,9 +22,13 @@ updates:
     directory: "/"
     schedule:
       interval: "daily"
+    cooldown:
+      default-days: 7
 
   # Maintain dependencies for rust
   - package-ecosystem: "cargo"
     directory: "/"
     schedule:
       interval: "daily"
+    cooldown:
+      default-days: 7
diff --git a/.github/workflows/aliyun_oss.yml b/.github/workflows/aliyun_oss.yml
index decf8b4..7ab1927 100644
--- a/.github/workflows/aliyun_oss.yml
+++ b/.github/workflows/aliyun_oss.yml
@@ -35,7 +35,9 @@ jobs:
     permissions:
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Test
         working-directory: ./services/aliyun-oss
         run: cargo test --no-fail-fast
diff --git a/.github/workflows/aws_v4.yml b/.github/workflows/aws_v4.yml
index 6b663fc..bffc8d3 100644
--- a/.github/workflows/aws_v4.yml
+++ b/.github/workflows/aws_v4.yml
@@ -33,12 +33,16 @@ env:
   RUST_LOG: DEBUG
   RUST_BACKTRACE: full
 
+permissions: {}
+
 jobs:
   # Unit tests - always run, no secrets needed
   unit_test:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Run unit tests
         working-directory: ./services/aws-v4
         run: |
@@ -70,14 +74,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -100,14 +106,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -127,15 +135,17 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
         id: load_secret
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         env:
           REQSIGN_AWS_V4_TEST_ENV: on
           REQSIGN_AWS_V4_TEST_PROFILE: on
@@ -146,12 +156,12 @@ jobs:
           mkdir -p ~/.aws
           cat > ~/.aws/credentials << EOF
           [default]
-          aws_access_key_id = ${{ steps.load_secrets.outputs.AWS_ACCESS_KEY_ID 
}}
-          aws_secret_access_key = ${{ 
steps.load_secrets.outputs.AWS_SECRET_ACCESS_KEY }}
+          aws_access_key_id = ${STEPS_LOAD_SECRETS_OUTPUTS_AWS_ACCESS_KEY_ID}
+          aws_secret_access_key = 
${STEPS_LOAD_SECRETS_OUTPUTS_AWS_SECRET_ACCESS_KEY}
 
           [test-profile]
-          aws_access_key_id = ${{ steps.load_secrets.outputs.AWS_ACCESS_KEY_ID 
}}
-          aws_secret_access_key = ${{ 
steps.load_secrets.outputs.AWS_SECRET_ACCESS_KEY }}
+          aws_access_key_id = ${STEPS_LOAD_SECRETS_OUTPUTS_AWS_ACCESS_KEY_ID}
+          aws_secret_access_key = 
${STEPS_LOAD_SECRETS_OUTPUTS_AWS_SECRET_ACCESS_KEY}
           EOF
 
           cat > ~/.aws/config << EOF
@@ -162,6 +172,9 @@ jobs:
           region = us-west-1
           output = json
           EOF
+        env:
+          STEPS_LOAD_SECRETS_OUTPUTS_AWS_ACCESS_KEY_ID: ${{ 
steps.load_secrets.outputs.AWS_ACCESS_KEY_ID }}
+          STEPS_LOAD_SECRETS_OUTPUTS_AWS_SECRET_ACCESS_KEY: ${{ 
steps.load_secrets.outputs.AWS_SECRET_ACCESS_KEY }}
       - name: Test ProfileCredentialProvider
         working-directory: ./services/aws-v4
         run: |
@@ -175,14 +188,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -207,9 +222,11 @@ jobs:
       contents: read
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Get GitHub OIDC token
-        uses: actions/github-script@v8
+        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # 
v8.0.0
         id: idtoken
         with:
           script: |
@@ -222,12 +239,12 @@ jobs:
 
             console.log('GitHub OIDC token obtained and saved');
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -247,7 +264,9 @@ jobs:
   test_imds_provider:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Start amazon-ec2-metadata-mock
         run: |
           # Download ec2-metadata-mock binary
@@ -323,7 +342,9 @@ jobs:
   test_ecs_provider:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup Mock ECS Credentials Server
         run: |
           # Start the mock server in background using the maintained script
@@ -372,7 +393,9 @@ jobs:
   test_sso_provider:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup SSO Mock Environment
         run: |
           # Create test home directory structure
@@ -451,7 +474,9 @@ jobs:
   test_process_provider:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup process credential helper
         run: |
           # Create test home directory
@@ -512,7 +537,9 @@ jobs:
   test_cognito_provider:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Start Cognito Identity Mock Server
         run: |
           # Start the mock server
@@ -555,14 +582,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -608,21 +637,21 @@ jobs:
           echo "#### Core Tests" >> $GITHUB_STEP_SUMMARY
           echo "| Test | Result |" >> $GITHUB_STEP_SUMMARY
           echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
-          echo "| Unit Tests | ${{ needs.unit_test.result }} |" >> 
$GITHUB_STEP_SUMMARY
+          echo "| Unit Tests | ${NEEDS_UNIT_TEST_RESULT} |" >> 
$GITHUB_STEP_SUMMARY
           echo "" >> $GITHUB_STEP_SUMMARY
 
           echo "#### Integration Tests (with real AWS credentials)" >> 
$GITHUB_STEP_SUMMARY
-          if [[ "${{ needs.check_secrets.outputs.has_secrets }}" == "true" ]]; 
then
+          if [[ "${NEEDS_CHECK_SECRETS_OUTPUTS_HAS_SECRETS}" == "true" ]]; then
             echo "✅ **Integration tests with real AWS credentials were 
executed**" >> $GITHUB_STEP_SUMMARY
             echo "" >> $GITHUB_STEP_SUMMARY
             echo "| Test | Result |" >> $GITHUB_STEP_SUMMARY
             echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
-            echo "| Signing Tests | ${{ needs.signing_test.result }} |" >> 
$GITHUB_STEP_SUMMARY
-            echo "| EnvCredentialProvider | ${{ needs.test_env_provider.result 
}} |" >> $GITHUB_STEP_SUMMARY
-            echo "| ProfileCredentialProvider | ${{ 
needs.test_profile_provider.result }} |" >> $GITHUB_STEP_SUMMARY
-            echo "| AssumeRoleCredentialProvider | ${{ 
needs.test_assume_role_provider.result }} |" >> $GITHUB_STEP_SUMMARY
-            echo "| AssumeRoleWithWebIdentityCredentialProvider | ${{ 
needs.test_web_identity_provider.result }} |" >> $GITHUB_STEP_SUMMARY
-            echo "| S3ExpressSessionProvider | ${{ 
needs.test_s3_express_provider.result }} |" >> $GITHUB_STEP_SUMMARY
+            echo "| Signing Tests | ${NEEDS_SIGNING_TEST_RESULT} |" >> 
$GITHUB_STEP_SUMMARY
+            echo "| EnvCredentialProvider | ${NEEDS_TEST_ENV_PROVIDER_RESULT} 
|" >> $GITHUB_STEP_SUMMARY
+            echo "| ProfileCredentialProvider | 
${NEEDS_TEST_PROFILE_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+            echo "| AssumeRoleCredentialProvider | 
${NEEDS_TEST_ASSUME_ROLE_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+            echo "| AssumeRoleWithWebIdentityCredentialProvider | 
${NEEDS_TEST_WEB_IDENTITY_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+            echo "| S3ExpressSessionProvider | 
${NEEDS_TEST_S3_EXPRESS_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
           else
             echo "⚠️ **Integration tests were skipped** (forked repository or 
no secrets available)" >> $GITHUB_STEP_SUMMARY
           fi
@@ -633,8 +662,35 @@ jobs:
           echo "" >> $GITHUB_STEP_SUMMARY
           echo "| Provider | Mock Server | Result |" >> $GITHUB_STEP_SUMMARY
           echo "|----------|-------------|--------|" >> $GITHUB_STEP_SUMMARY
-          echo "| IMDSv2CredentialProvider | amazon-ec2-metadata-mock | ${{ 
needs.test_imds_provider.result }} |" >> $GITHUB_STEP_SUMMARY
-          echo "| ECSCredentialProvider | Python mock (port 51679) | ${{ 
needs.test_ecs_provider.result }} |" >> $GITHUB_STEP_SUMMARY
-          echo "| SSOCredentialProvider | Python mock (port 8080) | ${{ 
needs.test_sso_provider.result }} |" >> $GITHUB_STEP_SUMMARY
-          echo "| ProcessCredentialProvider | Python credential helper | ${{ 
needs.test_process_provider.result }} |" >> $GITHUB_STEP_SUMMARY
-          echo "| CognitoIdentityCredentialProvider | Python mock (port 8443) 
| ${{ needs.test_cognito_provider.result }} |" >> $GITHUB_STEP_SUMMARY
+          echo "| IMDSv2CredentialProvider | amazon-ec2-metadata-mock | 
${NEEDS_TEST_IMDS_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+          echo "| ECSCredentialProvider | Python mock (port 51679) | 
${NEEDS_TEST_ECS_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+          echo "| SSOCredentialProvider | Python mock (port 8080) | 
${NEEDS_TEST_SSO_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+          echo "| ProcessCredentialProvider | Python credential helper | 
${NEEDS_TEST_PROCESS_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+          echo "| CognitoIdentityCredentialProvider | Python mock (port 8443) 
| ${NEEDS_TEST_COGNITO_PROVIDER_RESULT} |" >> $GITHUB_STEP_SUMMARY
+
+        env:
+          NEEDS_UNIT_TEST_RESULT: ${{ needs.unit_test.result }}
+
+          NEEDS_CHECK_SECRETS_OUTPUTS_HAS_SECRETS: ${{ 
needs.check_secrets.outputs.has_secrets }}
+
+          NEEDS_SIGNING_TEST_RESULT: ${{ needs.signing_test.result }}
+
+          NEEDS_TEST_ENV_PROVIDER_RESULT: ${{ needs.test_env_provider.result }}
+
+          NEEDS_TEST_PROFILE_PROVIDER_RESULT: ${{ 
needs.test_profile_provider.result }}
+
+          NEEDS_TEST_ASSUME_ROLE_PROVIDER_RESULT: ${{ 
needs.test_assume_role_provider.result }}
+
+          NEEDS_TEST_WEB_IDENTITY_PROVIDER_RESULT: ${{ 
needs.test_web_identity_provider.result }}
+
+          NEEDS_TEST_S3_EXPRESS_PROVIDER_RESULT: ${{ 
needs.test_s3_express_provider.result }}
+
+          NEEDS_TEST_IMDS_PROVIDER_RESULT: ${{ needs.test_imds_provider.result 
}}
+
+          NEEDS_TEST_ECS_PROVIDER_RESULT: ${{ needs.test_ecs_provider.result }}
+
+          NEEDS_TEST_SSO_PROVIDER_RESULT: ${{ needs.test_sso_provider.result }}
+
+          NEEDS_TEST_PROCESS_PROVIDER_RESULT: ${{ 
needs.test_process_provider.result }}
+
+          NEEDS_TEST_COGNITO_PROVIDER_RESULT: ${{ 
needs.test_cognito_provider.result }}
diff --git a/.github/workflows/azure_storage.yml 
b/.github/workflows/azure_storage.yml
index eafb43e..63720a5 100644
--- a/.github/workflows/azure_storage.yml
+++ b/.github/workflows/azure_storage.yml
@@ -33,12 +33,16 @@ env:
   RUST_LOG: DEBUG
   RUST_BACKTRACE: full
 
+permissions: {}
+
 jobs:
   # Unit tests - always run, no secrets needed
   unit_test:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Run unit tests
         working-directory: ./services/azure-storage
         run: |
@@ -70,14 +74,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -99,14 +105,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -127,14 +135,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -156,14 +166,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -184,14 +196,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -228,14 +242,16 @@ jobs:
       contents: read
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -243,7 +259,7 @@ jobs:
           AZURE_TENANT_ID: op://reqsign/azure-storage/tenant_id
           AZURE_CLIENT_ID: op://reqsign/azure-storage/client_id
       - name: Azure Login with OIDC
-        uses: azure/login@v2
+        uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
         with:
           client-id: ${{ env.AZURE_CLIENT_ID }}
           tenant-id: ${{ env.AZURE_TENANT_ID }}
@@ -261,7 +277,9 @@ jobs:
   test_imds_provider:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Start IMDS mock server
         run: |
           python3 ./services/azure-storage/tests/mocks/imds_mock.py 8080 &
@@ -312,29 +330,29 @@ jobs:
 
           echo "| Test | Status | Type |" >> $GITHUB_STEP_SUMMARY
           echo "|------|--------|------|" >> $GITHUB_STEP_SUMMARY
-          echo "| Unit Tests | ${{ needs.unit_test.result }} | Core |" >> 
$GITHUB_STEP_SUMMARY
-          echo "| Signing Tests | ${{ needs.signing_test.result }} | 
Integration |" >> $GITHUB_STEP_SUMMARY
-          echo "| EnvCredentialProvider | ${{ needs.test_env_provider.result 
}} | Integration |" >> $GITHUB_STEP_SUMMARY
-          echo "| StaticCredentialProvider | ${{ 
needs.test_static_provider.result }} | Integration |" >> $GITHUB_STEP_SUMMARY
-          echo "| ClientSecretCredentialProvider | ${{ 
needs.test_client_secret_provider.result }} | Integration |" >> 
$GITHUB_STEP_SUMMARY
-          echo "| ClientCertificateCredentialProvider | ${{ 
needs.test_client_certificate_provider.result }} | Integration |" >> 
$GITHUB_STEP_SUMMARY
-          echo "| AzureCliCredentialProvider | ${{ 
needs.test_azure_cli_provider.result }} | Integration |" >> $GITHUB_STEP_SUMMARY
-          echo "| ImdsCredentialProvider | ${{ needs.test_imds_provider.result 
}} | Mock |" >> $GITHUB_STEP_SUMMARY
+          echo "| Unit Tests | ${NEEDS_UNIT_TEST_RESULT} | Core |" >> 
$GITHUB_STEP_SUMMARY
+          echo "| Signing Tests | ${NEEDS_SIGNING_TEST_RESULT} | Integration 
|" >> $GITHUB_STEP_SUMMARY
+          echo "| EnvCredentialProvider | ${NEEDS_TEST_ENV_PROVIDER_RESULT} | 
Integration |" >> $GITHUB_STEP_SUMMARY
+          echo "| StaticCredentialProvider | 
${NEEDS_TEST_STATIC_PROVIDER_RESULT} | Integration |" >> $GITHUB_STEP_SUMMARY
+          echo "| ClientSecretCredentialProvider | 
${NEEDS_TEST_CLIENT_SECRET_PROVIDER_RESULT} | Integration |" >> 
$GITHUB_STEP_SUMMARY
+          echo "| ClientCertificateCredentialProvider | 
${NEEDS_TEST_CLIENT_CERTIFICATE_PROVIDER_RESULT} | Integration |" >> 
$GITHUB_STEP_SUMMARY
+          echo "| AzureCliCredentialProvider | 
${NEEDS_TEST_AZURE_CLI_PROVIDER_RESULT} | Integration |" >> $GITHUB_STEP_SUMMARY
+          echo "| ImdsCredentialProvider | ${NEEDS_TEST_IMDS_PROVIDER_RESULT} 
| Mock |" >> $GITHUB_STEP_SUMMARY
           echo "" >> $GITHUB_STEP_SUMMARY
 
-          if [[ "${{ needs.check_secrets.outputs.has_secrets }}" != "true" ]]; 
then
+          if [[ "${NEEDS_CHECK_SECRETS_OUTPUTS_HAS_SECRETS}" != "true" ]]; then
             echo "⚠️ **Note:** Integration tests requiring secrets were 
skipped (forked repository or no secrets available)" >> $GITHUB_STEP_SUMMARY
           fi
 
           # Check if any test failed
-          if [[ "${{ needs.unit_test.result }}" == "failure" ]] || \
-             [[ "${{ needs.signing_test.result }}" == "failure" ]] || \
-             [[ "${{ needs.test_env_provider.result }}" == "failure" ]] || \
-             [[ "${{ needs.test_static_provider.result }}" == "failure" ]] || \
-             [[ "${{ needs.test_client_secret_provider.result }}" == "failure" 
]] || \
-             [[ "${{ needs.test_client_certificate_provider.result }}" == 
"failure" ]] || \
-             [[ "${{ needs.test_azure_cli_provider.result }}" == "failure" ]] 
|| \
-             [[ "${{ needs.test_imds_provider.result }}" == "failure" ]]; then
+          if [[ "${NEEDS_UNIT_TEST_RESULT}" == "failure" ]] || \
+             [[ "${NEEDS_SIGNING_TEST_RESULT}" == "failure" ]] || \
+             [[ "${NEEDS_TEST_ENV_PROVIDER_RESULT}" == "failure" ]] || \
+             [[ "${NEEDS_TEST_STATIC_PROVIDER_RESULT}" == "failure" ]] || \
+             [[ "${NEEDS_TEST_CLIENT_SECRET_PROVIDER_RESULT}" == "failure" ]] 
|| \
+             [[ "${NEEDS_TEST_CLIENT_CERTIFICATE_PROVIDER_RESULT}" == 
"failure" ]] || \
+             [[ "${NEEDS_TEST_AZURE_CLI_PROVIDER_RESULT}" == "failure" ]] || \
+             [[ "${NEEDS_TEST_IMDS_PROVIDER_RESULT}" == "failure" ]]; then
             echo "" >> $GITHUB_STEP_SUMMARY
             echo "❌ **Some tests failed. Please check the logs above.**" >> 
$GITHUB_STEP_SUMMARY
             exit 1
@@ -342,3 +360,22 @@ jobs:
             echo "" >> $GITHUB_STEP_SUMMARY
             echo "✅ **All tests passed!**" >> $GITHUB_STEP_SUMMARY
           fi
+
+        env:
+          NEEDS_UNIT_TEST_RESULT: ${{ needs.unit_test.result }}
+
+          NEEDS_SIGNING_TEST_RESULT: ${{ needs.signing_test.result }}
+
+          NEEDS_TEST_ENV_PROVIDER_RESULT: ${{ needs.test_env_provider.result }}
+
+          NEEDS_TEST_STATIC_PROVIDER_RESULT: ${{ 
needs.test_static_provider.result }}
+
+          NEEDS_TEST_CLIENT_SECRET_PROVIDER_RESULT: ${{ 
needs.test_client_secret_provider.result }}
+
+          NEEDS_TEST_CLIENT_CERTIFICATE_PROVIDER_RESULT: ${{ 
needs.test_client_certificate_provider.result }}
+
+          NEEDS_TEST_AZURE_CLI_PROVIDER_RESULT: ${{ 
needs.test_azure_cli_provider.result }}
+
+          NEEDS_TEST_IMDS_PROVIDER_RESULT: ${{ needs.test_imds_provider.result 
}}
+
+          NEEDS_CHECK_SECRETS_OUTPUTS_HAS_SECRETS: ${{ 
needs.check_secrets.outputs.has_secrets }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2f728e9..681f83d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,11 +29,15 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
   cancel-in-progress: true
 
+permissions: {}
+
 jobs:
   check:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Format
         run: cargo fmt --all -- --check
 
@@ -46,9 +50,11 @@ jobs:
     env:
       FORCE_COLOR: 1
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Check license headers
-        uses: korandoru/hawkeye@v6
+        uses: korandoru/hawkeye@7ffde2c5fd29f3c486e4a6510436dca54f386e2a # 
v6.5.0
 
   build:
     runs-on: ${{ matrix.os }}
@@ -59,7 +65,9 @@ jobs:
           - macos-latest
           - windows-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Build
         run: cargo build --workspace
 
@@ -67,7 +75,9 @@ jobs:
   build_under_wasm:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Build
         working-directory: reqsign
         run: |
@@ -79,7 +89,9 @@ jobs:
     permissions:
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Test
         run: cargo test --no-fail-fast
         env:
@@ -94,7 +106,9 @@ jobs:
   wasm_tests:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Install wasm-bindgen-cli
         run: |
           WASM_BINDGEN_VERSION=$(
diff --git a/.github/workflows/google.yml b/.github/workflows/google.yml
index 65f1616..c901257 100644
--- a/.github/workflows/google.yml
+++ b/.github/workflows/google.yml
@@ -33,12 +33,16 @@ env:
   RUST_LOG: DEBUG
   RUST_BACKTRACE: full
 
+permissions: {}
+
 jobs:
   # Unit tests - always run, no secrets needed
   unit_test:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Run unit tests
         working-directory: ./services/google
         run: |
@@ -70,14 +74,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -98,22 +104,26 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
         id: load_secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         env:
           REQSIGN_GOOGLE_TEST_DEFAULT: on
           GOOGLE_APPLICATION_CREDENTIALS_BASE64: 
op://reqsign/google/credential_base64
       - name: Setup test credentials file
         run: |
-          echo "${{ 
steps.load_secrets.outputs.GOOGLE_APPLICATION_CREDENTIALS_BASE64 }}" | base64 
-d > /tmp/gcp_credentials.json
+          echo 
"${STEPS_LOAD_SECRETS_OUTPUTS_GOOGLE_APPLICATION_CREDENTIALS_BASE64}" | base64 
-d > /tmp/gcp_credentials.json
           echo "GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcp_credentials.json" >> 
$GITHUB_ENV
+        env:
+          STEPS_LOAD_SECRETS_OUTPUTS_GOOGLE_APPLICATION_CREDENTIALS_BASE64: 
${{ steps.load_secrets.outputs.GOOGLE_APPLICATION_CREDENTIALS_BASE64 }}
       - name: Test DefaultCredentialProvider
         working-directory: ./services/google
         run: |
@@ -127,14 +137,16 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -154,22 +166,26 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
         id: load_secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         env:
           REQSIGN_GOOGLE_TEST_AUTHORIZED_USER: on
           AUTHORIZED_USER_CREDENTIALS_BASE64: 
op://reqsign/google/authorized_user_base64
       - name: Setup test credentials file
         run: |
-          echo "${{ 
steps.load_secrets.outputs.AUTHORIZED_USER_CREDENTIALS_BASE64 }}" | base64 -d > 
/tmp/authorized_user.json
+          echo 
"${STEPS_LOAD_SECRETS_OUTPUTS_AUTHORIZED_USER_CREDENTIALS_BASE64}" | base64 -d 
> /tmp/authorized_user.json
           echo 
"REQSIGN_GOOGLE_AUTHORIZED_USER_CREDENTIALS=/tmp/authorized_user.json" >> 
$GITHUB_ENV
+        env:
+          STEPS_LOAD_SECRETS_OUTPUTS_AUTHORIZED_USER_CREDENTIALS_BASE64: ${{ 
steps.load_secrets.outputs.AUTHORIZED_USER_CREDENTIALS_BASE64 }}
       - name: Test AuthorizedUserCredentialProvider
         working-directory: ./services/google
         run: |
@@ -186,14 +202,16 @@ jobs:
       contents: read
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         with:
           export-env: true
         env:
@@ -201,7 +219,7 @@ jobs:
           GOOGLE_WORKLOAD_IDENTITY_PROVIDER: 
op://reqsign/google/workload_identity_provider
           GOOGLE_SERVICE_ACCOUNT: op://reqsign/google/service_account_email
       - name: Setup Workload Identity with Google Auth
-        uses: 
google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3
+        uses: 
google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
         with:
           create_credentials_file: true
           workload_identity_provider: ${{ 
env.GOOGLE_WORKLOAD_IDENTITY_PROVIDER }}
@@ -221,22 +239,26 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Setup 1Password Connect
-        uses: 1password/load-secrets-action/[email protected]
+        uses: 
1password/load-secrets-action/configure@8d0d610af187e78a2772c2d18d627f4c52d3fbfb
 # v3.1.0
         with:
           connect-host: ${{ secrets.OP_CONNECT_HOST }}
           connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
       - name: Load secrets
         id: load_secrets
-        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3
+        uses: 
1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
         env:
           REQSIGN_GOOGLE_TEST_IMPERSONATED_SERVICE_ACCOUNT: on
           IMPERSONATED_SA_CREDENTIALS_BASE64: 
op://reqsign/google/impersonated_sa_base64
       - name: Setup test credentials file
         run: |
-          echo "${{ 
steps.load_secrets.outputs.IMPERSONATED_SA_CREDENTIALS_BASE64 }}" | base64 -d > 
/tmp/impersonated_sa.json
+          echo 
"${STEPS_LOAD_SECRETS_OUTPUTS_IMPERSONATED_SA_CREDENTIALS_BASE64}" | base64 -d 
> /tmp/impersonated_sa.json
           echo 
"REQSIGN_GOOGLE_IMPERSONATED_SERVICE_ACCOUNT_CREDENTIALS=/tmp/impersonated_sa.json"
 >> $GITHUB_ENV
+        env:
+          STEPS_LOAD_SECRETS_OUTPUTS_IMPERSONATED_SA_CREDENTIALS_BASE64: ${{ 
steps.load_secrets.outputs.IMPERSONATED_SA_CREDENTIALS_BASE64 }}
       - name: Test ImpersonatedServiceAccountCredentialProvider
         working-directory: ./services/google
         run: |
@@ -250,7 +272,9 @@ jobs:
     if: needs.check_secrets.outputs.has_secrets == 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Start mock metadata server
         run: |
           python3 services/google/tests/mocks/vm_metadata_mock_server.py 8080 &
@@ -295,9 +319,9 @@ jobs:
           echo "" >> $GITHUB_STEP_SUMMARY
 
           # Unit tests status
-          if [[ "${{ needs.unit_test.result }}" == "success" ]]; then
+          if [[ "${NEEDS_UNIT_TEST_RESULT}" == "success" ]]; then
             echo "✅ Unit tests passed" >> $GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.unit_test.result }}" == "skipped" ]]; then
+          elif [[ "${NEEDS_UNIT_TEST_RESULT}" == "skipped" ]]; then
             echo "⏭️ Unit tests skipped" >> $GITHUB_STEP_SUMMARY
           else
             echo "❌ Unit tests failed" >> $GITHUB_STEP_SUMMARY
@@ -307,57 +331,57 @@ jobs:
           echo "" >> $GITHUB_STEP_SUMMARY
           echo "### Integration Tests" >> $GITHUB_STEP_SUMMARY
 
-          if [[ "${{ needs.signing_test.result }}" == "success" ]]; then
+          if [[ "${NEEDS_SIGNING_TEST_RESULT}" == "success" ]]; then
             echo "✅ Signing tests passed" >> $GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.signing_test.result }}" == "skipped" ]]; then
+          elif [[ "${NEEDS_SIGNING_TEST_RESULT}" == "skipped" ]]; then
             echo "⏭️ Signing tests skipped (no secrets)" >> 
$GITHUB_STEP_SUMMARY
           else
             echo "❌ Signing tests failed" >> $GITHUB_STEP_SUMMARY
           fi
 
-          if [[ "${{ needs.test_default_provider.result }}" == "success" ]]; 
then
+          if [[ "${NEEDS_TEST_DEFAULT_PROVIDER_RESULT}" == "success" ]]; then
             echo "✅ DefaultCredentialProvider tests passed" >> 
$GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.test_default_provider.result }}" == "skipped" ]]; 
then
+          elif [[ "${NEEDS_TEST_DEFAULT_PROVIDER_RESULT}" == "skipped" ]]; then
             echo "⏭️ DefaultCredentialProvider tests skipped (no secrets)" >> 
$GITHUB_STEP_SUMMARY
           else
             echo "❌ DefaultCredentialProvider tests failed" >> 
$GITHUB_STEP_SUMMARY
           fi
 
-          if [[ "${{ needs.test_static_provider.result }}" == "success" ]]; 
then
+          if [[ "${NEEDS_TEST_STATIC_PROVIDER_RESULT}" == "success" ]]; then
             echo "✅ StaticCredentialProvider tests passed" >> 
$GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.test_static_provider.result }}" == "skipped" ]]; 
then
+          elif [[ "${NEEDS_TEST_STATIC_PROVIDER_RESULT}" == "skipped" ]]; then
             echo "⏭️ StaticCredentialProvider tests skipped (no secrets)" >> 
$GITHUB_STEP_SUMMARY
           else
             echo "❌ StaticCredentialProvider tests failed" >> 
$GITHUB_STEP_SUMMARY
           fi
 
-          if [[ "${{ needs.test_authorized_user_provider.result }}" == 
"success" ]]; then
+          if [[ "${NEEDS_TEST_AUTHORIZED_USER_PROVIDER_RESULT}" == "success" 
]]; then
             echo "✅ AuthorizedUserCredentialProvider tests passed" >> 
$GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.test_authorized_user_provider.result }}" == 
"skipped" ]]; then
+          elif [[ "${NEEDS_TEST_AUTHORIZED_USER_PROVIDER_RESULT}" == "skipped" 
]]; then
             echo "⏭️ AuthorizedUserCredentialProvider tests skipped (no 
secrets)" >> $GITHUB_STEP_SUMMARY
           else
             echo "❌ AuthorizedUserCredentialProvider tests failed" >> 
$GITHUB_STEP_SUMMARY
           fi
 
-          if [[ "${{ needs.test_external_account_provider.result }}" == 
"success" ]]; then
+          if [[ "${NEEDS_TEST_EXTERNAL_ACCOUNT_PROVIDER_RESULT}" == "success" 
]]; then
             echo "✅ ExternalAccountCredentialProvider tests passed" >> 
$GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.test_external_account_provider.result }}" == 
"skipped" ]]; then
+          elif [[ "${NEEDS_TEST_EXTERNAL_ACCOUNT_PROVIDER_RESULT}" == 
"skipped" ]]; then
             echo "⏭️ ExternalAccountCredentialProvider tests skipped (no 
secrets)" >> $GITHUB_STEP_SUMMARY
           else
             echo "❌ ExternalAccountCredentialProvider tests failed" >> 
$GITHUB_STEP_SUMMARY
           fi
 
-          if [[ "${{ needs.test_impersonated_service_account_provider.result 
}}" == "success" ]]; then
+          if [[ "${NEEDS_TEST_IMPERSONATED_SERVICE_ACCOUNT_PROVIDER_RESULT}" 
== "success" ]]; then
             echo "✅ ImpersonatedServiceAccountCredentialProvider tests passed" 
>> $GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.test_impersonated_service_account_provider.result 
}}" == "skipped" ]]; then
+          elif [[ "${NEEDS_TEST_IMPERSONATED_SERVICE_ACCOUNT_PROVIDER_RESULT}" 
== "skipped" ]]; then
             echo "⏭️ ImpersonatedServiceAccountCredentialProvider tests 
skipped (no secrets)" >> $GITHUB_STEP_SUMMARY
           else
             echo "❌ ImpersonatedServiceAccountCredentialProvider tests failed" 
>> $GITHUB_STEP_SUMMARY
           fi
 
-          if [[ "${{ needs.test_vm_metadata_provider.result }}" == "success" 
]]; then
+          if [[ "${NEEDS_TEST_VM_METADATA_PROVIDER_RESULT}" == "success" ]]; 
then
             echo "✅ VmMetadataCredentialProvider tests passed" >> 
$GITHUB_STEP_SUMMARY
-          elif [[ "${{ needs.test_vm_metadata_provider.result }}" == "skipped" 
]]; then
+          elif [[ "${NEEDS_TEST_VM_METADATA_PROVIDER_RESULT}" == "skipped" ]]; 
then
             echo "⏭️ VmMetadataCredentialProvider tests skipped (no secrets)" 
>> $GITHUB_STEP_SUMMARY
           else
             echo "❌ VmMetadataCredentialProvider tests failed" >> 
$GITHUB_STEP_SUMMARY
@@ -365,16 +389,33 @@ jobs:
 
           # Overall status
           echo "" >> $GITHUB_STEP_SUMMARY
-          if [[ "${{ needs.unit_test.result }}" == "success" ]] && \
-             ( [[ "${{ needs.signing_test.result }}" == "success" ]] || [[ 
"${{ needs.signing_test.result }}" == "skipped" ]] ) && \
-             ( [[ "${{ needs.test_default_provider.result }}" == "success" ]] 
|| [[ "${{ needs.test_default_provider.result }}" == "skipped" ]] ) && \
-             ( [[ "${{ needs.test_static_provider.result }}" == "success" ]] 
|| [[ "${{ needs.test_static_provider.result }}" == "skipped" ]] ) && \
-             ( [[ "${{ needs.test_authorized_user_provider.result }}" == 
"success" ]] || [[ "${{ needs.test_authorized_user_provider.result }}" == 
"skipped" ]] ) && \
-             ( [[ "${{ needs.test_external_account_provider.result }}" == 
"success" ]] || [[ "${{ needs.test_external_account_provider.result }}" == 
"skipped" ]] ) && \
-             ( [[ "${{ needs.test_impersonated_service_account_provider.result 
}}" == "success" ]] || [[ "${{ 
needs.test_impersonated_service_account_provider.result }}" == "skipped" ]] ) 
&& \
-             ( [[ "${{ needs.test_vm_metadata_provider.result }}" == "success" 
]] || [[ "${{ needs.test_vm_metadata_provider.result }}" == "skipped" ]] ); then
+          if [[ "${NEEDS_UNIT_TEST_RESULT}" == "success" ]] && \
+             ( [[ "${NEEDS_SIGNING_TEST_RESULT}" == "success" ]] || [[ 
"${NEEDS_SIGNING_TEST_RESULT}" == "skipped" ]] ) && \
+             ( [[ "${NEEDS_TEST_DEFAULT_PROVIDER_RESULT}" == "success" ]] || 
[[ "${NEEDS_TEST_DEFAULT_PROVIDER_RESULT}" == "skipped" ]] ) && \
+             ( [[ "${NEEDS_TEST_STATIC_PROVIDER_RESULT}" == "success" ]] || [[ 
"${NEEDS_TEST_STATIC_PROVIDER_RESULT}" == "skipped" ]] ) && \
+             ( [[ "${NEEDS_TEST_AUTHORIZED_USER_PROVIDER_RESULT}" == "success" 
]] || [[ "${NEEDS_TEST_AUTHORIZED_USER_PROVIDER_RESULT}" == "skipped" ]] ) && \
+             ( [[ "${NEEDS_TEST_EXTERNAL_ACCOUNT_PROVIDER_RESULT}" == 
"success" ]] || [[ "${NEEDS_TEST_EXTERNAL_ACCOUNT_PROVIDER_RESULT}" == 
"skipped" ]] ) && \
+             ( [[ "${NEEDS_TEST_IMPERSONATED_SERVICE_ACCOUNT_PROVIDER_RESULT}" 
== "success" ]] || [[ 
"${NEEDS_TEST_IMPERSONATED_SERVICE_ACCOUNT_PROVIDER_RESULT}" == "skipped" ]] ) 
&& \
+             ( [[ "${NEEDS_TEST_VM_METADATA_PROVIDER_RESULT}" == "success" ]] 
|| [[ "${NEEDS_TEST_VM_METADATA_PROVIDER_RESULT}" == "skipped" ]] ); then
             echo "### ✅ All tests completed successfully" >> 
$GITHUB_STEP_SUMMARY
           else
             echo "### ❌ Some tests failed" >> $GITHUB_STEP_SUMMARY
             exit 1
           fi
+
+        env:
+          NEEDS_UNIT_TEST_RESULT: ${{ needs.unit_test.result }}
+
+          NEEDS_SIGNING_TEST_RESULT: ${{ needs.signing_test.result }}
+
+          NEEDS_TEST_DEFAULT_PROVIDER_RESULT: ${{ 
needs.test_default_provider.result }}
+
+          NEEDS_TEST_STATIC_PROVIDER_RESULT: ${{ 
needs.test_static_provider.result }}
+
+          NEEDS_TEST_AUTHORIZED_USER_PROVIDER_RESULT: ${{ 
needs.test_authorized_user_provider.result }}
+
+          NEEDS_TEST_EXTERNAL_ACCOUNT_PROVIDER_RESULT: ${{ 
needs.test_external_account_provider.result }}
+
+          NEEDS_TEST_IMPERSONATED_SERVICE_ACCOUNT_PROVIDER_RESULT: ${{ 
needs.test_impersonated_service_account_provider.result }}
+
+          NEEDS_TEST_VM_METADATA_PROVIDER_RESULT: ${{ 
needs.test_vm_metadata_provider.result }}
diff --git a/.github/workflows/huaweicloud_obs.yml 
b/.github/workflows/huaweicloud_obs.yml
index bac9332..9183262 100644
--- a/.github/workflows/huaweicloud_obs.yml
+++ b/.github/workflows/huaweicloud_obs.yml
@@ -29,16 +29,20 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
   cancel-in-progress: true
 
+permissions: {}
+
 jobs:
   unit_test:
     runs-on: ubuntu-latest
     permissions:
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Test
         working-directory: ./services/huaweicloud-obs
         run: cargo test --no-fail-fast
         env:
           RUST_LOG: DEBUG
-          RUST_BACKTRACE: full
\ No newline at end of file
+          RUST_BACKTRACE: full
diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml
index a8c64e3..fa24cb0 100644
--- a/.github/workflows/oracle.yml
+++ b/.github/workflows/oracle.yml
@@ -29,13 +29,17 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
   cancel-in-progress: true
 
+permissions: {}
+
 jobs:
   unit_test:
     runs-on: ubuntu-latest
     permissions:
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Test
         working-directory: ./services/oracle
         run: cargo test --no-fail-fast
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ccf49a7..dacea7c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,16 +21,20 @@ on:
   workflow_dispatch:
   push:
     # only for formal releases, not for release candidates
-    tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ]
+    tags: ["v[0-9]+.[0-9]+.[0-9]+"]
 
 env:
   CARGO_TERM_COLOR: always
   CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
 
+permissions: {}
+
 jobs:
   publish:
     name: Publish Workspace
     runs-on: ubuntu-24.04
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - run: cargo publish --workspace
diff --git a/.github/workflows/tencent_cos.yml 
b/.github/workflows/tencent_cos.yml
index df0dc93..0d4a1a9 100644
--- a/.github/workflows/tencent_cos.yml
+++ b/.github/workflows/tencent_cos.yml
@@ -35,7 +35,9 @@ jobs:
     permissions:
       id-token: write
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
       - name: Test
         working-directory: ./services/tencent-cos
         run: cargo test --no-fail-fast
@@ -55,10 +57,12 @@ jobs:
       id-token: "write"
     if: github.event_name == 'push' || 
!github.event.pull_request.head.repo.fork
     steps:
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 
v6.0.2
+        with:
+          persist-credentials: false
 
       - name: Get Id Token
-        uses: actions/github-script@v8
+        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # 
v8.0.0
         id: idtoken
         with:
           script: |

Reply via email to