Skip to content

Dev -> Stable 2.0.4 - #179

Merged
liquidsec merged 20 commits into
stablefrom
dev
Nov 10, 2026
Merged

liquidsec merged 20 commits into
stablefrom
dev

Conversation

@liquidsec

Copy link
Copy Markdown
Contributor

Patch release of current dev, version 2.0.4. The version bump is #178.

pjhartlieb and others added 20 commits November 5, 2026 14:17
stable now requires python / passed, rust / passed, clippy-python-feature and guard / release ready, so the job that reported the old python-tests and rust-tests contexts is no longer needed.
…k-names

ci: drop the legacy check names from tests.yml
…tory with 5 updates

Bumps the github-actions-minor-patch group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions-rust-lang/setup-rust-toolchain](https://github.com/actions-rust-lang/setup-rust-toolchain) | `2.0.0` | `2.0.1` |
| [actions/setup-python](https://github.com/actions/setup-python) | `7.0.0` | `7.1.0` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.1` | `7.0.2` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `8.0.1` | `8.0.2` |
| [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) | `1.14.2` | `1.14.3` |



Updates `actions-rust-lang/setup-rust-toolchain` from 2.0.0 to 2.0.1
- [Release notes](https://github.com/actions-rust-lang/setup-rust-toolchain/releases)
- [Changelog](https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/CHANGELOG.md)
- [Commits](actions-rust-lang/setup-rust-toolchain@ecabd13...a188e68)

Updates `actions/setup-python` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@5fda3b9...6d4fd22)

Updates `actions/upload-artifact` from 7.0.1 to 7.0.2
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@043fb46...cf430e0)

Updates `actions/download-artifact` from 8.0.1 to 8.0.2
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@3e5f45b...9000827)

Updates `pypa/gh-action-pypi-publish` from 1.14.2 to 1.14.3
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](pypa/gh-action-pypi-publish@dc37677...7245906)

---
updated-dependencies:
- dependency-name: actions-rust-lang/setup-rust-toolchain
  dependency-version: 2.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions-minor-patch
- dependency-name: actions/download-artifact
  dependency-version: 8.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions-minor-patch
- dependency-name: actions/setup-python
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions-minor-patch
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions-minor-patch
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
…h 2 updates

Bumps the uv-minor-patch group with 2 updates in the / directory: [maturin](https://github.com/pyo3/maturin) and [ruff](https://github.com/astral-sh/ruff).


Updates `maturin` from 1.10.2 to 1.16.0
- [Release notes](https://github.com/pyo3/maturin/releases)
- [Changelog](https://github.com/PyO3/maturin/blob/main/Changelog.md)
- [Commits](PyO3/maturin@v1.10.2...v1.16.0)

Updates `ruff` from 0.14.8 to 0.17.3
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](astral-sh/ruff@0.14.8...0.17.3)

---
updated-dependencies:
- dependency-name: maturin
  dependency-version: 1.16.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: uv-minor-patch
- dependency-name: ruff
  dependency-version: 0.17.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: uv-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Calls release-workflows dev-security.yml (v1.1.0), the security checks policy rule 3 requires on dev. Fixes what zizmor reports: the CLA triggers are marked as reviewed (cla-reusable.yml never checks out pull request code), benchmark checkouts drop persisted credentials, and publish.yml's local workflow calls are marked as reviewed (same-repository calls on stable).
zizmor dependabot-cooldown (the workflow-lint check): version updates now wait 7 days after a release is published, so a compromised release has time to be caught and pulled before it is proposed here. Security updates are not delayed.
…ctions/dev/github-actions-minor-patch-5b8456e292

build(deps): bump the github-actions-minor-patch group across 1 directory with 5 updates
ci: run dependency review and workflow lint on pull requests
Bumps the github-actions-major group with 1 update in the / directory: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv).


Updates `astral-sh/setup-uv` from 7.6.0 to 10.3.3
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@37802ad...68559e9)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 10.3.3
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions-major
...

Signed-off-by: dependabot[bot] <support@github.com>
…ctions/dev/github-actions-major-7313d4f700

build(deps): bump astral-sh/setup-uv from 7.6.0 to 10.3.3 in the github-actions-major group across 1 directory
Bumps [pygments](https://github.com/pygments/pygments) from 2.19.2 to 2.20.0.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](pygments/pygments@2.19.2...2.20.0)

---
updated-dependencies:
- dependency-name: pygments
  dependency-version: 2.20.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
hickory-resolver 0.26 replaced NameServerConfig::socket_addr with an
`ip` field, so get_system_resolvers() reads that instead.
…er-0.26

Bump hickory-resolver from 0.25.2 to 0.26.2
ruff 0.17 formats Python code blocks in Markdown, so ruff format --check
failed on two mock_dns examples in README.md.
…v-minor-patch-ed6531f1dc

build(deps-dev): bump the uv-minor-patch group across 1 directory with 2 updates
…nts-2.20.0

build(deps): bump pygments from 2.19.2 to 2.20.0
System resolvers were formatted as "{ip}:53" and parsed back, which
turns 2001:db8::1 into the different address 2001:db8::1:53 and rejects
addresses with no zero run. Build the socket addresses directly instead.

Closes #176
…olvers

fix: keep IPv6 system resolver addresses intact
chore(release): bump version to 2.0.4
@github-actions

Copy link
Copy Markdown

DNS Resolver Benchmark

this PR @ 764c362 against stable @ 3813bfb, base → head, median of 3 interleaved rounds. Bold is significant across all 56 comparisons (Benjamini-Hochberg at 1%); the rest is noise.

regime qps unanswered p99 attempts/query
ceiling/1-resolver 24,592 → 24,522 (-0.3%) 0.00% → 0.00% 0.811s → 0.813s (+0.3%) 1.00 → 1.00
pool/32-resolvers 24,571 → 24,153 (-1.7%) 0.00% → 0.00% 0.812s → 0.826s (+1.7%) 1.00 → 1.00
pool/32-persistent 28,056 → 27,875 (-0.6%) 0.00% → 0.00% 0.711s → 0.715s (+0.6%) 1.00 → 1.00
impaired/10%-loss 199 → 200 (+0.8%) 0.00% → 0.00% 8.129s → 8.131s (+0.0%) 1.11 → 1.11
impaired/20%-REFUSED 3,460 → 3,463 (+0.1%) 0.00% → 0.00% 0.578s → 0.577s (-0.1%) 1.24 → 1.24
impaired/50ms-latency 622 → 621 (-0.1%) 0.00% → 0.00% 3.216s → 3.219s (+0.1%) 1.00 → 1.00
impaired/20%-then-2.5%-dead-names 256 → 263 (+2.5%) 5.43% → 5.43% 9.919s → 10.910s (+10.0%) 1.05 → 1.05
All metrics
regime p50 p100 sockets conntrack
ceiling/1-resolver 0.438s → 0.441s (+0.7%) 0.813s → 0.815s (+0.3%) 42 → 42 (+0.0%) 14,757 → 11,037 (-25%)
pool/32-resolvers 0.439s → 0.442s (+0.7%) 0.814s → 0.828s (+1.7%) 73 → 74 (+1.4%) 19,047 → 19,365 (+1.7%)
pool/32-persistent 0.387s → 0.387s (+0.1%) 0.713s → 0.717s (+0.6%) 42 → 42 (+0.0%) 31 → 29 (-6.5%)
impaired/10%-loss 4.276s → 4.273s (-0.1%) 10.059s → 9.984s (-0.7%) 46 → 46 (+0.0%) 2,088 → 2,062 (-1.2%)
impaired/20%-REFUSED 0.414s → 0.414s (+0.0%) 0.578s → 0.577s (-0.1%) 46 → 46 (+0.0%) 2,217 → 2,182 (-1.6%)
impaired/50ms-latency 1.837s → 1.837s (-0.0%) 3.216s → 3.219s (+0.1%) 46 → 46 (+0.0%) 516 → 1,159 (+125%)
impaired/20%-then-2.5%-dead-names 4.371s → 3.744s (-14%) 11.702s → 11.411s (-2.5%) 39 → 39 (+0.0%) 419 → 12 (-97%)

@en0f en0f left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 764c362.

🟢 Dropping the legacy check names is safe for stable

The removed required job only existed to report python-tests (3.x) and rust-tests for the old ruleset. The stable ruleset now requires python / passed, rust / passed, clippy-python-feature and guard / release ready, classic branch protection on stable requires nothing, and all four reported success at this head. Nothing stable requires is left unreported, and the alls-green shim goes with it, as the removed comment planned.

🟢 The hickory-resolver 0.26 bump changes no public type, so 2.0.4 is an honest patch

hickory_resolver is used only in src/utils.rs for system_conf, and src/lib.rs re-exports none of it. get_system_resolvers keeps its Result<Vec<IpAddr>, BlastDNSError> signature, and ns.socket_addr.ip() to ns.ip is just the 0.26 field rename. Crate and wheel users see no type change, which is what a patch version promises.

🟢 benchmark.yml no longer leaves the token in .git/config while PR code builds

Both checkouts in benchmark.yml now set persist-credentials: false, and the job goes on to run uv sync and maturin develop on the PR's own build code. The GITHUB_TOKEN is no longer written into .git/config where that code could read it (per standards/ci.md § Permissions). The job still holds pull-requests: write for the report comment, so this closes the easy path rather than every path.

Reproduce this review
# save the script below as verify-179.sh and the patch as control-179.patch, then:
bash verify-179.sh blacklanternsecurity/blastdns 764c362544edaff3948d8c26419afab93b4b44de
# expected: SUMMARY 7 PASS, 0 FAIL, 0 SKIP, 0 BROKEN
# control:  bash verify-179.sh blacklanternsecurity/blastdns 764c362544edaff3948d8c26419afab93b4b44de control-179.patch   -> V01=FAIL V02=FAIL V03=FAIL V04=FAIL
#!/usr/bin/env bash
# verify-179.sh: reproducible checks for blacklanternsecurity/blastdns#179 (Dev -> Stable 2.0.4)
# Usage: bash verify-179.sh <owner/repo> <sha> [<control-patch>]
# Changes nothing outside a mktemp directory and nothing on GitHub (PR-VF-02).
#
# CONTROL: patch control-179.patch
# CONTROL-EXPECT: V01=FAIL V02=FAIL V03=FAIL V04=FAIL
# AUTHOR-CODE: none
set -uo pipefail

REPO="${1:?owner/repo}"; SHA="${2:?sha}"; PATCH="${3:-}"
PASS=0; FAIL=0; SKIP=0; BROKEN=0
pass()   { echo "PASS $1 $2"; PASS=$((PASS+1)); }
fail()   { echo "FAIL $1 $2 -- $3"; FAIL=$((FAIL+1)); }
skip()   { echo "SKIP $1 $2 -- $3"; SKIP=$((SKIP+1)); }
broken() { echo "BROKEN $1 $2 -- $3"; BROKEN=$((BROKEN+1)); }
summary() { echo "SUMMARY $PASS PASS, $FAIL FAIL, $SKIP SKIP, $BROKEN BROKEN"; [ "$FAIL" -eq 0 ] && [ "$BROKEN" -eq 0 ]; }

echo "script_sha256 $(shasum -a 256 "$0" | cut -d' ' -f1)"
echo "git $(git --version | cut -d' ' -f3)"
echo "gh $(gh --version | head -1 | cut -d' ' -f3)"
echo "jq $(jq --version)"

if [ -n "$PATCH" ]; then PATCH="$(cd "$(dirname "$PATCH")" && pwd)/$(basename "$PATCH")"; fi
WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
export GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 GIT_TERMINAL_PROMPT=0
# Every git call (including blob fetches of the partial clone) gets the gh helper.
export GIT_CONFIG_COUNT=2 GIT_CONFIG_KEY_0=credential.helper GIT_CONFIG_VALUE_0= \
       GIT_CONFIG_KEY_1=credential.helper GIT_CONFIG_VALUE_1='!gh auth git-credential'
git clone --quiet --filter=blob:none --no-checkout "https://github.com/$REPO.git" "$WORK/src" || { broken V00 "clone" "clone failed"; summary; exit 1; }
cd "$WORK/src"
git cat-file -e "$SHA^{commit}" 2>/dev/null || git fetch --quiet origin "+refs/pull/*/head:refs/remotes/pr/*" || true
git checkout --quiet --detach "$SHA" || { broken V00 "checkout $SHA" "checkout failed"; summary; exit 1; }
[ "$(git rev-parse HEAD)" = "$SHA" ] || { broken V00 "HEAD is $SHA" "HEAD mismatch"; summary; exit 1; }
if [ -n "$PATCH" ]; then git apply "$PATCH" || { broken V00 "apply control patch" "git apply failed"; summary; exit 1; }; fi

# ---- checks: each line states the desired property --------------------------

# V01: the hickory-resolver 0.25 -> 0.26 bump stays internal, so a patch version is honest.
users="$(grep -rl 'hickory_resolver' src | sort | tr '\n' ' ')"
if [ "$users" = "src/utils.rs " ] && ! grep -Eq '^pub use .*hickory_resolver' src/lib.rs; then
  pass V01 "hickory_resolver is used only in src/utils.rs and never re-exported from src/lib.rs"
else
  fail V01 "hickory_resolver is used only in src/utils.rs and never re-exported from src/lib.rs" "files: ${users:-none}; lib.rs re-exports: $(grep -c 'hickory_resolver' src/lib.rs)"
fi

# V02: every checkout in benchmark.yml (which builds and runs PR code) drops the token.
W=.github/workflows/benchmark.yml
n_co="$(grep -c 'uses: actions/checkout@' "$W")"
n_pc="$(grep -c 'persist-credentials: false' "$W")"
if [ "$n_co" -ge 1 ] && [ "$n_co" = "$n_pc" ]; then
  pass V02 "every actions/checkout in benchmark.yml sets persist-credentials: false ($n_co of $n_co)"
else
  fail V02 "every actions/checkout in benchmark.yml sets persist-credentials: false" "$n_pc of $n_co"
fi

# V03: the release version is 2.0.4 in Cargo.toml and Cargo.lock, and the wheel reads it.
v_toml="$(awk -F'"' '/^\[package\]/{p=1} p && /^version = /{print $2; exit}' Cargo.toml)"
v_lock="$(awk -F'"' '/^name = "blastdns"$/{getline; print $2; exit}' Cargo.lock)"
if [ "$v_toml" = "2.0.4" ] && [ "$v_lock" = "2.0.4" ] && grep -q '^dynamic = \["version"\]' pyproject.toml; then
  pass V03 "Cargo.toml and Cargo.lock both say 2.0.4 and pyproject.toml takes the version from Cargo"
else
  fail V03 "Cargo.toml and Cargo.lock both say 2.0.4 and pyproject.toml takes the version from Cargo" "toml=$v_toml lock=$v_lock"
fi

# V04: tests.yml no longer reports the legacy contexts.
LEGACY='"python-tests \(|[[ ,]rust-tests[],]'   # the context names, not the reusable *-tests.yml files
if ! grep -Eq "$LEGACY" .github/workflows/tests.yml; then
  pass V04 "tests.yml reports no legacy python-tests / rust-tests contexts"
else
  fail V04 "tests.yml reports no legacy python-tests / rust-tests contexts" "$(grep -Eo "$LEGACY" .github/workflows/tests.yml | head -3 | tr '\n' ' ')"
fi

# V05: every status check the stable ruleset requires reported success at this SHA,
# so dropping the legacy names leaves nothing required unreported.
req="$(gh api --method GET "repos/$REPO/rules/branches/stable" --jq '.[] | select(.type=="required_status_checks") | .parameters.required_status_checks[].context' 2>/dev/null | sort -u)"
runs="$(gh api --method GET "repos/$REPO/commits/$SHA/check-runs" -F per_page=100 --jq '.check_runs[] | select(.conclusion=="success") | .name' 2>/dev/null | sort -u)"
if [ -z "$req" ] || [ -z "$runs" ]; then
  skip V05 "every context the stable ruleset requires reported success at $SHA" "API read returned nothing"
else
  missing="$(comm -23 <(echo "$req") <(echo "$runs") | tr '\n' ';')"
  legacy="$(echo "$req" | grep -E 'python-tests|rust-tests' | tr '\n' ';')"
  if [ -z "$missing" ] && [ -z "$legacy" ]; then
    pass V05 "every context the stable ruleset requires reported success at $SHA ($(echo "$req" | tr '\n' ';'))"
  else
    fail V05 "every context the stable ruleset requires reported success at $SHA" "missing=$missing legacy_required=$legacy"
  fi
fi

# V06: every remote uses: in the workflows is pinned to a full 40-character SHA (ci.md).
bad="$(grep -hE '^[[:space:]]*-?[[:space:]]*uses:' .github/workflows/*.yml | grep -v 'uses: \./' | grep -Ev 'uses: [^@ ]+@[0-9a-f]{40}( |$)' | head -3 | tr '\n' ';')"
if [ -z "$bad" ]; then
  pass V06 "every remote uses: in .github/workflows is pinned to a 40-character SHA"
else
  fail V06 "every remote uses: in .github/workflows is pinned to a 40-character SHA" "$bad"
fi
# V07 (challenge C1): classic branch protection on stable requires no status check
# either, so the ruleset read in V05 is the whole list of required contexts.
classic="$(gh api --method GET "repos/$REPO/branches/stable" --jq '[.protection.required_status_checks.contexts[]?, .protection.required_status_checks.checks[]?.context] | join(";")' 2>/dev/null)"
rc=$?
if [ $rc -ne 0 ]; then
  skip V07 "classic branch protection on stable requires no status checks" "API read failed"
elif [ -z "$classic" ]; then
  pass V07 "classic branch protection on stable requires no status checks"
else
  fail V07 "classic branch protection on stable requires no status checks" "requires: $classic"
fi
# ------------------------------------------------------------------------------
summary
diff -ru a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
--- a/.github/workflows/benchmark.yml	2026-11-10 13:52:22
+++ b/.github/workflows/benchmark.yml	2026-11-10 13:52:22
@@ -17,8 +17,6 @@
     steps:
       # The PR merged into its base, so the comparison isolates exactly this change.
       - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
-        with:
-          persist-credentials: false
 
       - name: Check out base
         uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
diff -ru a/.github/workflows/tests.yml b/.github/workflows/tests.yml
--- a/.github/workflows/tests.yml	2026-11-10 13:52:22
+++ b/.github/workflows/tests.yml	2026-11-10 13:52:22
@@ -37,3 +37,14 @@
       pytest-args: blastdns/tests tests/cli_tests.py -vv
       setup-script: scripts/ci-setup.sh
       teardown-script: scripts/ci-teardown.sh
+
+  required:
+    name: ${{ matrix.context }}
+    if: always()
+    needs: [rust, clippy-python-feature, python]
+    runs-on: ubuntu-24.04
+    strategy:
+      matrix:
+        context: ["python-tests (3.11)", rust-tests]
+    steps:
+      - run: true
diff -ru a/Cargo.toml b/Cargo.toml
--- a/Cargo.toml	2026-11-10 13:52:22
+++ b/Cargo.toml	2026-11-10 13:52:22
@@ -1,6 +1,6 @@
 [package]
 name = "blastdns"
-version = "2.0.4"
+version = "2.0.5"
 edition = "2024"
 description = "Async DNS lookup library for bulk/parallel DNS resolution"
 license = "AGPL-3.0"
diff -ru a/src/lib.rs b/src/lib.rs
--- a/src/lib.rs	2026-11-10 13:52:22
+++ b/src/lib.rs	2026-11-10 13:52:22
@@ -27,5 +27,6 @@
 pub use limiter::RateLimiter;
 pub use mock::MockBlastDNSClient;
 pub use resolver::DnsResolver;
+pub use hickory_resolver::system_conf;
 pub use utils::{check_ulimits, get_system_resolvers};
 pub use zone_transfer::{ZoneTransferResult, zone_transfer};

@liquidsec
liquidsec merged commit 58976d2 into stable Nov 10, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IPv6 system resolvers get the wrong address

3 participants