Raw JSON report machine-readable
{
"data": {
"repo": {
"topics": [
"dns",
"dns-server",
"dnssec",
"dns-resolver",
"edns",
"dns-over-https",
"dns-over-tls",
"resolver",
"dns-privacy",
"dns-over-quic"
],
"is_fork": false,
"size_kb": 6574,
"has_wiki": true,
"homepage": "https://sdns.dev",
"languages": {
"Go": 1440790,
"Shell": 2307,
"Makefile": 320,
"Dockerfile": 534
},
"pushed_at": "2026-07-24T15:32:24Z",
"created_at": "2018-10-01T06:13:46Z",
"owner_type": "User",
"updated_at": "2026-07-27T10:58:19Z",
"description": "A high-performance, recursive DNS resolver server with DNSSEC support, focused on preserving privacy.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "main",
"license_spdx_raw": "MIT",
"primary_language": "Go",
"significant_languages": [
"Go"
]
},
"owner": {
"blog": "https://4lev.com",
"name": "Yasar Alev",
"type": "User",
"login": "semihalev",
"company": "@netdirekt @stoolap ",
"location": "Izmir, Turkey",
"followers": 153,
"avatar_url": "https://avatars.githubusercontent.com/u/539588?v=4",
"created_at": "2010-12-28T22:48:52Z",
"is_verified": null,
"public_repos": 38,
"account_age_days": 5689
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v1.7.3",
"kind": "patch",
"published_at": "2026-07-19T17:45:09Z"
},
{
"tag": "v1.7.2",
"kind": "patch",
"published_at": "2026-06-25T22:19:26Z"
},
{
"tag": "v1.7.1",
"kind": "patch",
"published_at": "2026-06-24T20:04:10Z"
},
{
"tag": "v1.7.0",
"kind": "minor",
"published_at": "2026-05-31T18:51:51Z"
},
{
"tag": "v1.6.7",
"kind": "patch",
"published_at": "2026-05-18T13:36:38Z"
},
{
"tag": "v1.6.6",
"kind": "patch",
"published_at": "2026-05-07T21:03:58Z"
},
{
"tag": "v1.6.5",
"kind": "patch",
"published_at": "2026-04-25T19:35:41Z"
},
{
"tag": "v1.6.3",
"kind": "patch",
"published_at": "2026-04-20T11:19:58Z"
},
{
"tag": "v1.6.2",
"kind": "patch",
"published_at": "2026-04-19T20:09:48Z"
},
{
"tag": "v1.6.1",
"kind": "patch",
"published_at": "2025-11-28T14:51:15Z"
},
{
"tag": "v1.6.0",
"kind": "minor",
"published_at": "2025-07-06T20:35:22Z"
},
{
"tag": "v1.5.3",
"kind": "patch",
"published_at": "2025-06-08T12:47:55Z"
},
{
"tag": "v1.5.2",
"kind": "patch",
"published_at": "2025-06-07T22:12:20Z"
},
{
"tag": "v1.5.1",
"kind": "patch",
"published_at": "2025-06-07T21:46:56Z"
},
{
"tag": "v1.5.0",
"kind": "minor",
"published_at": "2025-06-05T08:38:12Z"
},
{
"tag": "v1.4.0",
"kind": "minor",
"published_at": "2025-02-14T15:36:46Z"
},
{
"tag": "v1.3.7",
"kind": "patch",
"published_at": "2024-06-23T09:45:11Z"
},
{
"tag": "v1.3.6",
"kind": "patch",
"published_at": "2024-01-02T11:40:18Z"
},
{
"tag": "v1.3.5",
"kind": "patch",
"published_at": "2023-08-26T12:32:25Z"
},
{
"tag": "v1.3.4",
"kind": "patch",
"published_at": "2023-08-11T10:47:13Z"
},
{
"tag": "v1.3.3",
"kind": "patch",
"published_at": "2023-08-06T09:08:25Z"
},
{
"tag": "v1.3.2",
"kind": "patch",
"published_at": "2023-07-26T21:51:00Z"
},
{
"tag": "v1.3.1-rc1",
"kind": "prerelease",
"published_at": "2023-07-05T12:14:39Z"
},
{
"tag": "v1.3.0",
"kind": "minor",
"published_at": "2023-07-01T20:32:15Z"
},
{
"tag": "v1.2.4",
"kind": "patch",
"published_at": "2023-04-30T11:50:56Z"
},
{
"tag": "v1.2.3",
"kind": "patch",
"published_at": "2023-04-30T09:55:45Z"
},
{
"tag": "v1.2.2",
"kind": "patch",
"published_at": "2023-04-30T09:47:59Z"
},
{
"tag": "v1.2.1",
"kind": "patch",
"published_at": "2022-02-04T09:00:28Z"
},
{
"tag": "v1.2.0",
"kind": "minor",
"published_at": "2022-02-04T08:47:02Z"
},
{
"tag": "v1.1.8",
"kind": "patch",
"published_at": "2021-08-20T19:08:47Z"
},
{
"tag": "v1.1.7",
"kind": "patch",
"published_at": "2020-12-17T20:44:21Z"
},
{
"tag": "v1.1.6",
"kind": "patch",
"published_at": "2020-08-02T10:49:28Z"
},
{
"tag": "v1.1.5",
"kind": "patch",
"published_at": "2020-07-28T04:55:35Z"
},
{
"tag": "v1.1.4",
"kind": "patch",
"published_at": "2020-07-28T03:32:03Z"
},
{
"tag": "v1.1.3",
"kind": "patch",
"published_at": "2020-07-21T14:29:31Z"
},
{
"tag": "v1.1.2",
"kind": "patch",
"published_at": "2020-07-16T12:00:35Z"
},
{
"tag": "v1.1.1",
"kind": "patch",
"published_at": "2020-07-09T11:51:16Z"
},
{
"tag": "v1.1.0",
"kind": "minor",
"published_at": "2020-07-08T11:04:37Z"
},
{
"tag": "v1.0.0",
"kind": "major",
"published_at": "2020-05-27T10:25:28Z"
},
{
"tag": "v0.3.4",
"kind": "patch",
"published_at": "2020-05-04T08:06:18Z"
},
{
"tag": "v0.3.3",
"kind": "patch",
"published_at": "2020-05-01T22:12:30Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2020-04-25T23:16:23Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2020-04-23T17:55:29Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2020-04-16T18:56:10Z"
},
{
"tag": "v0.2.5",
"kind": "patch",
"published_at": "2018-12-20T18:49:23Z"
},
{
"tag": "v0.2.4",
"kind": "patch",
"published_at": "2018-11-24T19:12:15Z"
},
{
"tag": "v0.2.3",
"kind": "patch",
"published_at": "2018-11-12T18:01:14Z"
},
{
"tag": "v0.2.2",
"kind": "patch",
"published_at": "2018-10-31T18:27:18Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2018-10-28T18:53:17Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2018-10-19T21:04:03Z"
},
{
"tag": "v0.1.9",
"kind": "patch",
"published_at": "2018-10-19T13:23:02Z"
},
{
"tag": "v0.1.8",
"kind": "patch",
"published_at": "2018-10-15T10:17:34Z"
},
{
"tag": "v0.1.7",
"kind": "patch",
"published_at": "2018-10-14T19:50:51Z"
}
],
"recent_commits": [
{
"oid": "6f745fef3c0d2058044f20d98063bb6f0eac671a",
"body": null,
"is_bot": false,
"headline": "chore: bump version to 1.7.3 (#517)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-19T17:12:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f84362c6d4d341d240600a68aedba5e58357a625",
"body": "…coverage (#516)\n\nmiekg/dns NSEC3.Cover() accepts nameHash == ownerHash inside an ordinary\ninterval (the lower-bound check is strictly less-than), so an NSEC3 that\nexactly matches a name — proof the name exists — was also accepted as\ncovering it. This let an attacker replay a zone's own signed NSEC3\n[…]\nt excludes exact owner\nmatches before accepting Cover(), and use it at both coverage call\nsites (findCoverer, nextCloserDenied). The plain-NSEC path already uses\nstrict inequalities and is unaffected.",
"is_bot": false,
"headline": "fix(dnssec): reject exact-owner NSEC3 matches as denial-of-existence …",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-19T16:58:46Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "39825c74fbbc978d626fff340c949d1dcd7c7e16",
"body": "…CAS the prefetch write-back (GHSA-mqfw-f48p-2vc8) (#515)\n\nCompletes the durable Ghost/Phoenix protection (phases 1b and 2 of\ndocs/security/ghost-phoenix-durable-design.md) on top of the delegation\nlease fixes in #513/#514.\n\nAnswer-cache ghost (Phase 1b): a cached answer could outlive the\ndelegation\n[…]\nent referral → answer cache → prefetch → withdrawal (a blocked\nrefresh must not displace the newer NXDOMAIN), parent unchanged vs\nre-delegated at the lease boundary, and Phoenix T2 deadline reporting.",
"is_bot": false,
"headline": "fix(cache,resolver): bind cached answers to their delegation cut and …",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-19T16:33:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a799a5972c5f3a6696554192e1664846b16d9bc9",
"body": "…s (Phoenix T2, GHSA-mqfw-f48p-2vc8) (#514)\n\n* fix(resolver): inherit ancestor delegation deadline across nested cuts (Phoenix T2, GHSA-mqfw-f48p-2vc8)\n\nA nested delegation could outlive the parent lease that granted it: a\nshort ancestor cut (e.g. a 3s ghostzone referral) followed by a long\nnested r\n[…]\nte load in the\ninternal NS-address lookup pipeline.\n\nGive the closure a private copy made while the caller still exclusively\nowns the request, so an abandoned leader never touches caller-owned\nmemory.",
"is_bot": false,
"headline": "fix(resolver): inherit ancestor delegation deadline across nested cut…",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-19T14:17:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8c01ce47231599ce12d3b56080d2af1c8ce0eae5",
"body": null,
"is_bot": false,
"headline": "chore: bump Go toolchain to 1.26.5",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-07-19T14:14:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f0e26da59a8f65d25170706792016b9c771a1a51",
"body": "…GHSA-mqfw-f48p-2vc8) (#513)\n\nA withdrawn child zone could be kept alive indefinitely (the ghost / phoenix\ndomain attack): once cached, a delegation's servers were re-queried directly at\nthe former child and the parent was never re-consulted, so the parent's\nsubsequent NXDOMAIN was never seen.\n\nRoot\n[…]\nprotection\n(delegation generation/CAS for late prefetch writes, descendant inheritance of\nthe ancestor deadline, and top-down invalidation on ancestor change/expiry) is\ntracked as a durable follow-up.",
"is_bot": false,
"headline": "fix(resolver): honour parent-granted delegation lease (ghost domain, …",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-19T01:47:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "329eee848b0109eaf1bae1d494c1a441bab1fe1e",
"body": "Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.21.0 to 0.22.0.\n- [Commits](https://github.com/golang/sync/compare/v0.21.0...v0.22.0)\n\n---\nupdated-dependencies:\n- dependency-name: golang.org/x/sync\n dependency-version: 0.22.0\n dependency-type: direct:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump golang.org/x/sync from 0.21.0 to 0.22.0 (#508)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-19T01:46:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e62f0a2023b8efc938ffbdff4515895f58163383",
"body": "…504)\n\nBumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 7.2.2 to 7.2.3.\n- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)\n- [Commits](https://github.com/goreleaser/goreleaser-action/compare/v7.2.2...v7.2.3)\n\n---\nupdated-dependencies\n[…]\nirect:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump goreleaser/goreleaser-action from 7.2.2 to 7.2.3 (#…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-19T01:42:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9eeb560850ef12af6e34a80d662ef490f401ad6f",
"body": "Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6 to 7.\n- [Release notes](https://github.com/actions/setup-go/releases)\n- [Commits](https://github.com/actions/setup-go/compare/v6...v7)\n\n---\nupdated-dependencies:\n- dependency-name: actions/setup-go\n dependency-version: '7'\n depen\n[…]\nirect:production\n update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump actions/setup-go from 6 to 7 (#511)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-19T01:42:15Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "015d0bb5bf9fb4139819b69d4dd4f8fd449883f0",
"body": "Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.46.0 to 0.47.0.\n- [Commits](https://github.com/golang/sys/compare/v0.46.0...v0.47.0)\n\n---\nupdated-dependencies:\n- dependency-name: golang.org/x/sys\n dependency-version: 0.47.0\n dependency-type: direct:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump golang.org/x/sys from 0.46.0 to 0.47.0 (#509)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-19T01:40:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "179178dcb93d04c51088105bf7bde081600c60c0",
"body": "Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.51.0 to 0.52.0.\n- [Commits](https://github.com/golang/crypto/compare/v0.51.0...v0.52.0)\n\n---\nupdated-dependencies:\n- dependency-name: golang.org/x/crypto\n dependency-version: 0.52.0\n dependency-type: indirect\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump golang.org/x/crypto from 0.51.0 to 0.52.0 (#510)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-19T01:40:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f4f12b0ef940c402121b44ad10162b90c43a4cf3",
"body": "…035 §5.3.4) (#512)\n\nA positive answer was marked AuthenticatedData=true on RRSIG verification\nalone. miekg's RRSIG.Verify accepts a wildcard RRSIG (Labels < owner label\ncount) against any deeper owner because it canonicalises the owner back to\n*.<closest-encloser> before hashing. On its own that le\n[…]\ns; only the positive answer path was missing it.\n\nAdds unit tests for the replay attack, non-covering/owner-only NSEC, deep\nnext-closer, legitimate NSEC and NSEC3 proofs, and non-wildcard passthrough.",
"is_bot": false,
"headline": "fix(dnssec): require wildcard-denial proof on positive answers (RFC 4…",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-18T18:56:13Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "04c3efd60334b4b69e8a8dbc2706a7950766b70b",
"body": "…authorities (#507)\n\nFixes two false-SERVFAIL vectors for legitimately unsigned names reached\nvia a CNAME crossing a security boundary, when some of the upstream\nnameservers are authoritative for several zones of the chain at once.\nWhich vector fires depends on which server answers, so the failures \n[…]\nta.\n\nBoth vectors are pinned by deterministic regression tests built from\ncaptured wire shapes, each paired with a guard test asserting the\ndowngrade protections the fixes must not relax.\n\nCloses #506",
"is_bot": false,
"headline": "fix(dnssec): false SERVFAILs for insecure names served by multi-zone …",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-03T08:53:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4a639ea607340658897f3b40a4fdd37001c34f9d",
"body": "…etch downgrade) (#505)\n\n* fix(resolver): stop CD=0 queries borrowing CD=1 delegations (AD loss)\n\nDelegations were stored under cd := req.CheckingDisabled || len(parentDS)==0,\nso a CD=0 query resolving an insecure delegation filed it in the CD=1 bucket.\nsearchCache then bridged the mismatch by letti\n[…]\npreserved from the copy (cache key and\nvalidation opt-out). Adds an integration regression test that runs the\nrefresh through the real edns layer and asserts a DO=0 trigger keeps the\nRRSIG and AD bit.",
"is_bot": false,
"headline": "fix(dnssec): two intermittent AD-loss vectors (cache poisoning + pref…",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-07-02T04:45:14Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5c33725d7cf8d01a30465fd0db63bf1dbba5f326",
"body": "- sdns.go: const version 1.7.1 -> 1.7.2\n- README docker run example tag 1.7.1 -> 1.7.2\n\nconfigver and the README Configuration header track the config-file schema,\nunchanged in 1.7.2, so they stay at 1.7.0. README benchmark table stays at the\nlast-measured release.",
"is_bot": false,
"headline": "chore(release): bump version to 1.7.2 (#503)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-06-25T21:32:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "808adc940a918d8f464670c99f9da01ddb5c4199",
"body": "…(+ AD on CD=1) (#501)\n\n* fix(dnssec): validate insecure delegations served without a referral\n\nWhen one server is authoritative for both a signed parent and an unsigned\nchild delegated from it, it answers names in the child authoritatively — so\nthe recursor crosses no referral and the missing-signa\n[…]\nld still receive\nAD=1 — including an upstream's AD bit passed through by the forwarder. Clear\nAD whenever the request has CD set; this is the last-line backstop for every\npath, the forwarder included.",
"is_bot": false,
"headline": "fix(dnssec): validate insecure delegations served without a referral …",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-06-25T21:05:42Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3f91b63e76828e890036b16968cbfb34a345b89e",
"body": "…(#500)\n\nSDNS performed upstream DNS exchanges from five divergent places, only\nthe resolver's (a literal copy of miekg's Conn) hardened. Introduce\ninternal/dnsclient as the single owner of DNS transport: wire framing,\nsize-bucketed buffer pooling, dialing, deadlines, ID match, the\nquestion-section \n[…]\ncallers remain).\n\nTests cover UDP/TCP/DoT/DoH success, ID mismatch, question mismatch,\ntruncation->TCP fallback, short read, timeout and the p[:n] guard, plus\nFuzzReadMsg and an alloc micro-benchmark.",
"is_bot": false,
"headline": "feat(dnsclient): own DNS exchange library, replace miekg-copy client …",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-06-25T20:47:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5f51345b2eef51a7cc2aeb97e39ef11cc33f0fb8",
"body": "* chore(release): bump version to 1.7.1\n\n- sdns.go: const version 1.7.0 -> 1.7.1\n- README docker run example tag 1.7.0 -> 1.7.1\n\nconfig/config.go (configver) and the README \"Configuration (v1.7.0)\" header\ntrack the config-file schema, which is unchanged in 1.7.1, so they stay at\n1.7.0 — bumping conf\n[…]\n7.x, and replace the\n\"open a GitHub issue\" guidance with GitHub private vulnerability reporting —\npublicly disclosing a vulnerability before a fix exists is the wrong default\nfor a recursive resolver.",
"is_bot": false,
"headline": "chore(release): bump version to 1.7.1 + security policy update (#499)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-06-24T19:40:05Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "57131b4db43ef1b2509d42dec597acde0bc61d8d",
"body": "…ERR guard, blocklist whitelist, cookie secret (#498)\n\n* build(deps): pin Go toolchain to 1.26.4 (clears reachable stdlib CVEs)\n\ngovulncheck reported 5 reachable standard-library advisories in the build\ntoolchain (1.26.2): GO-2026-5037/5038/5039 (crypto/x509, mime, net/textproto)\nand GO-2026-4918/49\n[…]\nmple.com. is whitelisted reported success and persisted a block that Exists\nwould always exempt — a confusing shadowed entry. Use matchHierarchy in\nsetLocked so the add path and the lookup path agree.",
"is_bot": false,
"headline": "1.7.1 hardening (round 2): toolchain CVEs, circuit-breaker leak, FORM…",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-06-24T19:28:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "717308d82a95d9d4e83470458161f511f2d830b2",
"body": "…(#497)\n\n* fix(cache): verify full question on cache hit (xxhash collision / poisoning defense)\n\nThe cache map key is a non-cryptographic 64-bit xxhash of the query\npreimage (qclass/qtype/CD/qname[/ECS scope]), and entries were returned on\na bare key match with no comparison of the stored question. \n[…]\nn the hash, so two names the key treats as distinct\ncould compare equal in the verification and weaken the collision/poisoning\ndefense. Compare with equalNameASCIIFold, which mirrors the hash exactly.",
"is_bot": false,
"headline": "1.7.1 hardening: cache full-key verification, CI fix, doc.go rewrite …",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-06-24T19:08:05Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4591984a07f2b86ac83b1980af8885e0415deb79",
"body": "Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.36.1 to 0.36.2.\n- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/kubernetes/client-go/compare/v0.36.1...v0.36.2)\n\n---\nupdated-dependencies:\n- dependency-name: k8s.io\n[…]\nirect:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump k8s.io/client-go from 0.36.1 to 0.36.2 (#493)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-24T17:00:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7f9b0a680a937bc35b21ee6930e448a05bf80b70",
"body": "Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.20.0 to 0.21.0.\n- [Commits](https://github.com/golang/sync/compare/v0.20.0...v0.21.0)\n\n---\nupdated-dependencies:\n- dependency-name: golang.org/x/sync\n dependency-version: 0.21.0\n dependency-type: direct:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump golang.org/x/sync from 0.20.0 to 0.21.0 (#491)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-24T17:00:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "edc93d66425e84d7868ae2c0b607cdac7bd08ba0",
"body": "…490)\n\nBumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.59.1 to 0.60.0.\n- [Release notes](https://github.com/quic-go/quic-go/releases)\n- [Commits](https://github.com/quic-go/quic-go/compare/v0.59.1...v0.60.0)\n\n---\nupdated-dependencies:\n- dependency-name: github.com/quic-\n[…]\nirect:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump github.com/quic-go/quic-go from 0.59.1 to 0.60.0 (#…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-24T16:58:23Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4ecb65a205854309a2ec5817bd25334c01604058",
"body": "Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.36.1 to 0.36.2.\n- [Commits](https://github.com/kubernetes/api/compare/v0.36.1...v0.36.2)\n\n---\nupdated-dependencies:\n- dependency-name: k8s.io/api\n dependency-version: 0.36.2\n dependency-type: direct:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump k8s.io/api from 0.36.1 to 0.36.2 (#492)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-24T16:57:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "26c2b8560972d78cb897d746f18ae012fd147bfc",
"body": "Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.45.0 to 0.46.0.\n- [Commits](https://github.com/golang/sys/compare/v0.45.0...v0.46.0)\n\n---\nupdated-dependencies:\n- dependency-name: golang.org/x/sys\n dependency-version: 0.46.0\n dependency-type: direct:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump golang.org/x/sys from 0.45.0 to 0.46.0 (#489)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-24T16:56:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "07eed209e8cf2ca925071b0805a4e4edd57d42f9",
"body": "Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.\n- [Release notes](https://github.com/actions/checkout/releases)\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/checkout/compare/v6...v7)\n\n---\nupdated-dependenc\n[…]\nirect:production\n update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump actions/checkout from 6 to 7 (#494)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-24T16:54:19Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c973ec8b38340fb4ab11e06928b235684d23fa47",
"body": "Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6 to 7.\n- [Release notes](https://github.com/codecov/codecov-action/releases)\n- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/codecov/codecov-action/compare/v\n[…]\nirect:production\n update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump codecov/codecov-action from 6 to 7 (#488)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-06-24T16:54:14Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "aeddd196f879aaf59cd119884aee6195ce3fbfef",
"body": "…ing (closes #495) (#496)\n\nGo's crypto/rsa (and miekg/dns, mirroring it) reject any RSA public exponent\nabove 2^31-1 — a portability cap, not a security requirement. DNSSEC zones\nwhose keys use a wider exponent therefore failed validation on SDNS while\nBIND/Google/Cloudflare (OpenSSL, no such cap) v\n[…]\nrd.\n\nTested against live mailbox.org (alg 7/10) and .lv (alg 8) records, a\nmiekg cross-check across all four RSA algorithms, key-bound and\ncanonical-encoding edge cases, and fuzzing of the key parser.",
"is_bot": false,
"headline": "fix(dnssec): validate RSA keys with exponents above crypto/rsa's ceil…",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-06-24T16:03:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f3fa249b54ae4f32e009aeb1f22abe33ec2cdc6d",
"body": "- sdns.go: const version 1.6.7 -> 1.7.0\n- README docker run example tag 1.6.7 -> 1.7.0\n\nconfig/config.go (configver) and contrib/linux/sdns.conf were bumped\nto 1.7.0 in earlier PRs and remain unchanged. README benchmark table\nintentionally stays at the last-measured release.\n\nThis release ships:\n- E\n[…]\n)\n- ECS-aware cache partitioning (Stage 2, closes #417, PR #484)\n- internal/metric sharded-counter shim + 23 new metrics (PR #485)\n- DNS-over-HTTPS forwarder upstreams (RFC 8484, closes #473, PR #486)",
"is_bot": false,
"headline": "chore(release): bump version to 1.7.0 (#487)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-31T18:26:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2dae4958dabf64e8dd7ee7a45a8c58117da5cf45",
"body": "Accept three forms in forwarderservers:\n- \"1.1.1.1:53\" — plain UDP (existing)\n- \"tls://1.1.1.1:853\" — DoT (existing)\n- \"https://1.1.1.1/dns-query\" — DoH, IP literal (new)\n- \"https://cloudflare-dns.com/dns-query\" — DoH, hostname (new)\n\nHostname URL\n[…]\nm attempt (matching the\nresolver handler's behaviour) so three slow upstreams can't take\n~3 * per-call timeout. cfg.Timeout still bounds each per-IP dial.\n\n21 tests, all green under -race; lint clean.",
"is_bot": false,
"headline": "feat(forwarder): DNS-over-HTTPS upstreams (RFC 8484, closes #473) (#486)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-31T18:08:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "33c822e59456055e501e8396916f6d7ed81cdbb1",
"body": "…lity (#485)\n\ninternal/metric is a sharded-counter shim over Prometheus that flushes\ndeltas to the registry on a background tick. Hot path is per-CPU atomic\nadd (~2 ns/op unlabeled, ~7 ns/op single-label, ~12 ns/op multi-label\nwith collision-safe length-prefix encoding) vs ~120 ns/op for direct\nprom\n[…]\n_total\n- dns_kubernetes_queries_total / answered / errors / write_errors\n\nmetric.Stop() is wired into sdns.go shutdown so the final flush\ncaptures the last interval of counts before the process exits.",
"is_bot": false,
"headline": "feat(metric): introduce internal/metric package and broaden observabi…",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-31T16:59:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5c7b1035009202f16019a71e41ea2264532b2d5f",
"body": "…Scope\n\nCoverage was 66.7% on buildCacheECSPolicy and 73.7% on requestScope\n— the error branches weren't exercised. Two new tests close that:\n\n- TestECSCache_BuildPolicyFailClosed asserts the cache disables\n ECS-aware caching (c.ecsPolicy == nil) when client_networks\n carries a malformed CIDR, and\n[…]\nath instead of building a bogus scoped key.\n\nmiddleware/cache buildCacheECSPolicy 66.7% → 100.0%\nmiddleware/cache requestScope 73.7% → 94.7%\nmiddleware/cache overall 86.4% → 87.4%",
"is_bot": false,
"headline": "test(cache): close ECS coverage gaps on buildCacheECSPolicy + request…",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-31T02:31:37Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "93d38ff37578db9a88c416e83ff24a90681895f2",
"body": "- Bump the configuration version header 1.6.7 → 1.7.0 to match\n the configver actually shipped with Stage 1.\n- New \"EDNS Client Subnet (RFC 7871)\" section under Built-in\n Middlewares: explains the two halves (opt-in forwarding +\n ECS-aware cache), the privacy-default stance, the full [ecs]\n conf\n[…]\nd its\n three outcome labels, and three operator-facing notes\n (prefetch gated on scoped entries, Purge sweeps scoped entries,\n cache_ecs_test.go as a usage reference).\n\nNo code change; README only.",
"is_bot": false,
"headline": "docs(readme): document ECS middleware (RFC 7871)",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-31T02:31:37Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d3a183d7bb1b0478bd77caae66696b88c2c9b391",
"body": "* feat(ecs): cache partitions by ECS scope (Stage 2, closes #417)\n\nWhen an authority returns an ECS-tailored answer, key the cache\nentry under the response's SCOPE prefix instead of the shared\n(qname, qtype, class, CD) tuple. A geo-tailored answer for one\nclient subnet no longer gets served to a cli\n[…]\nCountsOnlyECSPaths walks\nthe metric through four cases (ECS miss → store → ECS hit_scoped,\nnon-ECS hit, non-ECS miss) and asserts deltas of (1, 1, 0). Non-ECS\ntraffic doesn't touch the counter at all.",
"is_bot": false,
"headline": "feat(ecs): cache partitions by ECS scope (Stage 2, closes #417) (#484)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-31T02:23:13Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6717a9cbf757fdd5036b957d6eb6fbb238ee6efe",
"body": "* feat(ecs): opt-in EDNS Client Subnet forwarding (RFC 7871)\n\nAdds a [ecs] config block and the plumbing to forward client-supplied\nEDNS Client Subnet options upstream when the operator explicitly\nopts in. SDNS continues to strip ECS by default per RFC 7871 §11\nprivacy guidance.\n\nMechanics:\n- New in\n[…]\n policy off; out-of-range forward_v4 keeps it off; the\nclamped query ECS does not appear in the client reply even when a\ndownstream handler simulates the resolver leak by re-attaching the\nrequest OPT.",
"is_bot": false,
"headline": "feat(ecs): opt-in EDNS Client Subnet forwarding (Stage 1, #417) (#483)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-30T21:05:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "da884dc7d00713c2ba66e3ff67a8f3b76e733d44",
"body": "checkLoop derives its context key as contextKeyNSList + contextKey(qtype).\nWith contextKeyNSList defined right below the fixed iota keys, an A query\n(qtype 1) produced the same key as contextKeyDnameDepth. After a DNAME was\nfollowed, checkDname stored an int depth under that key; the subsequent\nIPv4\n[…]\ndding the\n16-bit qtype can never overlap the fixed keys, independent of how many\niota keys exist. Add regression tests covering the DNAME-then-A sequence\nand a full qtype sweep against the fixed keys.",
"is_bot": false,
"headline": "fix(resolver): prevent context-key collision panicking checkLoop",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-28T00:15:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "213b5dcfa3eb8becf4d1f7485e6ca11eaa9e6e97",
"body": "Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.44.0 to 0.45.0.\n- [Commits](https://github.com/golang/sys/compare/v0.44.0...v0.45.0)\n\n---\nupdated-dependencies:\n- dependency-name: golang.org/x/sys\n dependency-version: 0.45.0\n dependency-type: direct:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump golang.org/x/sys from 0.44.0 to 0.45.0 (#481)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-27T15:56:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0f4d3f7c390feff82a5cb9d7c14ed5c64044c045",
"body": "…480)\n\nBumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 7.2.1 to 7.2.2.\n- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)\n- [Commits](https://github.com/goreleaser/goreleaser-action/compare/v7.2.1...v7.2.2)\n\n---\nupdated-dependencies\n[…]\nirect:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump goreleaser/goreleaser-action from 7.2.1 to 7.2.2 (#…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-27T15:56:11Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7d0c87002d1e6452937a5b9bf8f6686cb4f7dbe1",
"body": "Bare domains were stored as exact matches only, so an entry like\n\"miui.net\" blocked the apex but not \"tracking.miui.net\" — the names\ndevices actually query. Popular plain-domain lists (hagezi\n*-onlydomains, OISD, etc.) therefore appeared to load fine yet let\nmost traffic through.\n\nExists now walks t\n[…]\n. \"*.domain\" wildcards keep their\nsubdomain-only semantics. Matching is done in the lookup rather than by\nduplicating entries into the wildcard map, so memory is unchanged for\nlarge lists.\n\nFixes #478",
"is_bot": false,
"headline": "fix(blocklist): block subdomains for bare blocklist domains (#478)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-27T15:55:21Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "89583a99a7aad81d64961efd999f09fd90cfea79",
"body": null,
"is_bot": false,
"headline": "chore(contrib): regenerate contrib/linux/sdns.conf at 1.6.7",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-18T12:44:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9e64549a549b331d599308b79295485c8a80eb57",
"body": null,
"is_bot": false,
"headline": "chore: bump version 1.6.6 → 1.6.7",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-18T12:44:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "96247192472a96ebf38d225b0ee1af0b1d50c83b",
"body": "Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.36.0 to 0.36.1.\n- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/kubernetes/client-go/compare/v0.36.0...v0.36.1)\n\n---\nupdated-dependencies:\n- dependency-name: k8s.io\n[…]\nirect:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump k8s.io/client-go from 0.36.0 to 0.36.1 (#477)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-18T11:11:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "625f1e8fc3888d5eedafc49f741a8b0fdef67054",
"body": "Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.36.0 to 0.36.1.\n- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.36.0...v0.36.1)\n\n---\nupdated-dependencies:\n- dependency-name: k8s.io/apimachinery\n dependency-version: 0.36.1\n dependency-type: direct:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump k8s.io/apimachinery from 0.36.0 to 0.36.1 (#476)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-18T11:09:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7d828de5b462d2fe287704f0087d04958b54d1a7",
"body": "…475)\n\nBumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.59.0 to 0.59.1.\n- [Release notes](https://github.com/quic-go/quic-go/releases)\n- [Commits](https://github.com/quic-go/quic-go/compare/v0.59.0...v0.59.1)\n\n---\nupdated-dependencies:\n- dependency-name: github.com/quic-\n[…]\nirect:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump github.com/quic-go/quic-go from 0.59.0 to 0.59.1 (#…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-18T11:05:46Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "66e07db98d263f48f02e7728723240956d7367e8",
"body": "Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.43.0 to 0.44.0.\n- [Commits](https://github.com/golang/sys/compare/v0.43.0...v0.44.0)\n\n---\nupdated-dependencies:\n- dependency-name: golang.org/x/sys\n dependency-version: 0.44.0\n dependency-type: direct:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump golang.org/x/sys from 0.43.0 to 0.44.0 (#474)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-18T11:02:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0c92a070e72393b816f5d1a80b7e97f43bcf9752",
"body": "…(#468)\n\nBumps [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) from 1.10.0 to 1.10.1.\n- [Release notes](https://github.com/fsnotify/fsnotify/releases)\n- [Changelog](https://github.com/fsnotify/fsnotify/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/fsnotify/fsnotify/comp\n[…]\nirect:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump github.com/fsnotify/fsnotify from 1.10.0 to 1.10.1 …",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-18T11:01:15Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5b31e40f82bb66a0b9122ba0e725793d8b0b57e5",
"body": "* refactor: move internal-only packages under internal/\n\nMoves five packages that have no business being public API:\n- cache -> internal/cache (LRU/storage primitives)\n- util -> internal/dnsutil (DNS message helpers; renamed)\n- waitgroup -> internal/waitgroup (cache-dedup \n[…]\n-shutdown timeout,\n async blocklist persistence semantics documented.\n\nConversational style throughout — endpoint table at the top for\nscan, curl examples interleaved with the prose where it matters.",
"is_bot": false,
"headline": "refactor: move internal-only packages under internal/ (#479)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-18T10:55:23Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "360e2eacd09bc17d16f6d81d84bb1b66d985a192",
"body": "Synthesises AAAA records from A records for IPv6-only clients reaching\nIPv4-only services. Sits between kubernetes and cache; activated when\nthe client's AAAA query has no usable answer and a secondary A lookup\nsucceeds, embedding each IPv4 into a configured Pref64::/n via RFC\n6052 §2.2.\n\nRFC 6147 c\n[…]\nrpose default\n\nMetrics: dns64_synthesised_total, dns64_ptr_translated_total,\ndns64_passthrough_total{reason}, dns64_a_lookup_failures_total{reason}.\n\nCloses the only open item on the README TODO list.",
"is_bot": false,
"headline": "feat(dns64): RFC 6147 DNS64 middleware (#472)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-08T00:09:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8453afb753586e386b86edb322a8589dea201574",
"body": "Cuts the security-fix release pairing #470 and #471 (issue #469 — cache\npoisoning via mismatched upstream question section in forwarder and\nresolver paths).\n\nAlso folds in the changes that landed on main since v1.6.5:\n- feat(views): per-client static-answer middleware (#360)\n- feat(blocklist): non-b\n[…]\n\nfollow-up commit. The README benchmark row stays at 1.6.5 (the version the\nnumbers were actually measured against) — only the docker pin and the\n\"Configuration (vX.Y.Z)\" header track the new version.",
"is_bot": false,
"headline": "chore: bump version 1.6.5 → 1.6.6",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-07T20:42:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "03028469bd56c744c79984764e18bb4e84e4f95e",
"body": "Conn.Exchange previously validated only the DNS transaction ID; an upstream\nthat returned a different question section was passed back to the caller and\nultimately stored in the cache under that response's question, poisoning\nlater lookups for an unrelated name.\n\nMirror the forwarder fix from #470 a\n[…]\ntion to contain exactly one entry\nmatching the request's Qtype, Qclass, and Name (case-insensitively), and\nreturn ErrQuestion otherwise so the existing retry/next-server path takes\nover.\n\nCloses #469.",
"is_bot": false,
"headline": "fix(resolver): drop upstream responses with mismatched question (#471)",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-05-07T20:36:39Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "95e3cdb9c307437735e797c2bd67fb67c9805064",
"body": "Refs #469\n\nSigned-off-by: SAY-5 <SAY-5@users.noreply.github.com>\nCo-authored-by: SAY-5 <SAY-5@users.noreply.github.com>",
"is_bot": false,
"headline": "fix(forwarder): drop upstream responses with mismatched question (#470)",
"author_name": "Sai Asish Y",
"author_login": "SAY-5",
"committed_at": "2026-05-07T20:17:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "26615e8c3ce02d48d3578c3f401eb35814d860b4",
"body": "…s, SERVFAIL on unsynced\n\nCollapses the dual-mode (killer/boring) implementation into one sharded\nregistry with per-headless-service incremental state. Slice events go\nthrough ApplyEndpointSlice / RemoveEndpointSlice + a worker-coalesced\nMaterialiseHeadless, so a one-pod change in a 1000-pod headles\n[…]\ner.go, smart_predictor.go,\nprefetch_strategies.go, zero_alloc_cache.go, sharded_registry.go,\nkiller-mode tests, large coverage-only tests). config.KubernetesConfig\ndrops killer_mode from the live API.",
"is_bot": false,
"headline": "refactor(kubernetes): per-slice incremental headless state, UID guard…",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-07T19:55:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "eed1585b237c895b0f58dc30e8f04ed1a68408e4",
"body": "Move pure DNSSEC verify functions (RRSIG, DS, NSEC, NSEC3 denial-of-\nexistence proofs) and the EDE-coded sentinel errors that go with them\ninto a new middleware/resolver/dnssec subpackage. Move the generic DNS\nRR helpers (ExtractRRSet, FilterRRsToZone, NameInZone, DnameTarget) and\nthe EDEError type \n[…]\n and the goroutine entry no longer has to capture state via\nclosure.\n\nNet: −2016 / +265 lines in middleware/resolver/, ~1100 lines under\nmiddleware/resolver/dnssec/. Tests, gofmt, golangci-lint clean.",
"is_bot": false,
"headline": "refactor(resolver): extract DNSSEC primitives + split lookup()",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-05-06T01:07:08Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "eab6054ebf84dbed2cc09c383dfb542c52f4a436",
"body": "…#467)\n\nBumps [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) from 1.9.0 to 1.10.0.\n- [Release notes](https://github.com/fsnotify/fsnotify/releases)\n- [Changelog](https://github.com/fsnotify/fsnotify/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/fsnotify/fsnotify/compar\n[…]\nirect:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump github.com/fsnotify/fsnotify from 1.9.0 to 1.10.0 (…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-03T11:04:15Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0cffbd81a7882ed18d82ab2372160554aa901720",
"body": "…466)\n\nBumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 7.1.0 to 7.2.1.\n- [Commits](https://github.com/goreleaser/goreleaser-action/compare/v7.1.0...v7.2.1)\n\n---\nupdated-dependencies:\n- dependency-name: goreleaser/goreleaser-action\n dependency-version: 7.2.\n[…]\nirect:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump goreleaser/goreleaser-action from 7.1.0 to 7.2.1 (#…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-05-03T11:03:56Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9578a8fe74f8f4ecaf8ec299aca125e0555c9ce9",
"body": "ICANN/Verisign re-numbered B-root in late 2023:\n IPv4: 199.9.14.201 -> 170.247.170.2\n IPv6: 2001:500:200::b -> 2801:1b8:10::b\n\nThe old addresses still answer for transitional reasons (priming\neven discovers and merges the new ones at runtime — that's how the\nproduction instance picked up 2801:1b8:\n[…]\nt a config\nchange), but the canonical list at named.root has only the new\nones. Bring the embedded default config, the Linux packaging\nconfig, the benchmark fixtures, and the fuzz seed corpus in line.",
"is_bot": false,
"headline": "chore(config): update B-root to current IANA addresses",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-26T23:02:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "af849edc113b5e8dec800a6c468de780ffee1b2a",
"body": "Adds a new \"views\" middleware that returns different DNS answers\nbased on the originating client's source IP — a split-horizon\nresolver where a name like *.example.lan. can resolve to one\naddress for LAN clients and a different one for VPN clients\nwithout disturbing recursion for everyone else. Requ\n[…]\nd to the last view rather than the root config.\n\nPosition in the chain: between hostsfile and blocklist, so a\nview-curated answer for a specific client wins over a global\nblocklist rule for that name.",
"is_bot": false,
"headline": "feat(views): per-client static-answer middleware (#360)",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-26T03:44:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "35432ae01f860d9d8f3bed425a76ef5648b603db",
"body": "v2.0.7 changed the variadic-KV signature on Info/Warn/Error/Debug\nto typed Field arguments, breaking the existing 247 untyped call\nsites. v2.0.8 restored backward compatibility, so the bump is now\na no-op upgrade — no migration required.\n\nSkipping the buffered-stdout perf pattern the zlog author als\n[…]\n0 ns) doesn't\nmatter at sdns log volumes, and a 16 KiB buffer would lose the\nlast few seconds of logs on hard crash, OOM kill, or panic\nwithout recover — exactly the data needed for incident response.",
"is_bot": false,
"headline": "chore(deps): bump github.com/semihalev/zlog/v2 to v2.0.8",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T19:34:55Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "450f1ddf9942d1b7267ef953326329e11f0571a3",
"body": "Reported: blocklist mutations via the HTTP API caused DNS to\ntemporarily stop responding while changes were applied. Root cause\nin middleware/blocklist/blocklist.go: Set / Remove held b.mu\n(mutually exclusive with the RLock that ServeDNS takes on every\nDNS query) for the full duration of the synchro\n[…]\nringSave pins the contract: holds saveMu\n from a goroutine and asserts that a concurrent ServeDNS-style\n RLock returns within 2s. Fails loudly if anyone re-introduces\n disk I/O inside the map lock.",
"is_bot": false,
"headline": "feat(blocklist): non-blocking persistence and bulk import API",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T19:34:55Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "61365325396bfc18e71f22f7ad339ae795934ef3",
"body": "Replaced with the binary's freshly-emitted default. The packaging\nconfig had been lagging on every version bump (was still 1.6.3 even\nafter 1.6.4), so re-emitting from sdns -t guarantees structural\nparity with what a fresh install would generate today.",
"is_bot": false,
"headline": "chore(contrib): regenerate contrib/linux/sdns.conf at 1.6.5",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T14:33:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d580bf3f3fd0e2fbdcbf4f383c587a8dab62a549",
"body": "v1.6.4 release pipeline failed on freebsd_amd64 (build constraint bug\nin server/reuseport_darwin.go, fixed in 66ddad9). Cutting v1.6.5\ninstead of moving the v1.6.4 tag, since the broken tag is already\npublic.",
"is_bot": false,
"headline": "chore: bump version 1.6.4 → 1.6.5",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T14:28:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "66ddad9e9531d2123ca8e1cacf6df6ea8c687552",
"body": "The file was named reuseport_darwin.go, which Go treats as an implicit\nGOOS=darwin build constraint. The explicit //go:build line listing\ndarwin || freebsd || netbsd || openbsd || dragonfly was ANDed against\nthat, so only darwin actually picked up the file — freebsd, netbsd,\nopenbsd, dragonfly all f\n[…]\nicit tag governs.\n\nSurfaced by goreleaser v1.6.4 release pipeline failing on\nfreebsd_amd64. Cross-compiled here for darwin / freebsd / netbsd /\nopenbsd / dragonfly amd64 / linux / windows — all green.",
"is_bot": false,
"headline": "fix(server): build reuseport file on all BSDs, not just darwin",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T14:09:59Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2f8bb860dea12f0824c54eb186b80a8059e51194",
"body": "Picks up the terminal-writer formatter fix that always emits at least\none space between the message and the first key=value, so long log\nmessages no longer collide with their fields.",
"is_bot": false,
"headline": "chore(deps): bump github.com/semihalev/zlog/v2 to v2.0.6",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T13:30:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "24aeddb9bed7159fc37bb8cb206d10ae68ca023d",
"body": "CI on windows-latest tripped on two issues introduced with the trust-\nanchor dual-write hardening:\n\n- atomicGobWrite did `os.Open(dir).Sync()` after rename, which fails\n on Windows with \"Access is denied\" — FlushFileBuffers on a\n directory handle requires GENERIC_WRITE, which os.Open doesn't\n gra\n[…]\nntinel\n errCorruptTombstones; AutoTA now only fails closed when bytes\n actually fail to decode. Other open errors log and proceed with\n an empty in-memory tombstones map; the next refresh re-loads.",
"is_bot": false,
"headline": "fix(resolver): Windows compatibility for AutoTA persistence",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T12:48:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "51bba885c6005ea9e3e565690ec928ba44b4add2",
"body": "Trust-anchor lifecycle (auto_trust_anchor.go):\n- verifyFetchedKeys now uses at-least-one-trusted-anchor RRSIG\n semantics with a narrow revoked-bootstrap carve-out (RFC 5011 §2.1).\n Returns a revocation-only flag so a revoked-key signature can no\n longer drive non-revocation transitions.\n- Revocat\n[…]\n→ glueV4/glueV6.\n- Drop unused otype parameter from Resolver.authority.\n\nMisc:\n- Version bump 1.6.3 → 1.6.4.\n- Test config helper creates cfg.Directory so atomic writes work\n under the test temp dir.",
"is_bot": false,
"headline": "fix(resolver): RFC 5011 trust-anchor hardening and naming cleanup",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-25T12:10:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "61aa573816af5c786cd241ca9204b01fb4d2bb3c",
"body": "Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.35.4 to 0.36.0.\n- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/kubernetes/client-go/compare/v0.35.4...v0.36.0)\n\n---\nupdated-dependencies:\n- dependency-name: k8s.io\n[…]\nirect:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump k8s.io/client-go from 0.35.4 to 0.36.0 (#464)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-04-24T20:24:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9252e76f013bc7a43af80e9cc46c5c8e725023eb",
"body": "Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.35.4 to 0.36.0.\n- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.35.4...v0.36.0)\n\n---\nupdated-dependencies:\n- dependency-name: k8s.io/apimachinery\n dependency-version: 0.36.0\n dependency-type: direct:production\n update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump k8s.io/apimachinery from 0.35.4 to 0.36.0 (#463)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-04-24T20:22:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e108d27b0bcae58ad83e593b02f301638146eab2",
"body": "Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6.\n- [Release notes](https://github.com/codecov/codecov-action/releases)\n- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/codecov/codecov-action/compare/v\n[…]\nirect:production\n update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump codecov/codecov-action from 5 to 6 (#462)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-04-24T20:21:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7c058925eec301ebed8a09b8db91573d60e87426",
"body": "…ryer (#465)\n\n* refactor(resolver): promote requestID to typed resolveState\n\nRename resolveContext -> resolveState and add a typed requestID field\nconsulted by newDialer for outbound IP selection. Resolve() sources it\nfrom contextKeyRequestID when present (preserving ExchangeInternal\ncross-boundary \n[…]\ndleware/ doesn't\n register in the individual packages' coverage files.\n\nPatch coverage should move materially closer to project coverage\n(78.58%) on the next codecov run; -race and lint remain clean.",
"is_bot": false,
"headline": "refactor: retire util.ExchangeInternal; internal sub-pipeline via Que…",
"author_name": "Yasar Alev",
"author_login": "semihalev",
"committed_at": "2026-04-24T20:21:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d596ec267e6000762bf22bb107fb88c904afe23e",
"body": "Resolver\n- checkDname: surface DNAME alias-chain depth exhaustion as\n errMaxDepth instead of returning (nil, false) and letting answer()\n silently report the partial outer response with NOERROR. Cap is\n handler.maxDnameDepth (10); cross-DNAME cycles now SERVFAIL loudly.\n CD=1 from the outer requ\n[…]\ndrain before the port is released.\n- DoQ: MaxIncomingStreams=32, MaxIncomingUniStreams=4 so a single\n client can't monopolise the server by opening every stream the\n default allows and parking them.",
"is_bot": false,
"headline": "fix: DoS hardening and DNAME/DNSSEC correctness follow-ups",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-24T09:29:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1d7c091f0c1ffbee2aac4056c7399e348fcc11cc",
"body": "DNSSEC validation\n- verifyRRSIG rewritten to require every in-zone RRset to be covered by\n at least one signature that verifies; return ok=true only after every\n in-zone RRset passes. Zone is supplied by the caller (signer) instead\n of being derived from the keys map, defending against same-tag\n \n[…]\nODATA.\n- nsec_test.go: wildcard NSEC NODATA shape and \"wildcard has type\"\n rejection.\n- authserver_test.go: fingerprint invalidation ordering and the\n mutation race between snapshot and cache-store.",
"is_bot": false,
"headline": "fix(resolver): DNSSEC validation hardening and DNAME correctness",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-24T05:27:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9d6ed12c55baa39288ad7500162b514e109c628a",
"body": "Kubernetes middleware:\n- New(): gate standard-mode authoritative answers on demo load or live\n client sync so a failed/warming-up client no longer synthesises\n NXDOMAIN from an empty registry.\n- Client: accept a registryWriter, unwrap cache.DeletedFinalStateUnknown\n on all delete handlers, aggreg\n[…]\naitgroup:\n- Join leader/follower semantics: followers share the leader's\n done channel without bumping the dup counter, so leader Done\n cancels the shared context immediately. Regression test added.",
"is_bot": false,
"headline": "fix: batch of correctness findings across middleware stack",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T15:32:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7b4255f3534dfc4f9b3780709e5cb7063e005da8",
"body": "gosec flags uintptr -> int on the kernel file descriptor inside the\nnet.ListenConfig.Control callback. Linux FDs are always small\nnon-negative ints so the conversion is safe; extract the cast into\none sockfd variable with a //nolint:gosec annotation.",
"is_bot": false,
"headline": "fix: silence gosec G115 on Linux SO_REUSEPORT socket option",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T04:01:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "30869c9124f0cb6175f0b59b9d550d1391bca758",
"body": "groupLookup keyed singleflight only by (qname, qtype, qclass, CD), so\ntwo callers querying the same question against different authority\nsets at different recursion stages would collapse into one in-flight\nlookup and the first caller's answer — derived from the first\ncaller's delegation — would be c\n[…]\nts interleaved with valid negative answers\nwere enough to trip the breaker on a reachable server. The breaker\ntracks transport health, not answer positivity, so any non-error\nresponse should reset it.",
"is_bot": false,
"headline": "fix(resolver): five correctness bugs in the parallel lookup path",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T03:58:08Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3a9cf95276a813beafb95d2e78e4946d83182c63",
"body": "- resolver.go: 3-way if/else for pooled/UDP-fast/TCP-fallback dial\n paths is clearer as a switch { case ...: }. gocritic's\n ifElseChain hint.\n- resolver.go: localAddrIndex's uint64->int narrow carries a G115\n warning even though the modulo bounds result into [0, n). Annotate\n the conversion with\n[…]\nnally keeps\n the server-lifecycle context (it waits for cancellation to start\n the shutdown). Matches the pre-refactor G118 exception pattern\n that used to live on each ListenAndServeXxx goroutine.",
"is_bot": false,
"headline": "fix: silence three golangci-lint findings from the listener merge",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T03:39:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a28e8ee6271f1fede7c8487aec6da7b6f0f579c3",
"body": "Three related commits:\n\n perf(hostsfile): pre-build answer RRs at load time\n perf(resolver): pool net.Dialer, bypass DialContext on UDP upstream\n feat(server): explicit listener lifecycle with fail-fast binds\n\nFixes #453 — bind-in-use no longer silently limps in a background\ngoroutine; the proces\n[…]\nses its own\nsocket in Shutdown (miekg/dns and net/http Shutdown are both no-ops\nbefore Serve starts); HasListener reports \"serving\", not \"bound\";\nDoH3 / DoQ shutdown close the caller-owned PacketConn.",
"is_bot": false,
"headline": "Merge listener-lifecycle: perf + explicit listener lifecycle",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T03:30:11Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ab1546671bec29c32292a3b31151d3b62c31cc5d",
"body": "Each DNS transport (UDP, TCP, DoT, DoH, DoH3, DoQ) is now its own\nListener implementation with an explicit Bind / Serve / Shutdown\ncontract, living alongside the server in server/listener_*.go.\nServer.Run binds every listener synchronously before any Serve\ngoroutine starts and returns a non-zero err\n[…]\n\n cycles on fixed DoH3 + DoQ ports to catch any socket leak\n regression in graceful restart.\n\ngo.mod promotes golang.org/x/sys to a direct dependency (used by\nreuseport_linux.go for SO_REUSEPORT).",
"is_bot": false,
"headline": "feat(server): explicit listener lifecycle with fail-fast binds",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T03:29:22Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "978fcfa8b8d9697b0898ce042a45b8abe0c1c27e",
"body": "The recursive resolver created a fresh net.Dialer on every upstream\nquery and went through Dialer.DialContext — resolveAddrList,\ndialParallel, internal context.WithDeadline and AfterFunc — even for\nnumeric IP:port targets where none of that work is needed.\n\nThree changes land together:\n\n - net.Diale\n[…]\nuntyped\nnil instead of returning (*net.UDPConn)(nil) as net.Conn — otherwise\ndownstream code that treats Conn != nil as \"usable\" would panic\ncalling Close on a nil pointer through a non-nil interface.",
"is_bot": false,
"headline": "perf(resolver): pool net.Dialer, bypass DialContext on UDP upstream",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T03:28:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ed04e45c59a6e3d391cc9c0144ea9e4d8c8bc2de",
"body": "Every lookup allocated a fresh []dns.RR plus one *dns.A / *dns.AAAA\nper IP and a \"name + \\\".\\\"\" string — thousands of allocations per\nsecond under any hostsfile-heavy workload, all throwaway.\n\nBuild the per-entry A / AAAA / CNAME RR slices once in load() and\nreturn them directly from lookupA / looku\n[…]\ntead — safe because\nthe chain is cancelled before any downstream middleware runs.\nHeader bits (RD + CD) are copied explicitly so both round-trip.\n\nRegression test added for the CD / RD bit round-trip.",
"is_bot": false,
"headline": "perf(hostsfile): pre-build answer RRs at load time",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-23T03:28:25Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "86681e8d75d57f0086d7c7b8e5bc37dd2129af31",
"body": "Applies the five dependabot PRs (#457-#461) in a single commit so the\nDockerfile and the rest of docker.yml stay in sync. No config-surface\nchanges across these majors for the way we use them — metadata,\nmulti-arch setup, registry login, and multi-registry push all keep\nthe same inputs.\n\n docker/metadata-action v5 -> v6\n docker/setup-qemu-action v3 -> v4\n docker/setup-buildx-action v3 -> v4\n docker/login-action v3 -> v4\n docker/build-push-action v6 -> v7",
"is_bot": false,
"headline": "ci: bump docker/* actions to latest majors",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-22T19:30:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6c38f7886ae9d30ab72edfdcfb589ebcbc459ceb",
"body": null,
"is_bot": false,
"headline": "docs: refresh benchmark numbers against PowerDNS 5.4.1",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-22T19:30:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c68467eba9d1ad178837f6f3413d6e17af398889",
"body": "Five related changes land together — each removes one of the top\nallocators surfaced by profiling the middleware pipeline with\ndnsperf against a hostsfile-hit workload:\n\nloop: lazy tracker, zero alloc on external queries\n The old implementation did `q.Name + \":\" + type + \"loopcheck:\"`\n string-conc\n[…]\ning slots would corrupt the cache.\n\nLoop test updated to drive the handler through an internal\nwriter so the tracker engages, and a complementary\nexternal-writer case pins the new fast-path behaviour.",
"is_bot": false,
"headline": "perf: cut middleware pipeline allocations on the per-query hot path",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-22T16:39:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "302052a638bfa41e2c489d19b342480ca45b4bde",
"body": "docker/build-push-action v6 attaches a provenance attestation by\ndefault, which shows up as an \"unknown/unknown\" platform manifest\nentry in the multi-arch manifest list next to the real\nlinux/amd64 and linux/arm64 platforms. GHCR and Docker Hub both\nsurface it in their UI, which looks broken even though the real\nplatforms work fine.\n\nSet provenance: false (and sbom: false for symmetry) so only the\ntwo intended platforms appear in the manifest.",
"is_bot": false,
"headline": "ci: drop provenance/sbom attestations from Docker build",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-22T15:06:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5b193f832ff202f00c41bd05c40ce5fc559bb7ac",
"body": "The GitHub Container Registry link pointed to the retired\n`sdns/sdns` package (id 188181) which is now deleted, and the\n`docker run ... sdns` command never referenced a registry path\nso users couldn't copy-paste it to actually pull the image.\n\nReplace with the canonical paths (`ghcr.io/semihalev/sdns` and\n`c1982/sdns`), note the multi-arch support, and show both a\n`:latest` example and a version-pinned example for production.",
"is_bot": false,
"headline": "docs: refresh Docker install section",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-22T15:02:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d02c0d5f5cb5042496e35f0521103fd7a682abce",
"body": null,
"is_bot": false,
"headline": "Bump version to 1.6.3",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-20T10:55:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "19e87371994f4af97b5fdd67ddf3e9fb07259dba",
"body": "Profiling the middleware chain on an M4 showed that 100% of the\n32 B/op, 2 allocs/op cost per chain Reset came from\n\n w.RemoteAddr().String() == \"127.0.0.255:0\"\n\nnet.(*UDPAddr).String calls net.JoinHostPort and net.IP.String, each\nof which allocates. At 100k QPS that's 200k allocs/s and ~3.2 MB/s\n[…]\n 0 B/op 0 allocs/op\n\nSo ~58% faster per query walk and the hot path is alloc-free.\nBenchmarkGet drops 21.9 ns -> 5.3 ns (4x) from the atomic-pointer\npipeline, though Get is off the request hot path.",
"is_bot": false,
"headline": "perf: eliminate per-query allocation in responseWriter.Reset",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-20T09:48:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "49ebfabb93ef6f791b1c0bbbbca25a0d16629a13",
"body": "Replaces the package-level slice + index lookup that shipped in 1.6.2\nand caused `middleware.Get(\"blocklist\")` to return the wrong handler\nwhen a disabled middleware (typed-nil) sat earlier in the chain, panicking\nthe API on startup.\n\nNew structure:\n\n* types.go — Handler + Constructor types + i\n[…]\nsDisabled (regression\nfor the 1.6.2 bug), Test_Registry_RegisterAt (including duplicate-Register\npanic), Test_Registry_Build_ConcurrentReads (race coverage for lock-free\nreads), Test_Pipeline_NilSafe.",
"is_bot": false,
"headline": "refactor: redesign middleware around immutable pipeline + atomic pointer",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-20T09:33:00Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "728e86b0617db3ecc7224fa1193427e908fb0dde",
"body": null,
"is_bot": false,
"headline": "docs: point build badge to ci.yml after workflow consolidation",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-19T20:42:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "31dbd95805a6dc1425c4106f4374ea56418303d5",
"body": null,
"is_bot": false,
"headline": "Bump version to 1.6.2",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-19T19:48:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "08e800a52413fbf7a54f45bc70e8ce602d5798a4",
"body": "Merge go.yml + codecov.yml + golangci-lint.yml into ci.yml (test matrix +\nlint, single codecov upload on ubuntu). Merge docker-hub.yml +\ndocker-publish.yml into docker.yml — single buildx build pushes multi-arch\nto Docker Hub and ghcr.io (replacing the retired docker.pkg.github.com).\nModernize codeq\n[…]\np the action\nto v7.1.0, and pin the GoReleaser CLI to ~> v2 so a future v3 can't break\na tag.\n\nAll workflows now run on go-version: stable and declare least-privilege\npermissions + concurrency groups.",
"is_bot": false,
"headline": "ci: consolidate workflows from 8 to 5",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-19T19:24:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e6d5ccec5123c1ba881603e750736eb997624d44",
"body": "…451)\n\nBumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 6.4.0 to 7.0.0.\n- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)\n- [Commits](https://github.com/goreleaser/goreleaser-action/compare/v6.4.0...v7.0.0)\n\n---\nupdated-dependencies\n[…]\nirect:production\n update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "build(deps): bump goreleaser/goreleaser-action from 6.4.0 to 7.0.0 (#…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-04-19T11:55:59Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "173d02469a65d9b67936606946d8cab7cc5a3b90",
"body": "Key bumps:\n- miekg/dns 1.1.68 -> 1.1.72\n- quic-go 0.57.1 -> 0.59.0\n- k8s.io/{api,apimachinery,client-go} 0.34.2 -> 0.35.4\n- golang.org/x/net 0.47.0 -> 0.53.0\n- golang.org/x/crypto 0.45.0 -> 0.50.0\n\nFull test suite passes with -race.",
"is_bot": false,
"headline": "deps: bump all dependencies to latest minor versions",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-19T11:54:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "77f5fc2de24d381fa87fd822d24efe2c3eafd2da",
"body": "After PR #450, Test_handler consistently fails on CI at the example.com.\nIN A assertion with validateDelegation returning errDSRecords (\"Parent\nhas DS records but zone appears unsigned\"). The successful-A-resolution\npath is already covered by the www.apple.com. assertion earlier in the\nsame test, so removing the example.com. check keeps the coverage intact\nwhile stopping the deterministic CI failure.",
"is_bot": false,
"headline": "test: drop flaky example.com assertion from Test_handler",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-04-19T11:44:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "90c5113c46c35d68ac475c69c22cbae7c817b4c0",
"body": "…450)\n\n* Fix: DNSSEC - extract isZoneSecure and restore probeName stripping\n\n* Fix: DNSSEC isZoneSecure - RFC 4035 compliant zone security check\n\nRemove incorrect findDS walk on internal names that cleared DS state\nfor signed zones. Per RFC 4035 §5.3.3 and RFC 4034 §5, DS records\nonly exist at delegation points (zone cuts). Probing non-delegation\nnames inside a zone incorrectly treated signed zones as insecure.",
"is_bot": false,
"headline": "Fix: DNSSEC - extract isZoneSecure and restore probeName stripping (#…",
"author_name": "Maciej Tomczuk",
"author_login": "MaciejTe",
"committed_at": "2026-04-19T10:27:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "52f308572df8726208bf64f1b46c87a1056d7003",
"body": "…can't crash ServeDNS (#455)\n\nRegister wraps each middleware's New() inside a closure returning\nmiddleware.Handler:\n\n\tmiddleware.Register(\"reflex\", func(cfg *config.Config) middleware.Handler {\n\t\treturn reflex.New(cfg)\n\t})\n\nSome middlewares (reflex, accesslist, kubernetes, etc.) signal \"disabled\nin \n[…]\ning\n`return nil when disabled` idiom; no change at any New() site is\nrequired.\n\nFixes #453\n\nSigned-off-by: SAY-5 <SAY-5@users.noreply.github.com>\nCo-authored-by: SAY-5 <SAY-5@users.noreply.github.com>",
"is_bot": false,
"headline": "middleware: skip typed-nil handlers in Setup so disabled middlewares …",
"author_name": "Sai Asish Y",
"author_login": "SAY-5",
"committed_at": "2026-04-19T09:46:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "75c561370cde8c003521c6677e5e8d40dba92b43",
"body": "The goroutine intentionally uses context.Background() because the parent\ncontext is already cancelled at that point and the new context provides a\ngrace period for the HTTP server shutdown.",
"is_bot": false,
"headline": "Fix gosec G118 warning in API server shutdown goroutine",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-03-06T16:10:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "52f7da7b2703c60e3191ab10208f9de3b95f824f",
"body": "Add nolint directives for false-positive gosec warnings: G122 on trusted\nlocal temp file removal in blocklist updater, G118 on server lifecycle\ngoroutines using the parent context, and G118 on waitgroup cancel stored\nfor later use in Done().",
"is_bot": false,
"headline": "Fix gosec G118 and G122 linter warnings",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-03-06T16:08:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "85892906553990b0361cdff423c1869f63680025",
"body": "…, and util\n\nCover panic resistance for security-critical parsing: DNS wire format,\nDNSSEC validation (NSEC, exponent, base64), PTR/reverse name parsing,\nDoH message handling, cache key generation, config TOML loading,\nblocklist wildcard matching, and hosts file parsing.",
"is_bot": false,
"headline": "Add fuzz tests for cache, config, blocklist, hostsfile, resolver, doh…",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-03-06T16:07:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "82c5eaade65aba7df9f4134c783c13bb731f4e12",
"body": "Add nolint directives and explicit bitmasks for intentional integer\nnarrowing conversions (G115), secret field name pattern (G117), and\nslice bounds check (G602).",
"is_bot": false,
"headline": "Fix gosec linter failures for golangci-lint v2",
"author_name": "semihalev",
"author_login": "semihalev",
"committed_at": "2026-03-06T16:05:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "018b8534df05fd1cbd87fed0e4d7fa3bb487c2c2",
"body": "* add Cache.ForEachEntry and test\n\n* adds Cache.ForEach\n\n* facepalm\n\n* simplify",
"is_bot": false,
"headline": "Adds Cache.ForEachEntry() (#452)",
"author_name": "Johan Lindh",
"author_login": "linkdata",
"committed_at": "2026-03-03T08:52:45Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 53,
"commits_last_year": 141,
"latest_release_at": "2026-07-19T17:45:09Z",
"latest_release_tag": "v1.7.3",
"releases_from_tags": false,
"days_since_last_push": 2,
"active_weeks_last_year": 15,
"days_since_latest_release": 7,
"mean_days_between_releases": 25.9
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": true,
"health_percentage": 85,
"has_issue_template": false,
"has_code_of_conduct": true,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/semihalev/sdns",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/semihalev/sdns",
"is_deprecated": false,
"latest_version": "v1.7.3",
"repository_url": "https://github.com/semihalev/sdns",
"versions_count": 54,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-07-19T17:12:44Z",
"latest_version_yanked": null,
"days_since_latest_publish": 7
}
]
},
"popularity": {
"forks": 69,
"stars": 1070,
"watchers": 20,
"fork_history": {
"days": [
{
"date": "2018-10-15",
"count": 1
},
{
"date": "2018-10-16",
"count": 1
},
{
"date": "2018-10-31",
"count": 1
},
{
"date": "2018-11-01",
"count": 5
},
{
"date": "2018-11-25",
"count": 1
},
{
"date": "2018-12-03",
"count": 1
},
{
"date": "2018-12-06",
"count": 1
},
{
"date": "2019-03-05",
"count": 1
},
{
"date": "2019-09-16",
"count": 1
},
{
"date": "2019-09-20",
"count": 1
},
{
"date": "2020-06-26",
"count": 1
},
{
"date": "2020-07-20",
"count": 1
},
{
"date": "2020-07-28",
"count": 1
},
{
"date": "2020-10-02",
"count": 1
},
{
"date": "2020-11-18",
"count": 1
},
{
"date": "2021-02-22",
"count": 1
},
{
"date": "2021-03-08",
"count": 1
},
{
"date": "2021-04-07",
"count": 1
},
{
"date": "2021-04-09",
"count": 1
},
{
"date": "2021-05-29",
"count": 1
},
{
"date": "2021-09-16",
"count": 1
},
{
"date": "2022-01-27",
"count": 1
},
{
"date": "2022-03-28",
"count": 1
},
{
"date": "2022-06-14",
"count": 1
},
{
"date": "2022-07-01",
"count": 1
},
{
"date": "2022-08-16",
"count": 1
},
{
"date": "2022-08-23",
"count": 2
},
{
"date": "2022-09-26",
"count": 1
},
{
"date": "2022-11-17",
"count": 1
},
{
"date": "2022-12-26",
"count": 1
},
{
"date": "2023-04-01",
"count": 1
},
{
"date": "2023-04-26",
"count": 1
},
{
"date": "2023-06-24",
"count": 1
},
{
"date": "2023-07-10",
"count": 1
},
{
"date": "2023-08-12",
"count": 1
},
{
"date": "2023-08-19",
"count": 2
},
{
"date": "2023-10-10",
"count": 1
},
{
"date": "2023-11-03",
"count": 1
},
{
"date": "2023-12-02",
"count": 1
},
{
"date": "2023-12-17",
"count": 1
},
{
"date": "2024-01-23",
"count": 1
},
{
"date": "2024-06-24",
"count": 1
},
{
"date": "2024-07-03",
"count": 1
},
{
"date": "2024-07-21",
"count": 1
},
{
"date": "2025-01-07",
"count": 1
},
{
"date": "2025-03-06",
"count": 1
},
{
"date": "2025-03-14",
"count": 1
},
{
"date": "2025-04-29",
"count": 1
},
{
"date": "2025-06-17",
"count": 1
},
{
"date": "2025-06-23",
"count": 1
},
{
"date": "2025-09-06",
"count": 1
},
{
"date": "2025-09-23",
"count": 1
},
{
"date": "2025-12-18",
"count": 1
},
{
"date": "2025-12-28",
"count": 1
},
{
"date": "2026-01-17",
"count": 1
},
{
"date": "2026-01-19",
"count": 1
},
{
"date": "2026-01-24",
"count": 1
},
{
"date": "2026-02-13",
"count": 1
},
{
"date": "2026-02-27",
"count": 1
},
{
"date": "2026-02-28",
"count": 1
},
{
"date": "2026-04-19",
"count": 1
},
{
"date": "2026-05-09",
"count": 1
}
],
"complete": true,
"collected": 68,
"total_forks": 69
},
"star_history": null,
"open_issues_and_prs": 4
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": true,
"has_mcp_signal": false,
"bootstrap_files": [
"Makefile"
],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [],
"toolchain_manifests": [
"go.mod"
],
"largest_source_bytes": 100632,
"source_files_sampled": 256,
"oversized_source_files": 1,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"dependencies": {
"manifests": [
"go.mod"
],
"advisories": {
"error": null,
"scope": "repository_graph",
"source": "osv",
"findings": [
{
"name": "golang.org/x/crypto",
"direct": false,
"version": "v0.52.0",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5932"
],
"fixed_version": null,
"advisory_count": 1,
"oldest_advisory_days": 19
},
{
"name": "golang.org/x/net",
"direct": false,
"version": "v0.55.0",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5942"
],
"fixed_version": "0.56.0",
"advisory_count": 1,
"oldest_advisory_days": 12
},
{
"name": "golang.org/x/text",
"direct": false,
"version": "v0.37.0",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5970"
],
"fixed_version": "0.39.0",
"advisory_count": 1,
"oldest_advisory_days": 12
}
],
"collected": true,
"malicious": [],
"truncated": false,
"by_severity": {
"unknown": 3
},
"advisory_count": 3,
"affected_count": 3,
"assessed_count": 70,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"go"
],
"dependencies": [
{
"name": "github.com/BurntSushi/toml",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.6.0"
},
{
"name": "github.com/cespare/xxhash/v2",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v2.3.0"
},
{
"name": "github.com/fsnotify/fsnotify",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.10.1"
},
{
"name": "github.com/miekg/dns",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.1.72"
},
{
"name": "github.com/prometheus/client_golang",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.23.2"
},
{
"name": "github.com/prometheus/client_model",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.6.2"
},
{
"name": "github.com/quic-go/quic-go",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.60.0"
},
{
"name": "github.com/semihalev/zlog/v2",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v2.0.8"
},
{
"name": "github.com/spf13/cobra",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.10.2"
},
{
"name": "github.com/stretchr/testify",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.11.1"
},
{
"name": "github.com/yl2chen/cidranger",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.0.2"
},
{
"name": "golang.org/x/sync",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.22.0"
},
{
"name": "golang.org/x/sys",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.47.0"
},
{
"name": "golang.org/x/time",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.15.0"
},
{
"name": "k8s.io/api",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.36.2"
},
{
"name": "k8s.io/apimachinery",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.36.2"
},
{
"name": "k8s.io/client-go",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.36.2"
}
],
"all_dependencies": {
"error": null,
"source": "github-sbom",
"packages": [
{
"name": "github.com/burntsushi/toml",
"direct": true,
"version": "v1.6.0",
"ecosystem": "go"
},
{
"name": "github.com/cespare/xxhash/v2",
"direct": true,
"version": "v2.3.0",
"ecosystem": "go"
},
{
"name": "github.com/fsnotify/fsnotify",
"direct": true,
"version": "v1.10.1",
"ecosystem": "go"
},
{
"name": "github.com/miekg/dns",
"direct": true,
"version": "v1.1.72",
"ecosystem": "go"
},
{
"name": "github.com/prometheus/client_golang",
"direct": true,
"version": "v1.23.2",
"ecosystem": "go"
},
{
"name": "github.com/prometheus/client_model",
"direct": true,
"version": "v0.6.2",
"ecosystem": "go"
},
{
"name": "github.com/quic-go/quic-go",
"direct": true,
"version": "v0.60.0",
"ecosystem": "go"
},
{
"name": "github.com/semihalev/zlog/v2",
"direct": true,
"version": "v2.0.8",
"ecosystem": "go"
},
{
"name": "github.com/spf13/cobra",
"direct": true,
"version": "v1.10.2",
"ecosystem": "go"
},
{
"name": "github.com/stretchr/testify",
"direct": true,
"version": "v1.11.1",
"ecosystem": "go"
},
{
"name": "github.com/yl2chen/cidranger",
"direct": true,
"version": "v1.0.2",
"ecosystem": "go"
},
{
"name": "golang.org/x/sync",
"direct": true,
"version": "v0.22.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/sys",
"direct": true,
"version": "v0.47.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/time",
"direct": true,
"version": "v0.15.0",
"ecosystem": "go"
},
{
"name": "k8s.io/api",
"direct": true,
"version": "v0.36.2",
"ecosystem": "go"
},
{
"name": "k8s.io/apimachinery",
"direct": true,
"version": "v0.36.2",
"ecosystem": "go"
},
{
"name": "k8s.io/client-go",
"direct": true,
"version": "v0.36.2",
"ecosystem": "go"
},
{
"name": "github.com/beorn7/perks",
"direct": false,
"version": "v1.0.1",
"ecosystem": "go"
},
{
"name": "github.com/davecgh/go-spew",
"direct": false,
"version": "v1.1.2-0.20180830191138-d8f796af33cc",
"ecosystem": "go"
},
{
"name": "github.com/emicklei/go-restful/v3",
"direct": false,
"version": "v3.13.0",
"ecosystem": "go"
},
{
"name": "github.com/fxamacker/cbor/v2",
"direct": false,
"version": "v2.9.1",
"ecosystem": "go"
},
{
"name": "github.com/go-logr/logr",
"direct": false,
"version": "v1.4.3",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/jsonpointer",
"direct": false,
"version": "v0.23.1",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/jsonreference",
"direct": false,
"version": "v0.21.5",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/cmdutils",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/conv",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/fileutils",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/jsonname",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/jsonutils",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/loading",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/mangling",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/netutils",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/stringutils",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/typeutils",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/go-openapi/swag/yamlutils",
"direct": false,
"version": "v0.26.0",
"ecosystem": "go"
},
{
"name": "github.com/google/gnostic-models",
"direct": false,
"version": "v0.7.1",
"ecosystem": "go"
},
{
"name": "github.com/google/uuid",
"direct": false,
"version": "v1.6.0",
"ecosystem": "go"
},
{
"name": "github.com/inconshreveable/mousetrap",
"direct": false,
"version": "v1.1.0",
"ecosystem": "go"
},
{
"name": "github.com/json-iterator/go",
"direct": false,
"version": "v1.1.12",
"ecosystem": "go"
},
{
"name": "github.com/kr/text",
"direct": false,
"version": "v0.2.0",
"ecosystem": "go"
},
{
"name": "github.com/modern-go/concurrent",
"direct": false,
"version": "v0.0.0-20180306012644-bacd9c7ef1dd",
"ecosystem": "go"
},
{
"name": "github.com/modern-go/reflect2",
"direct": false,
"version": "v1.0.3-0.20250322232337-35a7c28c31ee",
"ecosystem": "go"
},
{
"name": "github.com/munnerz/goautoneg",
"direct": false,
"version": "v0.0.0-20191010083416-a7dc8b61c822",
"ecosystem": "go"
},
{
"name": "github.com/pmezard/go-difflib",
"direct": false,
"version": "v1.0.1-0.20181226105442-5d4384ee4fb2",
"ecosystem": "go"
},
{
"name": "github.com/prometheus/common",
"direct": false,
"version": "v0.67.5",
"ecosystem": "go"
},
{
"name": "github.com/prometheus/procfs",
"direct": false,
"version": "v0.20.1",
"ecosystem": "go"
},
{
"name": "github.com/quic-go/qpack",
"direct": false,
"version": "v0.6.0",
"ecosystem": "go"
},
{
"name": "github.com/spf13/pflag",
"direct": false,
"version": "v1.0.10",
"ecosystem": "go"
},
{
"name": "github.com/x448/float16",
"direct": false,
"version": "v0.8.4",
"ecosystem": "go"
},
{
"name": "go.yaml.in/yaml/v2",
"direct": false,
"version": "v2.4.4",
"ecosystem": "go"
},
{
"name": "go.yaml.in/yaml/v3",
"direct": false,
"version": "v3.0.4",
"ecosystem": "go"
},
{
"name": "golang.org/x/crypto",
"direct": false,
"version": "v0.52.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/mod",
"direct": false,
"version": "v0.35.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/net",
"direct": false,
"version": "v0.55.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/oauth2",
"direct": false,
"version": "v0.36.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/term",
"direct": false,
"version": "v0.43.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/text",
"direct": false,
"version": "v0.37.0",
"ecosystem": "go"
},
{
"name": "golang.org/x/tools",
"direct": false,
"version": "v0.44.0",
"ecosystem": "go"
},
{
"name": "google.golang.org/protobuf",
"direct": false,
"version": "v1.36.12-0.20260120151049-f2248ac996af",
"ecosystem": "go"
},
{
"name": "gopkg.in/evanphx/json-patch.v4",
"direct": false,
"version": "v4.13.0",
"ecosystem": "go"
},
{
"name": "gopkg.in/inf.v0",
"direct": false,
"version": "v0.9.1",
"ecosystem": "go"
},
{
"name": "gopkg.in/yaml.v3",
"direct": false,
"version": "v3.0.1",
"ecosystem": "go"
},
{
"name": "k8s.io/klog/v2",
"direct": false,
"version": "v2.140.0",
"ecosystem": "go"
},
{
"name": "k8s.io/kube-openapi",
"direct": false,
"version": "v0.0.0-20260414162039-ec9c827d403f",
"ecosystem": "go"
},
{
"name": "k8s.io/utils",
"direct": false,
"version": "v0.0.0-20260319190234-28399d86e0b5",
"ecosystem": "go"
},
{
"name": "sigs.k8s.io/json",
"direct": false,
"version": "v0.0.0-20250730193827-2d320260d730",
"ecosystem": "go"
},
{
"name": "sigs.k8s.io/randfill",
"direct": false,
"version": "v1.0.0",
"ecosystem": "go"
},
{
"name": "sigs.k8s.io/structured-merge-diff/v6",
"direct": false,
"version": "v6.4.0",
"ecosystem": "go"
},
{
"name": "sigs.k8s.io/yaml",
"direct": false,
"version": "v1.6.0",
"ecosystem": "go"
}
],
"collected": true,
"truncated": false,
"total_count": 70,
"direct_count": 17,
"indirect_count": 53
}
},
"maintainership": {
"issues": {
"open_prs": 4,
"merged_prs": 263,
"open_issues": 0,
"closed_ratio": 1,
"closed_issues": 50,
"closed_unmerged_prs": 181
},
"bus_factor": 1,
"bot_contributors": 1,
"top_contributors": [
{
"type": "User",
"login": "semihalev",
"commits": 876,
"avatar_url": "https://avatars.githubusercontent.com/u/539588?v=4"
},
{
"type": "User",
"login": "c1982",
"commits": 17,
"avatar_url": "https://avatars.githubusercontent.com/u/45575?v=4"
},
{
"type": "User",
"login": "hstern",
"commits": 2,
"avatar_url": "https://avatars.githubusercontent.com/u/6068107?v=4"
},
{
"type": "User",
"login": "MaciejTe",
"commits": 2,
"avatar_url": "https://avatars.githubusercontent.com/u/22226367?v=4"
},
{
"type": "User",
"login": "PeterDaveHello",
"commits": 2,
"avatar_url": "https://avatars.githubusercontent.com/u/3691490?v=4"
},
{
"type": "User",
"login": "SAY-5",
"commits": 2,
"avatar_url": "https://avatars.githubusercontent.com/u/240962040?v=4"
},
{
"type": "User",
"login": "gordonbondon",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/9439689?v=4"
},
{
"type": "User",
"login": "benleb",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/512997?v=4"
},
{
"type": "User",
"login": "linkdata",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/2185977?v=4"
},
{
"type": "User",
"login": "aybarsm",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/39916128?v=4"
}
],
"contributors_sampled": 14,
"top_contributor_share": 0.964
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"claude.yml",
"codeql.yml",
"docker.yml",
"release.yml"
],
"has_docs_dir": true,
"linter_configs": [
".golangci.yml"
],
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 6,
"reason": "branch protection is not maximal on development and all release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": 10,
"reason": "29 out of 29 merged PRs checked by a CI test -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 5,
"reason": "badge detected: Passing",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 9,
"reason": "Found 17/18 approved changesets -- score normalized to 9",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 10,
"reason": "project has 5 contributing companies or organizations",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 10,
"reason": "update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 10,
"reason": "project is fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "30 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 10,
"reason": "SAST tool is run on all commits",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 10,
"reason": "security policy file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": 0,
"reason": "Project has not signed or included provenance with any releases.",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 7,
"reason": "3 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "6f745fef3c0d2058044f20d98063bb6f0eac671a",
"ran_at": "2026-07-27T12:28:52Z",
"aggregate_score": 7.4,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": true,
"has_security_policy": true,
"has_dependabot_config": true
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-26T00:32:12Z",
"oldest_open_prs": [
{
"number": 519,
"created_at": "2026-07-23T15:32:38Z",
"last_comment_at": "2026-07-23T15:32:39Z",
"last_comment_author": "dependabot"
},
{
"number": 520,
"created_at": "2026-07-23T15:32:44Z",
"last_comment_at": "2026-07-23T15:32:45Z",
"last_comment_author": "dependabot"
},
{
"number": 521,
"created_at": "2026-07-23T15:32:50Z",
"last_comment_at": "2026-07-23T15:32:51Z",
"last_comment_author": "dependabot"
},
{
"number": 522,
"created_at": "2026-07-24T15:32:21Z",
"last_comment_at": "2026-07-24T15:32:21Z",
"last_comment_author": "dependabot"
}
],
"last_merged_pr_at": "2026-07-19T17:12:45Z",
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/semihalev/sdns",
"host": "github.com",
"name": "sdns",
"owner": "semihalev"
},
"metrics": {
"overall": {
"key": "overall",
"band": "good",
"name": "Overall health",
"note": null,
"notes": [],
"value": 78,
"inputs": {
"security": 79,
"vitality": 80,
"community": 78,
"governance": 66,
"engineering": 90
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 80,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 74,
"inputs": {
"commits_last_year": 141,
"human_commit_share": 0.75,
"days_since_last_push": 2,
"active_weeks_last_year": 15
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 2 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 2
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "15/52 weeks with commits",
"points": 10.4,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 15
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "141 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 141
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"releases_count": 53,
"latest_release_tag": "v1.7.3",
"releases_from_tags": false,
"days_since_latest_release": 7,
"mean_days_between_releases": 25.9
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "53 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 53
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 7 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 7
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~25.9 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 25.9
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "maintained",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": null,
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": 7,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "last human commit 7 days ago",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_maintained",
"params": {
"days": 7
}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "good",
"name": "Community & Adoption",
"value": 78,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "good",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 72,
"inputs": {
"forks": 69,
"stars": 1070,
"watchers": 20,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "1,070 stars",
"points": 49.1,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 1070
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "69 forks",
"points": 15.3,
"status": "partial",
"details": [
{
"code": "forks",
"params": {
"count": 69
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "20 watchers",
"points": 7.1,
"status": "partial",
"details": [
{
"code": "watchers",
"params": {
"count": 20
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "excellent",
"name": "Community health",
"note": null,
"notes": [],
"value": 85,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": true,
"has_issue_template": false,
"has_code_of_conduct": true,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 18,
"status": "met",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 13.5,
"status": "met",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 66,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "at_risk",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 33,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 14,
"top_contributor_share": 0.964
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 96% of commits",
"points": 0.8,
"status": "partial",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 96
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "14 contributors",
"points": 13.5,
"status": "met",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 14
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 5 contributing companies or organizations",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "good",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 83,
"inputs": {
"merged_prs": 263,
"open_issues": 0,
"closed_issues": 50,
"issue_closed_ratio": 1,
"closed_unmerged_prs": 181
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "100% of issues closed",
"points": 46.8,
"status": "met",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 100
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "263/444 decided PRs merged",
"points": 22.7,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 263,
"decided": 444
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 17/18 approved changesets -- score normalized to 9",
"points": 13.5,
"status": "partial",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "moderate",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 62,
"inputs": {
"followers": 153,
"owner_type": "User",
"is_verified": null,
"owner_login": "semihalev",
"public_repos": 38,
"account_age_days": 5689
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "personal (user) account",
"points": 10,
"status": "partial",
"details": [
{
"code": "owner_personal",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": "not applicable to user accounts",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_applicable_to_user_accounts",
"params": {}
}
],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "153 followers of semihalev",
"points": 15.7,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 153,
"login": "semihalev"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "38 public repos, account ~15 yr old",
"points": 23.6,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 38
}
},
{
"code": "account_age_years",
"params": {
"years": 15
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/semihalev/sdns"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 7
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on go",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "go"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 7 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 7
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "54 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 54
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "excellent",
"name": "Engineering Quality",
"value": 90,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "good",
"name": "Engineering practices",
"note": null,
"notes": [],
"value": 84,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "5 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 5
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": ".golangci.yml",
"points": 16,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".golangci.yml"
}
}
],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "29 out of 29 merged PRs checked by a CI test -- score normalized to 10",
"points": 20,
"status": "met",
"details": [],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "excellent",
"name": "Documentation",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"topics": [
"dns",
"dns-server",
"dnssec",
"dns-resolver",
"edns",
"dns-over-https",
"dns-over-tls",
"resolver",
"dns-privacy",
"dns-over-quic"
],
"has_wiki": true,
"homepage": "https://sdns.dev",
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": "https://sdns.dev",
"points": 15,
"status": "met",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": "10 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 10
}
}
],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "good",
"name": "Security",
"value": 79,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "good",
"name": "Security posture",
"note": null,
"notes": [],
"value": 74,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 18,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 0,
"scorecard_aggregate": 7.4
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection is not maximal on development and all release branches",
"points": 4.5,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "29 out of 29 merged PRs checked by a CI test -- score normalized to 10",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "badge detected: Passing",
"points": 1.2,
"status": "partial",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 17/18 approved changesets -- score normalized to 9",
"points": 6.8,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 5 contributing companies or organizations",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "update tool detected",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is fuzzed",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "30 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "SAST tool is run on all commits",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "3 existing vulnerabilities detected",
"points": 5.2,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "dependency_advisories",
"band": "excellent",
"name": "Dependency advisories",
"note": "Excluded from scoring (no data or not applicable): Indirect dependencies free of known advisories, No advisories left outstanding. Remaining weights renormalized. Matched 70 resolved dependencies against OSV. This repository publishes no package the index resolves, so the repository dependency graph was assessed instead. That graph mixes development and test pins with shipped dependencies, so only the declared runtime dependencies are scored; transitive findings are reported as context and excluded from the score. Reachability is not analyzed.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"indirect_dependencies_free_of_known_advisories",
"no_advisories_left_outstanding"
]
}
},
{
"code": "weights_renormalized",
"params": {}
},
{
"code": "advisories_scope_repository",
"params": {
"assessed": 70
}
},
{
"code": "advisories_repo_graph_caveat",
"params": {}
},
{
"code": "advisories_reachability",
"params": {}
}
],
"value": 100,
"inputs": {
"source": "osv",
"advisories": 3,
"affected_packages": 3,
"assessed_packages": 70,
"unassessed_packages": 0,
"affected_by_severity": "unknown 3",
"direct_affected_packages": 0
},
"components": [
{
"key": "direct_dependencies_free_of_known_advisories",
"name": "Direct dependencies free of known advisories",
"detail": "no direct dependency carries a known advisory",
"points": 35,
"status": "met",
"details": [
{
"code": "no_direct_advisories",
"params": {}
}
],
"max_points": 35
},
{
"key": "indirect_dependencies_free_of_known_advisories",
"name": "Indirect dependencies free of known advisories",
"detail": "transitive set not separable from development and test dependencies in this scope",
"points": 0,
"status": "excluded",
"details": [
{
"code": "advisories_scope_not_separable",
"params": {}
}
],
"max_points": 25
},
{
"key": "no_advisories_left_outstanding",
"name": "No advisories left outstanding",
"detail": "no advisory carries a publication date",
"points": 0,
"status": "excluded",
"details": [
{
"code": "advisories_no_publication_date",
"params": {}
}
],
"max_points": 40
}
]
},
{
"key": "malicious_dependencies",
"band": "excellent",
"name": "Malicious dependencies",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"source": "osv",
"meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
"packages": [],
"red_flag": false,
"assessed_packages": 70,
"malicious_packages": 0,
"direct_malicious_packages": 0,
"withdrawn_malicious_packages": 0,
"installable_malicious_packages": 0
},
"components": [
{
"key": "no_dependency_reported_as_a_malicious_package",
"name": "No dependency reported as a malicious package",
"detail": "no dependency is reported as a malicious package",
"points": 100,
"status": "met",
"details": [
{
"code": "no_malicious_dependencies",
"params": {}
}
],
"max_points": 100
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 14
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "moderate",
"name": "AI Readiness",
"value": 69,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "at_risk",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.973,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "no CLAUDE.md / AGENTS.md / editor rules",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_instructions",
"params": {}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "73 of 75 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 73,
"sampled": 75
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "good",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 80,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"go.sum"
],
"has_dockerfile": true,
"typed_language": true,
"bootstrap_files": [
"Makefile"
],
"has_devcontainer": false,
"has_linter_config": true,
"typecheck_configs": [],
"agent_commit_share": 0,
"toolchain_manifests": [
"go.mod"
],
"dependency_bot_commit_share": 0.25
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "Makefile",
"points": 18,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Makefile"
}
}
],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": ".golangci.yml",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".golangci.yml"
}
}
],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "Go (statically typed)",
"points": 11,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "Dockerfile, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Dockerfile, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 100",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "25 of the last 100 commits are automated dependency updates",
"points": 8,
"status": "met",
"details": [
{
"code": "dependency_bot_commits",
"params": {
"count": 25,
"sampled": 100
}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 100632,
"source_files_sampled": 256,
"oversized_source_files": 1
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "1/256 source files over 60KB",
"points": 54.8,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 256,
"oversized": 1
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token"
],
"report_type": "repository",
"generated_at": "2026-07-27T12:29:14.963476Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/s/semihalev/sdns.svg",
"full_name": "semihalev/sdns",
"license_state": "standard",
"license_spdx": "MIT"
}