Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,35 +1,40 @@
# 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 Ruby dependencies up to date
- package-ecosystem: "bundler"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
target-branch: "develop"
interval: weekly
day: tuesday
time: "06:00"
timezone: Europe/Bucharest
open-pull-requests-limit: 0
labels:
- "dependabot-security"
- "ruby dependencies"
groups:
bundler:
applies-to: version-updates
bundler-security:
applies-to: security-updates
patterns:
- "*"

# Keep the Github Actions dependencies up to date
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
target-branch: "develop"
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:
- "*"
3 changes: 2 additions & 1 deletion .github/workflows/auto_assign_ci.yaml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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"
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,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`
Expand All @@ -71,7 +71,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4.37.8
uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
Expand Down Expand Up @@ -100,6 +100,6 @@ jobs:
exit 1

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4.37.8
uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
category: "/language:${{matrix.language}}"
50 changes: 50 additions & 0 deletions .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -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 }}
59 changes: 40 additions & 19 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,36 @@ 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: ${{ github.event.inputs.tag }}
ref: refs/tags/${{ github.event.inputs.tag }}

persist-credentials: false
- name: Verify tag and gem version
run: |
TAG="${{ github.event.inputs.tag }}"
if [ -z "$TAG" ]; then
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
Expand All @@ -43,7 +56,14 @@ jobs:
echo "Error: lib/zerobounce/version.rb ($PKG_VERSION) does not match tag ($TAG)."
exit 1
fi
echo "Publishing tag: $TAG (zerobounce-sdk@$PKG_VERSION)"

- 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"

test:
name: Test
Expand All @@ -54,12 +74,12 @@ jobs:
ZEROBOUNCE_API_KEY: "invalid_key_for_tests"
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 Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@651ff0d62c5c79bed6d53ec518387aae20e72c1a # v1
with:
ruby-version: "3.2"
bundler-cache: true
Expand All @@ -69,7 +89,7 @@ jobs:

publish:
name: Build and publish to RubyGems
needs: [test]
needs: [validate-tag, test]
if: ${{ !cancelled() && !failure() }}
runs-on: ubuntu-latest
environment: release
Expand All @@ -78,18 +98,18 @@ jobs:
contents: read
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 Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@651ff0d62c5c79bed6d53ec518387aae20e72c1a # v1
with:
ruby-version: "3.2"
bundler-cache: true

- name: Configure RubyGems credentials
uses: rubygems/configure-rubygems-credentials@v2.1.0
uses: rubygems/configure-rubygems-credentials@dc5a8d8553e6ee01fc26761a49e99e733d17954a # v2.1.0
with:
api-token: ${{ secrets.RUBYGEMS_API_TOKEN }}

Expand All @@ -104,28 +124,29 @@ 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 if missing
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ github.event.inputs.tag }}"
if gh release view "$TAG" --repo "${{ github.repository }}" >/dev/null 2>&1; then
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "Release $TAG already exists, skipping."
else
gh release create "$TAG" \
--repo "${{ github.repository }}" \
--repo "$GITHUB_REPOSITORY" \
--title "$TAG" \
--generate-notes
fi
6 changes: 4 additions & 2 deletions .github/workflows/sdk_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ jobs:
env:
ZEROBOUNCE_API_KEY: "invalid_key_for_tests"
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Ruby
uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@651ff0d62c5c79bed6d53ec518387aae20e72c1a # v1
with:
ruby-version: "3.2"
bundler-cache: true
Expand Down
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ RUN gem install bundler -v 2.4.22 && \
# Dummy key for VCR/cassette-based specs; override with env for live API
ENV ZEROBOUNCE_API_KEY="${ZEROBOUNCE_API_KEY:-invalid_key_for_tests}"


USER 65532:65532

CMD ["bundle", "_2.4.22_", "exec", "rspec"]
3 changes: 2 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ PATH
remote: .
specs:
zerobounce-sdk (2.1.8)
dotenv
rest-client (~> 2.1)

GEM
Expand Down Expand Up @@ -107,13 +106,15 @@ GEM
PLATFORMS
arm64-darwin-24
arm64-darwin-25
arm64-darwin-27
x86_64-linux

DEPENDENCIES
addressable (>= 2.8.10)
base64
bigdecimal
bundler (~> 2.4.6)
dotenv
logger
ostruct
pry (~> 0.14.1)
Expand Down
11 changes: 9 additions & 2 deletions lib/zerobounce/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

require 'rest-client'
require 'dotenv'
require_relative 'api_urls'

module Zerobounce
Expand Down Expand Up @@ -30,13 +29,21 @@ class Configuration
attr_accessor :headers, :apikey, :api_root_url, :bulk_api_root_url, :valid_statuses, :mock

def initialize(mock = false)
File.file?('.env') ? Dotenv.load('.env') : Dotenv.load
self.apikey = ENV['ZEROBOUNCE_API_KEY']
self.api_root_url = ENV['ZEROBOUNCE_API_URL'] || ApiUrls::DEFAULT_URL
self.bulk_api_root_url = ENV['ZEROBOUNCE_BULK_API_URL'] || ApiUrls::BULK_DEFAULT_URL
self.valid_statuses = %i[valid catch_all accept_all]
self.headers = { user_agent: "ZerobounceRubyGem/#{Zerobounce::VERSION}" }
self.mock = mock
end

# Keep the API key out of logs, consoles and error pages that call #inspect.
def inspect
vars = instance_variables.map do |var|
value = var == :@apikey && apikey ? '[FILTERED]' : instance_variable_get(var).inspect
"#{var}=#{value}"
end
"#<#{self.class.name} #{vars.join(', ')}>"
end
end
end
6 changes: 2 additions & 4 deletions zerobounce.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
spec.homepage = 'https://zerobounce.net'
spec.license = 'MIT'

spec.files = `git ls-files -z`.split("\x0").reject do |f|
f.match(%r{^(test|spec|features)/})
end
spec.files = Dir['lib/**/*', 'README.md', 'LICENSE*', 'CHANGELOG*'].select { |f| File.file?(f) }
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']
Expand All @@ -27,8 +25,8 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
spec.required_ruby_version = '>= 2.5'

spec.add_dependency 'rest-client', '~>2.1'
spec.add_dependency 'dotenv'

spec.add_development_dependency 'dotenv'
spec.add_development_dependency 'base64' # stdlib gem on Ruby 3.4+
spec.add_development_dependency 'bigdecimal' # required by crack (webmock) on Ruby 3.4+
spec.add_development_dependency 'ostruct' # stdlib gem on Ruby 3.5+ (json/simplecov load chain)
Expand Down
Loading