Skip to content

feat: validate allow/denylist references in ClientGroupsBlock - #2016

Merged
0xERR0R merged 4 commits into
0xERR0R:mainfrom
JenswBE:validate-blocking-config
Mar 23, 2026
Merged

0xERR0R merged 4 commits into
0xERR0R:mainfrom
JenswBE:validate-blocking-config

Conversation

@JenswBE

@JenswBE JenswBE commented Mar 15, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #1958.

Just 2 remarks about the code:

  1. Since I use logger.Fatal, it's technically a breaking change when currently an invalid config is used. Another option is to log a warning instead. However, in that case, I would be really nice to consider a strict option or flag to still enforce a failure on invalid references to allowlists or denylists (and other future breaking validations on the config).
  2. The check is case sensitive. I checked resolver/blocking_resolver.go, but didn't see a place where the names of the denylists and allowlists are lowered (contrary to the names of the clientGroupLists). If needed, I can make it case-insensitive.

@0xERR0R 0xERR0R added the 🔨 enhancement New feature or request label Mar 16, 2026
@0xERR0R 0xERR0R added this to the v0.30.0 milestone Mar 16, 2026
@0xERR0R 0xERR0R changed the title fix: validate allow/denylist references in ClientGroupsBlock feat: validate allow/denylist references in ClientGroupsBlock Mar 16, 2026
@codecov

codecov Bot commented Mar 16, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.52%. Comparing base (b4a1d54) to head (5099c65).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
config/config.go 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2016      +/-   ##
==========================================
- Coverage   89.52%   89.52%   -0.01%     
==========================================
  Files          95       95              
  Lines        6960     6977      +17     
==========================================
+ Hits         6231     6246      +15     
- Misses        559      560       +1     
- Partials      170      171       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@0xERR0R 0xERR0R left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thank you for your contribution! Please check my comments. Regarding the case-sensitive group names: yes, you're right. Imho, it would make sense to make them case-insensitive or at least print warning if user defines 2 different groups which are basically equal if case insensitive

Comment thread config/config.go Outdated

// Blocking validation
if err := cfg.Blocking.validate(); err != nil {
logger.Fatal(err)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

As you mentioned, this is a breaking change. Installations with invalid config are silently working now and with this change, we will break them. I think it would be better to log it here as warning

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I converted it to a warning in 583c254. Unfortunately, it seems the config is loaded twice: once in the root command and once in the serve command. Therefore, the warning is logged twice:

image

Note: The Load config from ... was just for debugging and has been removed from the final commit.

Comment thread config/blocking.go Outdated
@JenswBE

JenswBE commented Mar 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Regarding the case-sensitive group names, converting to case insensitive would also be a breaking change to the config parsing as the following won't work anymore as expected (one will overwrite the other depending on the order):

  denylists:
    main:
      - ...
    MAIN:
      - ...
  clientGroupsBlock:
    default:
      - main

Therefore, I tried to add code for the case hinting as a warning. Unfortunately, this would make the validation code much more complex as we have to lowercase all keys, but keep the original casing in case someone defined the same key with different cases (main and MAIN in above example). Leading to e.g. a map[string]map[string]bool or map[string][]string for the checking and an additional []string for storing the suggestion (unless you want to loop each time a slice for checking the list key exists).

Since it makes the code hard to read due to big complexity increase, I didn't include this additional check in the code and just kept the Available: hint in the error.

Another solution is to introduce an opt-in strict flag or config option which:

  • Considers a non-existing allow/denylist reference a fatal instead of warn
  • Enforces case-insensitivity for the allow/denylist names and their references
  • Includes any future breaking validations of the config file

This way the case check is much simpler and detecting a failure is easier compared to scraping the logs for warnings. As it's an opt-in, only users which explicitly agreed on breaking code validations are impacted.

What do you think?

@0xERR0R

0xERR0R commented Mar 19, 2026

Copy link
Copy Markdown
Owner

For me, the current implementation is ok. We don't break existing configs, and print only warning. We can skip the duplicates detection if the solution is to complex. If you have nothing to change on your PR, we can merge it

@JenswBE

JenswBE commented Mar 19, 2026

Copy link
Copy Markdown
Contributor Author

Nothing to change on the PR, so feel free to merge. Thanks for the reviews and follow-up of this PR!

@0xERR0R
0xERR0R enabled auto-merge (squash) March 19, 2026 21:26
@0xERR0R
0xERR0R merged commit c95cfba into 0xERR0R:main Mar 23, 2026
12 of 13 checks passed
dadezzz pushed a commit to dadezzz/infra_docker-compose that referenced this pull request May 19, 2026
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/0xerr0r/blocky](https://github.com/0xERR0R/blocky) | minor | `v0.29.0` → `v0.30.0` |

---

### Release Notes

<details>
<summary>0xERR0R/blocky (ghcr.io/0xerr0r/blocky)</summary>

### [`v0.30.0`](https://github.com/0xERR0R/blocky/releases/tag/v0.30.0)

[Compare Source](0xERR0R/blocky@v0.29.0...v0.30.0)

#### Changelog

##### Features

- [`0de3fac`](0xERR0R/blocky@0de3fac): feat(sudn): handle resolver.arpa zone per RFC 9462 (DDR) ([#&#8203;2059](0xERR0R/blocky#2059)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`c32863d`](0xERR0R/blocky@c32863d): feat: add DNS-over-QUIC (DoQ) upstream support (RFC 9250) ([#&#8203;2013](0xERR0R/blocky#2013)) ([@&#8203;elsbrock](https://github.com/elsbrock))
- [`22b0bdd`](0xERR0R/blocky@22b0bdd): feat: add schedule-based blocking for deny/allowlist groups ([#&#8203;2037](0xERR0R/blocky#2037)) ([@&#8203;alessandrocuzzocrea](https://github.com/alessandrocuzzocrea))
- [`842dda9`](0xERR0R/blocky@842dda9): feat: serve DoH over HTTP/3 (DoH3, RFC 9114) ([#&#8203;2060](0xERR0R/blocky#2060)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`c95cfba`](0xERR0R/blocky@c95cfba): feat: validate allow/denylist references in ClientGroupsBlock ([#&#8203;2016](0xERR0R/blocky#2016)) ([@&#8203;JenswBE](https://github.com/JenswBE))

##### Bug fixes

- [`10d6446`](0xERR0R/blocky@10d6446): fix(api): keep /api/query response unobfuscated when log.privacy is on ([#&#8203;2058](0xERR0R/blocky#2058)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`fb28513`](0xERR0R/blocky@fb28513): fix: enhance DNS bootstrapping by utilizing IPs from DNS stamps ([#&#8203;1995](0xERR0R/blocky#1995)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`2ffe18a`](0xERR0R/blocky@2ffe18a): fix: use RFC 4034 canonical DNS name ordering for NSEC coverage check ([#&#8203;2017](0xERR0R/blocky#2017)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))

##### Build and dependencies

- [`a8015c8`](0xERR0R/blocky@a8015c8): build(deps): bump codecov/codecov-action from 5 to 6 ([#&#8203;2029](0xERR0R/blocky#2029)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`89aee54`](0xERR0R/blocky@89aee54): build(deps): bump crazy-max/ghaction-docker-meta from 5 to 6 ([#&#8203;2005](0xERR0R/blocky#2005)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`98f41c4`](0xERR0R/blocky@98f41c4): build(deps): bump dependabot/fetch-metadata from 2 to 3 ([#&#8203;2031](0xERR0R/blocky#2031)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`83434c5`](0xERR0R/blocky@83434c5): build(deps): bump docker/build-push-action from 6 to 7 ([#&#8203;2004](0xERR0R/blocky#2004)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`0c9e176`](0xERR0R/blocky@0c9e176): build(deps): bump docker/login-action from 3 to 4 ([#&#8203;2003](0xERR0R/blocky#2003)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`67dabab`](0xERR0R/blocky@67dabab): build(deps): bump docker/setup-buildx-action from 3 to 4 ([#&#8203;2006](0xERR0R/blocky#2006)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`def8e95`](0xERR0R/blocky@def8e95): build(deps): bump docker/setup-qemu-action from 3 to 4 ([#&#8203;2002](0xERR0R/blocky#2002)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`733f21c`](0xERR0R/blocky@733f21c): build(deps): bump github.com/alicebob/miniredis/v2 from 2.37.0 to 2.38.0 ([#&#8203;2055](0xERR0R/blocky#2055)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`5130c3e`](0xERR0R/blocky@5130c3e): build(deps): bump github.com/breml/rootcerts from 0.3.4 to 0.3.5 ([#&#8203;2040](0xERR0R/blocky#2040)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`08e53d7`](0xERR0R/blocky@08e53d7): build(deps): bump github.com/docker/go-connections from 0.6.0 to 0.7.0 ([#&#8203;2038](0xERR0R/blocky#2038)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`95225f8`](0xERR0R/blocky@95225f8): build(deps): bump github.com/jackc/pgx/v5 from 5.7.5 to 5.9.0 ([#&#8203;2039](0xERR0R/blocky#2039)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`3274076`](0xERR0R/blocky@3274076): build(deps): bump github.com/jackc/pgx/v5 from 5.9.0 to 5.9.2 ([#&#8203;2041](0xERR0R/blocky#2041)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`7a279fc`](0xERR0R/blocky@7a279fc): build(deps): bump github.com/moby/moby/api from 1.54.1 to 1.54.2 ([#&#8203;2050](0xERR0R/blocky#2050)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`1a04f45`](0xERR0R/blocky@1a04f45): build(deps): bump github.com/oapi-codegen/runtime from 1.1.2 to 1.2.0 ([#&#8203;1999](0xERR0R/blocky#1999)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`076c880`](0xERR0R/blocky@076c880): build(deps): bump github.com/oapi-codegen/runtime from 1.2.0 to 1.3.0 ([#&#8203;2021](0xERR0R/blocky#2021)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`b7fddae`](0xERR0R/blocky@b7fddae): build(deps): bump github.com/oapi-codegen/runtime from 1.3.0 to 1.3.1 ([#&#8203;2028](0xERR0R/blocky#2028)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`9c8f11c`](0xERR0R/blocky@9c8f11c): build(deps): bump github.com/oapi-codegen/runtime from 1.3.1 to 1.4.0 ([#&#8203;2030](0xERR0R/blocky#2030)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`62a7e4c`](0xERR0R/blocky@62a7e4c): build(deps): bump github.com/onsi/ginkgo/v2 from 2.28.1 to 2.28.2 ([#&#8203;2042](0xERR0R/blocky#2042)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`56dfb1d`](0xERR0R/blocky@56dfb1d): build(deps): bump github.com/onsi/ginkgo/v2 from 2.28.2 to 2.28.3 ([#&#8203;2044](0xERR0R/blocky#2044)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`adb9457`](0xERR0R/blocky@adb9457): build(deps): bump github.com/onsi/ginkgo/v2 from 2.28.3 to 2.29.0 ([#&#8203;2057](0xERR0R/blocky#2057)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`5d6da86`](0xERR0R/blocky@5d6da86): build(deps): bump github.com/onsi/gomega from 1.39.1 to 1.40.0 ([#&#8203;2043](0xERR0R/blocky#2043)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`6ac0c33`](0xERR0R/blocky@6ac0c33): build(deps): bump github.com/onsi/gomega from 1.40.0 to 1.41.0 ([#&#8203;2056](0xERR0R/blocky#2056)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`14047f2`](0xERR0R/blocky@14047f2): build(deps): bump github.com/quic-go/quic-go from 0.59.0 to 0.59.1 ([#&#8203;2054](0xERR0R/blocky#2054)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`670daf3`](0xERR0R/blocky@670daf3): build(deps): bump github.com/testcontainers/testcontainers-go/modules/mariadb from 0.40.0 to 0.41.0 ([#&#8203;2011](0xERR0R/blocky#2011)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`ecd41d6`](0xERR0R/blocky@ecd41d6): build(deps): bump github.com/testcontainers/testcontainers-go/modules/postgres from 0.40.0 to 0.41.0 ([#&#8203;2012](0xERR0R/blocky#2012)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`5c9df81`](0xERR0R/blocky@5c9df81): build(deps): bump github.com/testcontainers/testcontainers-go/modules/redis from 0.40.0 to 0.41.0 ([#&#8203;2009](0xERR0R/blocky#2009)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`0f1b3f3`](0xERR0R/blocky@0f1b3f3): build(deps): bump go.opentelemetry.io/otel/sdk from 1.35.0 to 1.40.0 ([#&#8203;2001](0xERR0R/blocky#2001)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`6a06aa4`](0xERR0R/blocky@6a06aa4): build(deps): bump go.opentelemetry.io/otel/sdk from 1.39.0 to 1.43.0 ([#&#8203;2047](0xERR0R/blocky#2047)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`394a585`](0xERR0R/blocky@394a585): build(deps): bump golang.org/x/net from 0.51.0 to 0.52.0 ([#&#8203;2014](0xERR0R/blocky#2014)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`f7718ae`](0xERR0R/blocky@f7718ae): build(deps): bump golang.org/x/net from 0.52.0 to 0.53.0 ([#&#8203;2036](0xERR0R/blocky#2036)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`2ea2b65`](0xERR0R/blocky@2ea2b65): build(deps): bump golang.org/x/net from 0.53.0 to 0.54.0 ([#&#8203;2053](0xERR0R/blocky#2053)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`2d36b56`](0xERR0R/blocky@2d36b56): build(deps): bump google.golang.org/grpc from 1.73.0 to 1.79.3 ([#&#8203;2020](0xERR0R/blocky#2020)) ([@&#8203;dependabot](https://github.com/dependabot)\[bot])
- [`bdcd239`](0xERR0R/blocky@bdcd239): build(deps): bump testcontainers-go to v0.42.0 ([#&#8203;2046](0xERR0R/blocky#2046)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`cb2ae25`](0xERR0R/blocky@cb2ae25): build: update golangci-lint ([#&#8203;2008](0xERR0R/blocky#2008)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`fa8250c`](0xERR0R/blocky@fa8250c): build: update goreleaser action ([#&#8203;2024](0xERR0R/blocky#2024)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))

##### Misc

- [`1c43054`](0xERR0R/blocky@1c43054): perf(blocking): keep time.Parse off the schedule hot path ([#&#8203;2049](0xERR0R/blocky#2049)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`b4a1d54`](0xERR0R/blocky@b4a1d54): refactor(e2e): extend e2e tests ([#&#8203;2023](0xERR0R/blocky#2023)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`667044b`](0xERR0R/blocky@667044b): refactor: redis write through cache ([#&#8203;2025](0xERR0R/blocky#2025)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`835e018`](0xERR0R/blocky@835e018): refactor: small quick improvements ([#&#8203;2019](0xERR0R/blocky#2019)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))
- [`94e9212`](0xERR0R/blocky@94e9212): test(e2e): smoke-test schedule-based blocking ([#&#8203;2048](0xERR0R/blocky#2048)) ([@&#8203;0xERR0R](https://github.com/0xERR0R))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xODIuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE4Mi4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

clientGroupsBlock group references not validated

2 participants