diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e0e2a35..26714da 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,50 +1,57 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#versioning-strategy +# Dependabot: security updates only (no version-update PRs). +# Grouped security PRs open weekly on Tuesday morning (Europe/Bucharest). +# Auto-merge: .github/workflows/dependabot-auto-merge.yml (on PR + Tuesday cron). +# https://docs.github.com/en/code-security/dependabot/dependabot-security-updates version: 2 updates: - # Keep the Java dependencies up to date - - package-ecosystem: "maven" # See documentation for possible values - directory: "/" # Location of package manifests + - package-ecosystem: "maven" + directory: "/" schedule: - interval: "weekly" - day: "monday" - target-branch: "master" + interval: weekly + day: tuesday + time: "06:00" + timezone: Europe/Bucharest + open-pull-requests-limit: 0 labels: + - "dependabot-security" - "java dependencies" groups: - java: - applies-to: version-updates + maven-security: + applies-to: security-updates patterns: - - "*" # A wildcard that matches all dependencies in the package - - # Keep the Java dependencies up to date - - package-ecosystem: "maven" # See documentation for possible values - directory: "/zero-bounce-sdk/" # Location of package manifests + - "*" + + - package-ecosystem: "maven" + directory: "/zero-bounce-sdk/" schedule: - interval: "weekly" - day: "monday" - target-branch: "master" + interval: weekly + day: tuesday + time: "06:00" + timezone: Europe/Bucharest + open-pull-requests-limit: 0 labels: + - "dependabot-security" - "java dependencies" groups: - java: - applies-to: version-updates + maven-sdk-security: + applies-to: security-updates patterns: - - "*" # A wildcard that matches all dependencies in the package + - "*" - # Keep the Github Actions dependencies up to date - - package-ecosystem: "github-actions" # See documentation for possible values - directory: "/" # Location of package manifests + - package-ecosystem: "github-actions" + directory: "/" schedule: - interval: "weekly" - day: "monday" - target-branch: "master" + interval: weekly + day: tuesday + time: "06:00" + timezone: Europe/Bucharest + open-pull-requests-limit: 0 labels: + - "dependabot-security" - "github dependencies" groups: - github: - applies-to: version-updates + github-actions-security: + applies-to: security-updates patterns: - - "*" # A wildcard that matches all dependencies in the package + - "*" diff --git a/.github/workflows/auto_assign_ci.yaml b/.github/workflows/auto_assign_ci.yaml index 0e6c515..59aa47c 100644 --- a/.github/workflows/auto_assign_ci.yaml +++ b/.github/workflows/auto_assign_ci.yaml @@ -1,4 +1,5 @@ name: Auto Assign +# Audit 2026-10-14: pull_request_target — do not checkout the PR head here; configuration-path only. on: pull_request_target: @@ -16,6 +17,6 @@ jobs: name: Auto assign (me only) runs-on: ubuntu-latest steps: - - uses: kentaro-m/auto-assign-action@v2.0.2 + - uses: kentaro-m/auto-assign-action@0a2c53d3721e4c5cfcce6afd4014aecc337979f6 # v2.0.2 with: configuration-path: ".github/auto_assign.yml" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c33fbb8..6d7ccec 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -63,7 +63,7 @@ jobs: # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Add any setup steps before running the `github/codeql-action/init` action. # This includes steps like installing compilers or runtimes (`actions/setup-node` @@ -73,7 +73,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v4.37.9 + uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.9 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -102,6 +102,6 @@ jobs: exit 1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4.37.9 + uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.9 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..138a59d --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,50 @@ +name: Dependabot security auto-merge + +on: + pull_request: + types: [opened, synchronize, reopened] + schedule: + - cron: "0 6 * * 2" + timezone: Europe/Bucharest + +permissions: + contents: write + pull-requests: write + +jobs: + approve-and-queue-merge: + runs-on: ubuntu-latest + if: >- + github.event_name == 'pull_request' + && github.event.pull_request.user.login == 'dependabot[bot]' + steps: + - name: Approve Dependabot pull request + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Enable auto-merge when checks pass + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + weekly-merge-ready: + runs-on: ubuntu-latest + if: github.event_name == 'schedule' + steps: + - name: Approve and queue merge for open Dependabot PRs + run: | + set -euo pipefail + mapfile -t urls < <(gh pr list --author app/dependabot --state open --json url --jq '.[].url') + if [ "${#urls[@]}" -eq 0 ]; then + echo "No open Dependabot pull requests." + exit 0 + fi + for url in "${urls[@]}"; do + gh pr review --approve "$url" || true + gh pr merge --auto --merge "$url" || true + done + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 56cd28a..432bbb0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,14 +13,27 @@ permissions: jobs: validate-tag: + outputs: + tag_sha: ${{ steps.tag_sha.outputs.sha }} name: Validate tag runs-on: ubuntu-latest steps: + - name: Validate tag input + env: + TAG: ${{ github.event.inputs.tag }} + run: | + re='^v?[0-9]+\.[0-9]+\.[0-9]+([.+-][0-9A-Za-z.-]+)?$' + if [[ ! "$TAG" =~ $re ]]; then + echo "Error: the tag input must be a release tag such as v1.2.3." + exit 1 + fi + - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - + ref: refs/tags/${{ github.event.inputs.tag }} + persist-credentials: false - name: Verify tag exists run: | TAG="${{ github.event.inputs.tag }}" @@ -28,11 +41,18 @@ jobs: echo "Error: Tag is required." exit 1 fi - if ! git rev-parse "$TAG" >/dev/null 2>&1; then + if ! git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then echo "Error: Tag '$TAG' does not exist." exit 1 fi - echo "Publishing tag: $TAG" + + - name: Record tag commit SHA + id: tag_sha + env: + TAG: ${{ github.event.inputs.tag }} + run: | + SHA=$(git rev-parse "refs/tags/$TAG^{commit}") + echo "sha=$SHA" >> "$GITHUB_OUTPUT" publish: name: Test, release build and publish @@ -41,12 +61,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout tag - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ github.event.inputs.tag }} - + ref: ${{ needs.validate-tag.outputs.tag_sha }} + persist-credentials: false - name: Set up Maven Central Repository - uses: actions/setup-java@v6 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6 with: java-version: 21 distribution: 'temurin' @@ -65,20 +85,21 @@ jobs: release: name: Create GitHub Release - needs: [publish] + needs: [validate-tag, publish] if: ${{ !cancelled() && !failure() }} runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ github.event.inputs.tag }} + ref: ${{ needs.validate-tag.outputs.tag_sha }} fetch-depth: 0 + persist-credentials: false - name: Create Release - uses: softprops/action-gh-release@v3.0.2 + uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3.0.2 with: tag_name: ${{ github.event.inputs.tag }} name: ${{ github.event.inputs.tag }} diff --git a/.github/workflows/sdk_ci.yml b/.github/workflows/sdk_ci.yml index 6b70782..97a74c0 100644 --- a/.github/workflows/sdk_ci.yml +++ b/.github/workflows/sdk_ci.yml @@ -15,10 +15,12 @@ jobs: name: Test & Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Set up Maven Central Repository - uses: actions/setup-java@v6 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6 with: java-version: 21 distribution: 'temurin' diff --git a/Dockerfile b/Dockerfile index 977e92a..19f0a76 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,7 @@ WORKDIR /app/zero-bounce-sdk RUN mvn -q test # Default: run tests (re-run in case of docker run without build) + +USER 65532:65532 + CMD ["mvn", "-q", "test"] diff --git a/zero-bounce-sdk/src/main/java/com/zerobounce/ZeroBounceSDK.java b/zero-bounce-sdk/src/main/java/com/zerobounce/ZeroBounceSDK.java index 0e8f004..c6e19df 100644 --- a/zero-bounce-sdk/src/main/java/com/zerobounce/ZeroBounceSDK.java +++ b/zero-bounce-sdk/src/main/java/com/zerobounce/ZeroBounceSDK.java @@ -1167,6 +1167,9 @@ private void sendRequest( HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("Accept", "application/json"); // con.setRequestProperty("Content-Type", "application/json"); + // Timeouts must be set before connect(); the POST branch connects explicitly below. + con.setConnectTimeout(timeoutInMillis); + con.setReadTimeout(timeoutInMillis); String httpMethod; if (body == null) { @@ -1190,9 +1193,6 @@ private void sendRequest( logDebug("ZeroBounceSDK::sendRequest executing " + httpMethod + " " + urlPath); - con.setConnectTimeout(timeoutInMillis); - con.setReadTimeout(timeoutInMillis); - int status = con.getResponseCode(); logDebug("ZeroBounceSDK::sendRequest status: " + status); Reader streamReader;