Compare commits

...

87 Commits
v0.7.6 ... main

Author SHA1 Message Date
bakito
25e7aeeecb
test: setup cache 2025-10-25 21:54:06 +02:00
bakito-renovate[bot]
b77248d82d
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.12.7 (#684)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-24 20:30:42 +02:00
bakito
85f996c516
fix: correct release task 2025-10-24 19:09:40 +02:00
bakito-renovate[bot]
0d04d693aa
chore(deps): update module github.com/onsi/ginkgo/v2 to v2.27.1 (#682)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-24 18:41:22 +02:00
bakito-renovate[bot]
e5f5321f45
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.12.6 (#680)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-24 18:40:56 +02:00
bakito-renovate[bot]
8b4e78b148
chore(deps): update module github.com/anchore/syft/cmd/syft to v1.36.0 (#681)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-24 18:40:41 +02:00
bakito-renovate[bot]
d306fba8e2
chore(deps): update dependency adguardteam/adguardhome to v0.107.68 (#679)
* fix: upgrade adguardhome schema to v0.107.68

* chore(deps): update dependency adguardteam/adguardhome to v0.107.68

---------

Co-authored-by: bakito <github@bakito.ch>
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-24 18:40:07 +02:00
bakito
5648639607
feat: generate sbom 2025-10-18 15:16:09 +02:00
bakito-renovate[bot]
35c1af2cea
chore(deps): update module golang.org/x/mod to v0.29.0 (#675)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-13 07:58:04 +02:00
dependabot[bot]
2be15795e5
chore(deps): bump github.com/quic-go/quic-go from 0.54.0 to 0.54.1 (#674)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.54.0 to 0.54.1.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.54.0...v0.54.1)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-version: 0.54.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-11 00:08:15 +02:00
bakito-renovate[bot]
2fe94ec964
chore(deps): update k8s.io/utils digest to bc988d5 (#669)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-06 22:55:34 +02:00
bakito-renovate[bot]
e0c00c3ccb
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.12.5 (#671)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-06 22:55:04 +02:00
bakito-renovate[bot]
a90113f470
chore(deps): update module github.com/onsi/ginkgo/v2 to v2.26.0 (#672)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-10-06 22:43:30 +02:00
bakito-renovate[bot]
46ec505fd9
chore(deps): update dependency adguardteam/adguardhome to v0.107.67 (#670)
* chore(deps): update dependency adguardteam/adguardhome to v0.107.67

* Update wait-for-start.sh

* Update read-latest-replica-config.sh

* Update values.yaml

---------

Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
Co-authored-by: Marc Brugger <github@bakito.ch>
2025-10-06 22:33:44 +02:00
bakito-renovate[bot]
5a47f8857d
chore(deps): update module github.com/go-faker/faker/v4 to v4.7.0 (#668)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-29 07:00:24 +02:00
bakito-renovate[bot]
05485821c0
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.12.3 (#667)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-29 06:57:08 +02:00
bakito-renovate[bot]
3cce67b220
chore(deps): update module github.com/gin-gonic/gin to v1.11.0 (#665)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-22 02:49:46 +02:00
bakito-renovate[bot]
0429d86f40
chore(deps): update module github.com/golangci/golangci-lint/v2 to v2.5.0 (#666)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-22 02:49:30 +02:00
bakito-renovate[bot]
731d92e9d8
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.12.2 (#664)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-22 02:47:07 +02:00
bakito-renovate[bot]
7f99704566
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.12.1 (#662)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-16 20:25:06 +02:00
Marc Brugger
5acd3beff5
fix: correct division by 0 issue in web percentage (#661) 2025-09-15 21:00:21 +02:00
bakito
e10830434b
chore: remove openapi patch for fixed upstream / move utils to cmd 2025-09-15 18:47:07 +02:00
bakito-renovate[bot]
c7a1d5dcef
chore(deps): update dependency adguardteam/adguardhome to v0.107.66 (#660)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-15 17:56:45 +02:00
imgbot[bot]
7b4c342631
chore: [ImgBot] Optimize images (#659)
*Total -- 17.52kb -> 4.59kb (73.81%)

/media/adguardhome-sync.svg -- 8.76kb -> 2.29kb (73.81%)
/internal/sync/static/logo.svg -- 8.76kb -> 2.29kb (73.81%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2025-09-15 17:46:26 +02:00
Marc Brugger
700dbd2d63
feat: offline js and css (#658) 2025-09-15 17:37:06 +02:00
Marc Brugger
f5c9e822a7
fix: disable tls feature by default (#657) 2025-09-15 16:26:19 +02:00
bakito
fb5afb2505
fix: correct typo in index page 2025-09-15 08:10:43 +02:00
Marc Brugger
2882785b9b
chore: move pkg to internal (#655) 2025-09-15 08:07:27 +02:00
Marc Brugger
7d9edf4fa0
feat: remove support for deprecated env vars (#654) 2025-09-15 07:59:29 +02:00
apo-mak
bc70795769
fix: Fix typo in RUN_ON_START description (#652) 2025-09-15 07:46:46 +02:00
bakito
ea92d376c7
chore: actions/checkout@v5 2025-09-15 07:21:03 +02:00
bakito-renovate[bot]
16e97cd9b2
chore(deps): update module github.com/go-faker/faker/v4 to v4.6.2 (#653)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-15 06:54:50 +02:00
Marc Brugger
20fe83745f
feat: sync tls config (#651)
* feat: implement tls config sync

* feat: implement workaround for #633

* extend feature test

* add tests
2025-09-14 18:25:36 +02:00
Marc Brugger
961cf4dbb5
feat: implement workaround for #633 (#650) 2025-09-14 18:03:32 +02:00
bakito-renovate[bot]
81d1bbf27b
chore(deps): update module k8s.io/apimachinery to v0.34.1 (#647)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-11 07:31:17 +02:00
Marc Brugger
0fe6bb3a0b
chore: update github actions (#646) 2025-09-08 08:07:23 +02:00
bakito-renovate[bot]
847a38fe1c
chore(deps): update module golang.org/x/mod to v0.28.0 (#645)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-08 07:02:36 +02:00
bakito-renovate[bot]
1db6a5a4e0
chore(deps): update module github.com/onsi/ginkgo/v2 to v2.25.3 (#640)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-05 17:51:15 +02:00
bakito-renovate[bot]
6388eec95f
chore(deps): update module github.com/spf13/cobra to v1.10.1 (#644)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-05 17:09:59 +02:00
bakito
31ac480737
update tools 2025-09-05 17:09:23 +02:00
bakito-renovate[bot]
6877b58b02
chore(deps): update module github.com/prometheus/client_golang to v1.23.2 (#641)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-05 17:07:36 +02:00
bakito-renovate[bot]
d212045058
chore(deps): update module github.com/bakito/semver to v1.1.7 (#639)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-05 17:07:24 +02:00
bakito-renovate[bot]
83f34fb377
chore(deps): update module k8s.io/apimachinery to v0.34.0 (#637)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-01 07:24:25 +02:00
bakito-renovate[bot]
f1a943491a
chore(deps): update module github.com/kubernetes-sigs/controller-tools to v0.19.0 (#636)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-01 06:40:47 +02:00
bakito-renovate[bot]
75d9724db6
chore(deps): update onsi (#635)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-09-01 06:39:59 +02:00
bakito-renovate[bot]
531d63d04f
chore(deps): update onsi (#632)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-25 07:42:02 +02:00
bakito-renovate[bot]
84999be6fc
chore(deps): update module go.uber.org/mock to v0.6.0 (#631)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-25 07:24:49 +02:00
bakito-renovate[bot]
190ccdad8a
chore(deps): update module github.com/uber-go/mock to v0.6.0 (#630)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-25 07:24:30 +02:00
bakito-renovate[bot]
49054242f8
chore(deps): update module github.com/segmentio/golines to v0.13.0 (#629)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-25 07:24:20 +02:00
bakito-renovate[bot]
930684ffc2
chore(deps): update k8s.io/utils digest to 0af2bda (#627)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-25 07:23:58 +02:00
bakito-renovate[bot]
3fac1d2ced
chore(deps): update dependency adguardteam/adguardhome to v0.107.65 (#628)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-25 07:23:48 +02:00
bakito-renovate[bot]
c85579ce4a
chore(deps): update golang docker tag to v1.25 (#625)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-18 06:46:46 +02:00
bakito-renovate[bot]
d0dd73220d
chore(deps): update module github.com/bakito/semver to v1.1.5 (#623)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-18 06:25:31 +02:00
bakito-renovate[bot]
80f4436d98
chore(deps): update module k8s.io/apimachinery to v0.33.4 (#624)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-18 06:25:19 +02:00
bakito-renovate[bot]
fecc60cfca
chore(deps): update module github.com/golangci/golangci-lint/v2 to v2.4.0 (#626)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-18 06:25:04 +02:00
bakito-renovate[bot]
b3d052db80
chore(deps): update module golang.org/x/mod to v0.27.0 (#622)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-11 06:43:10 +02:00
bakito-renovate[bot]
9cd88a0b47
chore(deps): update module github.com/golangci/golangci-lint/v2 to v2.3.1 (#618)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-04 07:41:18 +02:00
bakito-renovate[bot]
56eb522ea5
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.11.2 (#619)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-04 07:41:08 +02:00
bakito-renovate[bot]
e6feaddc15
chore(deps): update module github.com/prometheus/client_golang to v1.23.0 (#620)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-04 07:40:56 +02:00
bakito-renovate[bot]
70ae93f73a
chore(deps): update dependency adguardteam/adguardhome to v0.107.64 (#617)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-08-04 07:40:46 +02:00
bakito-renovate[bot]
c3d6e696a1
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.11.1 (#616)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-07-28 07:46:26 +02:00
bakito-renovate[bot]
89f2a1eb82
chore(deps): update module github.com/golangci/golangci-lint/v2 to v2.3.0 (#614)
* chore(deps): update module github.com/golangci/golangci-lint/v2 to v2.3.0

* fix lint

---------

Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
Co-authored-by: bakito <github@bakito.ch>
2025-07-24 21:11:18 +02:00
bakito-renovate[bot]
307b050579
chore(deps): update module github.com/onsi/gomega to v1.38.0 (#615)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-07-24 20:47:07 +02:00
bakito-renovate[bot]
caddf2a029
chore(deps): update module github.com/oapi-codegen/runtime to v1.1.2 (#610)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-07-21 07:17:34 +02:00
bakito-renovate[bot]
20ff0192d5
chore(deps): update module k8s.io/apimachinery to v0.33.3 (#611)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-07-21 07:17:18 +02:00
bakito-renovate[bot]
7d8cfbaeed
chore(deps): update module github.com/oapi-codegen/oapi-codegen/v2 to v2.5.0 (#612)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-07-21 07:17:04 +02:00
Marc Brugger
b07101c97a
fix: Correct version check and refactor healthz check (#609) 2025-07-16 17:06:17 +02:00
Marc Brugger
447bfb24a9
test: extend versions check #607 (#608) 2025-07-16 07:55:00 +02:00
Marc Brugger
4fff8f4302
test: run goreleaser with --parallelism 2 (#606) 2025-07-14 20:48:51 +02:00
Michael Stegeman
04bd12d7dd
feat: Add OpenBSD support to releaser. (#605)
* Add OpenBSD support to releaser.

* Skip upx on OpenBSD.
2025-07-14 20:01:18 +02:00
bakito-renovate[bot]
4e33a88163
chore(deps): update module golang.org/x/mod to v0.26.0 (#604)
* chore(deps): update module golang.org/x/mod to v0.26.0

* go 1.24.5

---------

Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
Co-authored-by: bakito <github@bakito.ch>
2025-07-13 14:30:32 +02:00
bakito
4a38df1b59
chore: update goreleaser 2025-07-13 09:18:00 +02:00
Marc Brugger
9ec5c0412e
add new logo (#603) 2025-07-13 08:23:12 +02:00
ElevenNotes
01676e12f3
feat: add unauthorized health check based on status (if all success = http OK) (#601)
* feat: add unauthorized health check based on status (if all success = http OK)

* feat: ignore v or other non-numerical version affixes and suffixes

* fix: syntax

* fix: add head not just get
2025-07-10 22:33:46 +02:00
Marc Brugger
78f7d08398
test: add rewrites for e2e test (#600) 2025-07-05 09:25:56 +02:00
bakito-renovate[bot]
11d4d14f4d
chore(deps): update module github.com/golangci/golangci-lint/v2 to v2.2.1 (#598)
* chore(deps): update module github.com/golangci/golangci-lint/v2 to v2.2.1

* ignore revive var-naming

---------

Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
Co-authored-by: bakito <github@bakito.ch>
2025-06-30 20:36:54 +02:00
bakito-renovate[bot]
ff91f4873a
chore(deps): update dependency adguardteam/adguardhome to v0.107.63 (#597)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-06-27 16:43:31 +02:00
bakito-renovate[bot]
778bf7b516
chore(deps): update module k8s.io/apimachinery to v0.33.2 (#596)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-06-23 06:53:46 +02:00
bakito
cce24c1223
docs: add icon to readme 2025-06-19 09:28:38 +02:00
Ted Jangius
b4fabf687b
Add logo (#595) 2025-06-18 21:57:16 +02:00
Joseph Williams
74ae6a9096
Docs: Clarify initial setup instructions for origin and replicas (#593)
* Disambiguate 'Prerequisites' section in README.md

* Correct  part of speech error in 'Prerequisite' section in README.md
2025-06-12 23:48:16 +02:00
bakito-renovate[bot]
92129ab069
chore(deps): update k8s.io/utils digest to 4c0f3b2 (#590)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-06-09 07:59:24 +02:00
bakito-renovate[bot]
d7f50086c3
chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.10.2 (#591)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-06-09 07:59:11 +02:00
bakito-renovate[bot]
50f883337a
chore(deps): update module golang.org/x/mod to v0.25.0 (#592)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-06-09 07:58:52 +02:00
bakito-renovate[bot]
5a35f7c9d1
chore(deps): update dependency adguardteam/adguardhome to v0.107.62 (#589)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-06-01 13:06:59 +02:00
bakito-renovate[bot]
1b1a712a65
chore(deps): update module github.com/santhosh-tekuri/jsonschema/v6 to v6.0.2 (#588)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-05-24 11:02:28 +02:00
bakito-renovate[bot]
724a20e47e
chore(deps): update module github.com/gin-gonic/gin to v1.10.1 (#587)
Co-authored-by: bakito-renovate[bot] <205501741+bakito-renovate[bot]@users.noreply.github.com>
2025-05-24 11:02:17 +02:00
92 changed files with 1212 additions and 789 deletions

View File

@ -42,11 +42,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"

View File

@ -45,7 +45,7 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Modify Dockerfile
run: |

View File

@ -24,7 +24,7 @@ jobs:
protocol: http
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup jq
uses: dcarbone/install-jq-action@v3

View File

@ -15,13 +15,20 @@ jobs:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
- 'name': 'Set up tools cache'
'uses': 'actions/cache@v4'
'with':
'path': "${{ github.workspace }}/bin"
'key': "${{ runner.os }}-${{ github.job }}-tools-${{ hashFiles('.toolbox.mk') }}"
'restore-keys': '${{ runner.os }}-${{ github.job }}-tools-'
- name: Lint
run: make lint
@ -35,13 +42,20 @@ jobs:
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
- 'name': 'Set up tools cache'
'uses': 'actions/cache@v4'
'with':
'path': "${{ github.workspace }}/bin"
'key': "${{ runner.os }}-${{ github.job }}-tools-${{ hashFiles('.toolbox.mk') }}"
'restore-keys': '${{ runner.os }}-${{ github.job }}-tools-'
- name: Model
run: make model
@ -51,6 +65,7 @@ jobs:
- name: Send coverage
if: runner.os == 'Linux'
uses: shogo82148/actions-goveralls@v1
continue-on-error: true
with:
path-to-profile: coverage.out
@ -60,12 +75,19 @@ jobs:
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
- 'name': 'Set up tools cache'
'uses': 'actions/cache@v4'
'with':
'path': "${{ github.workspace }}/bin"
'key': "${{ runner.os }}-${{ github.job }}-tools-${{ hashFiles('.toolbox.mk') }}"
'restore-keys': '${{ runner.os }}-${{ github.job }}-tools-'
- name: Run GoReleaser
run: make test-release

View File

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has been inactive for 60 days. If the issue is still relevant please comment to re-activate the issue. If no action is taken within 7 days, the issue will be marked closed.'

View File

@ -162,6 +162,12 @@ linters:
disabled: true
- name: unused-receiver
disabled: true
- name: var-naming
disabled: true
- name: enforce-switch-style
disabled: true
- name: blank-imports
disabled: true
staticcheck:
checks:
- 'all'

View File

@ -10,6 +10,7 @@ builds:
- linux
- windows
- darwin
- openbsd
goarch:
- 386
- amd64
@ -28,10 +29,14 @@ builds:
goarch: arm
- goos: windows
goarch: arm64
- goos: openbsd
goarch: 386
- goos: openbsd
goarch: arm
hooks:
post:
# don't upx windows binaries as they make trouble with virus scanners
- bash -c 'if [[ "{{ .Path }}" != *.exe ]] && [[ "{{ .Path }}" != *darwin* ]]; then upx {{ .Path }}; fi'
- bash -c 'if [[ "{{ .Path }}" != *.exe ]] && [[ "{{ .Path }}" != *darwin* ]] && [[ "{{ .Path }}" != *openbsd* ]]; then upx {{ .Path }}; fi'
checksum:
name_template: 'checksums.txt'
snapshot:
@ -45,3 +50,5 @@ changelog:
- '^chore'
release:
prerelease: auto
sboms:
- artifacts: archive

View File

@ -8,97 +8,95 @@ TB_LOCALBIN ?= $(TB_LOCALDIR)/bin
$(TB_LOCALBIN):
if [ ! -e $(TB_LOCALBIN) ]; then mkdir -p $(TB_LOCALBIN); fi
# Helper functions
STRIP_V = $(patsubst v%,%,$(1))
## Tool Binaries
TB_CONTROLLER_GEN ?= $(TB_LOCALBIN)/controller-gen
TB_GINKGO ?= $(TB_LOCALBIN)/ginkgo
TB_GOFUMPT ?= $(TB_LOCALBIN)/gofumpt
TB_GOLANGCI_LINT ?= $(TB_LOCALBIN)/golangci-lint
TB_GOLINES ?= $(TB_LOCALBIN)/golines
TB_GORELEASER ?= $(TB_LOCALBIN)/goreleaser
TB_MOCKGEN ?= $(TB_LOCALBIN)/mockgen
TB_OAPI_CODEGEN ?= $(TB_LOCALBIN)/oapi-codegen
TB_SEMVER ?= $(TB_LOCALBIN)/semver
TB_SYFT ?= $(TB_LOCALBIN)/syft
## Tool Versions
# renovate: packageName=sigs.k8s.io/controller-tools/cmd/controller-gen
TB_CONTROLLER_GEN_VERSION ?= v0.18.0
# renovate: packageName=mvdan.cc/gofumpt
TB_GOFUMPT_VERSION ?= v0.8.0
# renovate: packageName=github.com/kubernetes-sigs/controller-tools
TB_CONTROLLER_GEN_VERSION ?= v0.19.0
# renovate: packageName=github.com/golangci/golangci-lint/v2
TB_GOLANGCI_LINT_VERSION ?= v2.1.6
# renovate: packageName=github.com/segmentio/golines
TB_GOLINES_VERSION ?= v0.12.2
TB_GOLANGCI_LINT_VERSION ?= v2.5.0
TB_GOLANGCI_LINT_VERSION_NUM ?= $(call STRIP_V,$(TB_GOLANGCI_LINT_VERSION))
# renovate: packageName=github.com/goreleaser/goreleaser/v2
TB_GORELEASER_VERSION ?= v2.9.0
# renovate: packageName=go.uber.org/mock/mockgen
TB_MOCKGEN_VERSION ?= v0.5.2
TB_GORELEASER_VERSION ?= v2.12.7
TB_GORELEASER_VERSION_NUM ?= $(call STRIP_V,$(TB_GORELEASER_VERSION))
# renovate: packageName=github.com/uber-go/mock
TB_MOCKGEN_VERSION ?= v0.6.0
# renovate: packageName=github.com/oapi-codegen/oapi-codegen/v2
TB_OAPI_CODEGEN_VERSION ?= v2.4.1
TB_OAPI_CODEGEN_VERSION ?= v2.5.0
# renovate: packageName=github.com/bakito/semver
TB_SEMVER_VERSION ?= v1.1.3
TB_SEMVER_VERSION ?= v1.1.7
TB_SEMVER_VERSION_NUM ?= $(call STRIP_V,$(TB_SEMVER_VERSION))
# renovate: packageName=github.com/anchore/syft/cmd/syft
TB_SYFT_VERSION ?= v1.36.0
TB_SYFT_VERSION_NUM ?= $(call STRIP_V,$(TB_SYFT_VERSION))
## Tool Installer
.PHONY: tb.controller-gen
tb.controller-gen: $(TB_CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(TB_CONTROLLER_GEN): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/controller-gen || GOBIN=$(TB_LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(TB_CONTROLLER_GEN_VERSION)
tb.controller-gen: ## Download controller-gen locally if necessary.
@test -s $(TB_CONTROLLER_GEN) || \
GOBIN=$(TB_LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(TB_CONTROLLER_GEN_VERSION)
.PHONY: tb.ginkgo
tb.ginkgo: $(TB_GINKGO) ## Download ginkgo locally if necessary.
$(TB_GINKGO): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/ginkgo || GOBIN=$(TB_LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo
.PHONY: tb.gofumpt
tb.gofumpt: $(TB_GOFUMPT) ## Download gofumpt locally if necessary.
$(TB_GOFUMPT): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/gofumpt || GOBIN=$(TB_LOCALBIN) go install mvdan.cc/gofumpt@$(TB_GOFUMPT_VERSION)
tb.ginkgo: ## Download ginkgo locally if necessary.
@test -s $(TB_GINKGO) || \
GOBIN=$(TB_LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo
.PHONY: tb.golangci-lint
tb.golangci-lint: $(TB_GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(TB_GOLANGCI_LINT): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/golangci-lint || GOBIN=$(TB_LOCALBIN) go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(TB_GOLANGCI_LINT_VERSION)
.PHONY: tb.golines
tb.golines: $(TB_GOLINES) ## Download golines locally if necessary.
$(TB_GOLINES): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/golines || GOBIN=$(TB_LOCALBIN) go install github.com/segmentio/golines@$(TB_GOLINES_VERSION)
tb.golangci-lint: ## Download golangci-lint locally if necessary.
@test -s $(TB_GOLANGCI_LINT) && $(TB_GOLANGCI_LINT) --version | grep -q $(TB_GOLANGCI_LINT_VERSION_NUM) || \
GOBIN=$(TB_LOCALBIN) go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(TB_GOLANGCI_LINT_VERSION)
.PHONY: tb.goreleaser
tb.goreleaser: $(TB_GORELEASER) ## Download goreleaser locally if necessary.
$(TB_GORELEASER): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/goreleaser || GOBIN=$(TB_LOCALBIN) go install github.com/goreleaser/goreleaser/v2@$(TB_GORELEASER_VERSION)
tb.goreleaser: ## Download goreleaser locally if necessary.
@test -s $(TB_GORELEASER) && $(TB_GORELEASER) --version | grep -q $(TB_GORELEASER_VERSION_NUM) || \
GOBIN=$(TB_LOCALBIN) go install github.com/goreleaser/goreleaser/v2@$(TB_GORELEASER_VERSION)
.PHONY: tb.mockgen
tb.mockgen: $(TB_MOCKGEN) ## Download mockgen locally if necessary.
$(TB_MOCKGEN): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/mockgen || GOBIN=$(TB_LOCALBIN) go install go.uber.org/mock/mockgen@$(TB_MOCKGEN_VERSION)
tb.mockgen: ## Download mockgen locally if necessary.
@test -s $(TB_MOCKGEN) || \
GOBIN=$(TB_LOCALBIN) go install go.uber.org/mock/mockgen@$(TB_MOCKGEN_VERSION)
.PHONY: tb.oapi-codegen
tb.oapi-codegen: $(TB_OAPI_CODEGEN) ## Download oapi-codegen locally if necessary.
$(TB_OAPI_CODEGEN): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/oapi-codegen || GOBIN=$(TB_LOCALBIN) go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(TB_OAPI_CODEGEN_VERSION)
tb.oapi-codegen: ## Download oapi-codegen locally if necessary.
@test -s $(TB_OAPI_CODEGEN) || \
GOBIN=$(TB_LOCALBIN) go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(TB_OAPI_CODEGEN_VERSION)
.PHONY: tb.semver
tb.semver: $(TB_SEMVER) ## Download semver locally if necessary.
$(TB_SEMVER): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/semver || GOBIN=$(TB_LOCALBIN) go install github.com/bakito/semver@$(TB_SEMVER_VERSION)
tb.semver: ## Download semver locally if necessary.
@test -s $(TB_SEMVER) && $(TB_SEMVER) -version | grep -q $(TB_SEMVER_VERSION_NUM) || \
GOBIN=$(TB_LOCALBIN) go install github.com/bakito/semver@$(TB_SEMVER_VERSION)
.PHONY: tb.syft
tb.syft: ## Download syft locally if necessary.
@test -s $(TB_SYFT) && $(TB_SYFT) --version | grep -q $(TB_SYFT_VERSION_NUM) || \
GOBIN=$(TB_LOCALBIN) go install github.com/anchore/syft/cmd/syft@$(TB_SYFT_VERSION)
## Reset Tools
.PHONY: tb.reset
tb.reset:
@rm -f \
$(TB_LOCALBIN)/controller-gen \
$(TB_LOCALBIN)/ginkgo \
$(TB_LOCALBIN)/gofumpt \
$(TB_LOCALBIN)/golangci-lint \
$(TB_LOCALBIN)/golines \
$(TB_LOCALBIN)/goreleaser \
$(TB_LOCALBIN)/mockgen \
$(TB_LOCALBIN)/oapi-codegen \
$(TB_LOCALBIN)/semver
$(TB_CONTROLLER_GEN) \
$(TB_GINKGO) \
$(TB_GOLANGCI_LINT) \
$(TB_GORELEASER) \
$(TB_MOCKGEN) \
$(TB_OAPI_CODEGEN) \
$(TB_SEMVER) \
$(TB_SYFT)
## Update Tools
.PHONY: tb.update
tb.update: tb.reset
toolbox makefile --renovate -f $(TB_LOCALDIR)/Makefile \
sigs.k8s.io/controller-tools/cmd/controller-gen@github.com/kubernetes-sigs/controller-tools \
mvdan.cc/gofumpt@github.com/mvdan/gofumpt \
github.com/golangci/golangci-lint/v2/cmd/golangci-lint \
github.com/segmentio/golines \
github.com/goreleaser/goreleaser/v2 \
github.com/golangci/golangci-lint/v2/cmd/golangci-lint?--version \
github.com/goreleaser/goreleaser/v2?--version \
go.uber.org/mock/mockgen@github.com/uber-go/mock \
github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen \
github.com/bakito/semver
## toolbox - end
github.com/bakito/semver?-version \
github.com/anchore/syft/cmd/syft?--version
## toolbox - end

View File

@ -1,4 +1,4 @@
FROM golang:1.24-alpine AS builder
FROM golang:1.25-alpine AS builder
WORKDIR /go/src/app

View File

@ -13,16 +13,17 @@ generate: model mocks deepcopy-gen
deepcopy-gen: tb.controller-gen
@mkdir -p ./tmp
@touch ./tmp/deepcopy-gen-boilerplate.go.txt
$(TB_CONTROLLER_GEN) paths=./pkg/types object
$(TB_CONTROLLER_GEN) paths=./internal/types object
fmt: tb.golines tb.gofumpt
$(TB_GOLINES) --base-formatter="$(TB_GOFUMPT)" --max-len=120 --write-output .
.PHONY: docs
docs:
go run cmd/docs/main.go
# Run tests
test: generate fmt lint test-ci
test: generate lint test-ci
fuzz:
go test -fuzz=FuzzMask -v ./pkg/types/ -fuzztime=60s
go test -fuzz=FuzzMask -v ./internal/types/ -fuzztime=60s
# Run ci tests
test-ci: mocks tidy tb.ginkgo
@ -31,16 +32,16 @@ test-ci: mocks tidy tb.ginkgo
go tool cover -func=coverage.out
mocks: tb.mockgen
$(TB_MOCKGEN) -package client -destination pkg/mocks/client/mock.go github.com/bakito/adguardhome-sync/pkg/client Client
$(TB_MOCKGEN) -package client -destination pkg/mocks/flags/mock.go github.com/bakito/adguardhome-sync/pkg/config Flags
$(TB_MOCKGEN) -package client -destination internal/mocks/client/mock.go github.com/bakito/adguardhome-sync/internal/client Client
$(TB_MOCKGEN) -package client -destination internal/mocks/flags/mock.go github.com/bakito/adguardhome-sync/internal/config Flags
release: tb.semver tb.goreleaser
release: tb.semver tb.goreleaser tb.syft
@version=$$($(TB_SEMVER)); \
git tag -s $$version -m"Release $$version"
$(TB_GORELEASER) --clean
PATH=$(TB_LOCALBIN):$${PATH} $(TB_GORELEASER) --clean --parallelism 2
test-release: tb.goreleaser
$(TB_GORELEASER) --skip=publish --snapshot --clean
test-release: tb.goreleaser tb.syft
PATH=$(TB_LOCALBIN):$${PATH} $(TB_GORELEASER) --skip=publish --snapshot --clean --parallelism 2
start-replica:
docker rm -f adguardhome-replica
@ -74,16 +75,16 @@ kind-test:
@./testdata/e2e/bin/install-chart.sh
# renovate: packageName=AdguardTeam/AdGuardHome
ADGUARD_HOME_VERSION ?= v0.107.61
ADGUARD_HOME_VERSION ?= v0.107.68
model: tb.oapi-codegen
@mkdir -p tmp
go run openapi/main.go $(ADGUARD_HOME_VERSION)
$(TB_OAPI_CODEGEN) -package model -generate types,client -config .oapi-codegen.yaml tmp/schema.yaml > pkg/client/model/model_generated.go
go run cmd/openapi/main.go $(ADGUARD_HOME_VERSION)
$(TB_OAPI_CODEGEN) -package model -generate types,client -config .oapi-codegen.yaml tmp/schema.yaml > internal/client/model/model_generated.go
model-diff:
go run openapi/main.go $(ADGUARD_HOME_VERSION)
go run openapi/main.go
go run cmd/openapi/main.go $(ADGUARD_HOME_VERSION)
go run cmd/openapi/main.go
diff tmp/schema.yaml tmp/schema-master.yaml
zellij:

112
README.md
View File

@ -3,7 +3,9 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/bakito/adguardhome-sync)](https://goreportcard.com/report/github.com/bakito/adguardhome-sync)
[![Coverage Status](https://coveralls.io/repos/github/bakito/adguardhome-sync/badge.svg?branch=main&service=github)](https://coveralls.io/github/bakito/adguardhome-sync?branch=main)
# AdGuardHome sync
# <img src="./media/adguardhome-sync.svg" alt="AdGuardHome sync" width="50"/> AdGuardHome sync
Synchronize [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) config to replica instances.
@ -43,7 +45,7 @@ go install github.com/bakito/adguardhome-sync@latest
## Prerequisites
Both the origin instance must be initially setup via the AdguardHome installation wizard.
Both the origin instance and replica(s) must be initially set up with AdguardHome via the AdguardHome installation wizard.
## Username / Password vs. Cookie
@ -183,58 +185,60 @@ services:
## Config via environment variables
For Replicas replace `#` with the index number for the replica. E.g: `REPLICA#_URL` -> `REPLICA1_URL`
| Name | Type | Description |
|:-------------------------------------|--------|:----------------------------------------------------------|
| ORIGIN_URL (string) | string | URL of adguardhome instance |
| ORIGIN_WEB_URL (string) | string | Web URL of adguardhome instance |
| ORIGIN_API_PATH (string) | string | API Path |
| ORIGIN_USERNAME (string) | string | Adguardhome username |
| ORIGIN_PASSWORD (string) | string | Adguardhome password |
| ORIGIN_COOKIE (string) | string | Adguardhome cookie |
| ORIGIN_REQUEST_HEADERS (map) | map | Request Headers 'key1:value1,key2:value2' |
| ORIGIN_INSECURE_SKIP_VERIFY (bool) | bool | Skip TLS verification |
| ORIGIN_AUTO_SETUP (bool) | bool | Automatically setup the instance if it is not initialized |
| ORIGIN_INTERFACE_NAME (string) | string | Network interface name |
| ORIGIN_DHCP_SERVER_ENABLED (bool) | bool | Enable DHCP server |
| REPLICA#_URL (string) | string | URL of adguardhome instance |
| REPLICA#_WEB_URL (string) | string | Web URL of adguardhome instance |
| REPLICA#_API_PATH (string) | string | API Path |
| REPLICA#_USERNAME (string) | string | Adguardhome username |
| REPLICA#_PASSWORD (string) | string | Adguardhome password |
| REPLICA#_COOKIE (string) | string | Adguardhome cookie |
| REPLICA#_REQUEST_HEADERS (map) | map | Request Headers 'key1:value1,key2:value2' |
| REPLICA#_INSECURE_SKIP_VERIFY (bool) | bool | Skip TLS verification |
| REPLICA#_AUTO_SETUP (bool) | bool | Automatically setup the instance if it is not initialized |
| REPLICA#_INTERFACE_NAME (string) | string | Network interface name |
| REPLICA#_DHCP_SERVER_ENABLED (bool) | bool | Enable DHCP server |
| CRON (string) | string | Cron expression for the sync interval |
| RUN_ON_START (bool) | bool | Run the sung on startup |
| PRINT_CONFIG_ONLY (bool) | bool | Print current config only and stop the application |
| CONTINUE_ON_ERROR (bool) | bool | Continue sync on errors |
| API_PORT (int) | int | API port |
| API_USERNAME (string) | string | API username |
| API_PASSWORD (string) | string | API password |
| API_DARK_MODE (bool) | bool | API dark mode |
| API_METRICS_ENABLED (bool) | bool | Enable metrics |
| API_METRICS_SCRAPE_INTERVAL (int64) | int64 | Interval for metrics scraping |
| API_METRICS_QUERY_LOG_LIMIT (int) | int | Metrics log query limit |
| API_TLS_CERT_DIR (string) | string | API TLS certificate directory |
| API_TLS_CERT_NAME (string) | string | API TLS certificate file name |
| API_TLS_KEY_NAME (string) | string | API TLS key file name |
| FEATURES_DNS_ACCESS_LISTS (bool) | bool | Sync DNS access lists |
| FEATURES_DNS_SERVER_CONFIG (bool) | bool | Sync DNS server config |
| FEATURES_DNS_REWRITES (bool) | bool | Sync DNS rewrites |
| FEATURES_DHCP_SERVER_CONFIG (bool) | bool | Sync DHCP server config |
| FEATURES_DHCP_STATIC_LEASES (bool) | bool | Sync DHCP static leases |
| FEATURES_GENERAL_SETTINGS (bool) | bool | Sync general settings |
| FEATURES_QUERY_LOG_CONFIG (bool) | bool | Sync query log config |
| FEATURES_STATS_CONFIG (bool) | bool | Sync stats config |
| FEATURES_CLIENT_SETTINGS (bool) | bool | Sync client settings |
| FEATURES_SERVICES (bool) | bool | Sync services |
| FEATURES_FILTERS (bool) | bool | Sync filters |
| FEATURES_THEME (bool) | bool | Sync the weg UI theme |
For Replicas replace `#` with the index number for the replica. E.g.: `REPLICA#_URL` -> `REPLICA1_URL`
<!-- env-doc-start -->
| Name | Type | Description |
| :--- | ---- |:----------- |
| ORIGIN_URL (string) | string | URL of adguardhome instance |
| ORIGIN_WEB_URL (string) | string | Web URL of adguardhome instance |
| ORIGIN_API_PATH (string) | string | API Path |
| ORIGIN_USERNAME (string) | string | Adguardhome username |
| ORIGIN_PASSWORD (string) | string | Adguardhome password |
| ORIGIN_COOKIE (string) | string | Adguardhome cookie |
| ORIGIN_REQUEST_HEADERS (map) | map | Request Headers 'key1:value1,key2:value2' |
| ORIGIN_INSECURE_SKIP_VERIFY (bool) | bool | Skip TLS verification |
| ORIGIN_AUTO_SETUP (bool) | bool | Automatically setup the instance if it is not initialized |
| ORIGIN_INTERFACE_NAME (string) | string | Network interface name |
| ORIGIN_DHCP_SERVER_ENABLED (bool) | bool | Enable DHCP server |
| REPLICA#_URL (string) | string | URL of adguardhome instance |
| REPLICA#_WEB_URL (string) | string | Web URL of adguardhome instance |
| REPLICA#_API_PATH (string) | string | API Path |
| REPLICA#_USERNAME (string) | string | Adguardhome username |
| REPLICA#_PASSWORD (string) | string | Adguardhome password |
| REPLICA#_COOKIE (string) | string | Adguardhome cookie |
| REPLICA#_REQUEST_HEADERS (map) | map | Request Headers 'key1:value1,key2:value2' |
| REPLICA#_INSECURE_SKIP_VERIFY (bool) | bool | Skip TLS verification |
| REPLICA#_AUTO_SETUP (bool) | bool | Automatically setup the instance if it is not initialized |
| REPLICA#_INTERFACE_NAME (string) | string | Network interface name |
| REPLICA#_DHCP_SERVER_ENABLED (bool) | bool | Enable DHCP server |
| CRON (string) | string | Cron expression for the sync interval |
| RUN_ON_START (bool) | bool | Run the sync on startup |
| PRINT_CONFIG_ONLY (bool) | bool | Print current config only and stop the application |
| CONTINUE_ON_ERROR (bool) | bool | Continue sync on errors |
| API_PORT (int) | int | API port (API is disabled if port is set to 0) |
| API_USERNAME (string) | string | API username |
| API_PASSWORD (string) | string | API password |
| API_DARK_MODE (bool) | bool | API dark mode |
| API_METRICS_ENABLED (bool) | bool | Enable metrics |
| API_METRICS_SCRAPE_INTERVAL (int64) | int64 | Interval for metrics scraping |
| API_METRICS_QUERY_LOG_LIMIT (int) | int | Metrics log query limit |
| API_TLS_CERT_DIR (string) | string | API TLS certificate directory |
| API_TLS_CERT_NAME (string) | string | API TLS certificate file name |
| API_TLS_KEY_NAME (string) | string | API TLS key file name |
| FEATURES_DNS_ACCESS_LISTS (bool) | bool | Sync DNS access lists |
| FEATURES_DNS_SERVER_CONFIG (bool) | bool | Sync DNS server config |
| FEATURES_DNS_REWRITES (bool) | bool | Sync DNS rewrites |
| FEATURES_DHCP_SERVER_CONFIG (bool) | bool | Sync DHCP server config |
| FEATURES_DHCP_STATIC_LEASES (bool) | bool | Sync DHCP static leases |
| FEATURES_GENERAL_SETTINGS (bool) | bool | Sync general settings |
| FEATURES_QUERY_LOG_CONFIG (bool) | bool | Sync query log config |
| FEATURES_STATS_CONFIG (bool) | bool | Sync stats config |
| FEATURES_CLIENT_SETTINGS (bool) | bool | Sync client settings |
| FEATURES_SERVICES (bool) | bool | Sync services |
| FEATURES_FILTERS (bool) | bool | Sync filters |
| FEATURES_THEME (bool) | bool | Sync the web UI theme |
| FEATURES_TLS_CONFIG (bool) | bool | Sync the TLS config |
<!-- env-doc-end -->
### Unraid

96
cmd/docs/main.go Normal file
View File

@ -0,0 +1,96 @@
// Print the available environment variables
package main
import (
"fmt"
"io"
"log"
"os"
"reflect"
"strings"
"github.com/bakito/adguardhome-sync/internal/types"
)
func main() {
// Read the README.md file
content, err := os.ReadFile("README.md")
if err != nil {
log.Fatal(err)
}
// Convert to string for easier manipulation
fileContent := string(content)
// Generate the environment variables documentation
var buf strings.Builder
_, _ = buf.WriteString("| Name | Type | Description |\n")
_, _ = buf.WriteString("| :--- | ---- |:----------- |\n")
printEnvTags(&buf, reflect.TypeOf(types.Config{}), "")
// Find the markers and replace content between them
startMarker := "<!-- env-doc-start -->"
endMarker := "<!-- env-doc-end -->"
start := strings.Index(fileContent, startMarker)
end := strings.Index(fileContent, endMarker)
if start == -1 || end == -1 {
log.Fatal("Could not find markers in README.md")
}
// Construct new content
newContent := fileContent[:start+len(startMarker)] + "\n" + buf.String() + fileContent[end:]
// Write back to README.md
err = os.WriteFile("README.md", []byte(newContent), 0o644)
if err != nil {
log.Fatal(err)
}
}
// printEnvTags recursively prints all fields with `env` tags.
func printEnvTags(w io.Writer, t reflect.Type, prefix string) {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return
}
for _, field := range reflect.VisibleFields(t) {
if field.PkgPath != "" { // unexported field
continue
}
envTag := field.Tag.Get("env")
if envTag == "" {
switch field.Name {
case "Origin":
envTag = "ORIGIN"
case "Replica":
envTag = "REPLICA#"
}
}
combinedTag := envTag
if prefix != "" && envTag != "" {
combinedTag = prefix + "_" + envTag
} else if prefix != "" {
combinedTag = prefix
}
ft := field.Type
if ft.Kind() == reflect.Ptr {
ft = ft.Elem()
}
if ft.Kind() == reflect.Struct && ft.Name() != "Time" { // skip time.Time
printEnvTags(w, ft, strings.TrimSuffix(combinedTag, "_"))
} else if envTag != "" {
envVar := strings.Trim(combinedTag, "_") + " (" + ft.Kind().String() + ")"
docs := field.Tag.Get("documentation")
_, _ = fmt.Fprintf(w, "| %s | %s | %s |\n", envVar, ft.Kind().String(), docs)
}
}
}

View File

@ -87,10 +87,6 @@ func main() {
}
func correctEntries(schema map[string]any) {
// https://github.com/AdguardTeam/AdGuardHome/pull/7678
if err := unstructured.SetNestedField(schema, "string", "components", "schemas", "QueryLogItem", "properties", "client_proto", "type"); err != nil {
log.Fatalln(err)
}
}
func addFakeTags(schema map[string]any) {

View File

@ -6,7 +6,7 @@ import (
"github.com/spf13/cobra"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/version"
)

View File

@ -3,9 +3,9 @@ package cmd
import (
"github.com/spf13/cobra"
"github.com/bakito/adguardhome-sync/pkg/config"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/sync"
"github.com/bakito/adguardhome-sync/internal/config"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/internal/sync"
)
// runCmd represents the run command.
@ -67,6 +67,7 @@ func init() {
doCmd.PersistentFlags().Bool(config.FlagFeatureClient, true, "Enable client settings feature")
doCmd.PersistentFlags().Bool(config.FlagFeatureServices, true, "Enable services sync feature")
doCmd.PersistentFlags().Bool(config.FlagFeatureFilters, true, "Enable filters sync feature")
doCmd.PersistentFlags().Bool(config.FlagFeatureTLSConfig, false, "Enable TLS config sync feature")
doCmd.PersistentFlags().String(config.FlagOriginURL, "", "Origin instance url")
doCmd.PersistentFlags().

View File

@ -1,62 +0,0 @@
// Print the available environment variables
package main
import (
"fmt"
"reflect"
"strings"
"github.com/bakito/adguardhome-sync/pkg/types"
)
func main() {
_, _ = fmt.Println("| Name | Type | Description |")
_, _ = fmt.Println("| :--- | ---- |:----------- |")
printEnvTags(reflect.TypeOf(types.Config{}), "")
}
// printEnvTags recursively prints all fields with `env` tags.
func printEnvTags(t reflect.Type, prefix string) {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return
}
for _, field := range reflect.VisibleFields(t) {
if field.PkgPath != "" { // unexported field
continue
}
envTag := field.Tag.Get("env")
if envTag == "" {
switch field.Name {
case "Origin":
envTag = "ORIGIN"
case "Replica":
envTag = "REPLICA#"
}
}
combinedTag := envTag
if prefix != "" && envTag != "" {
combinedTag = prefix + "_" + envTag
} else if prefix != "" {
combinedTag = prefix
}
ft := field.Type
if ft.Kind() == reflect.Ptr {
ft = ft.Elem()
}
if ft.Kind() == reflect.Struct && ft.Name() != "Time" { // skip time.Time
printEnvTags(ft, strings.TrimSuffix(combinedTag, "_"))
} else if envTag != "" {
envVar := strings.Trim(combinedTag, "_") + " (" + ft.Kind().String() + ")"
docs := field.Tag.Get("documentation")
_, _ = fmt.Printf("| %s | %s | %s |\n", envVar, ft.Kind().String(), docs)
}
}
}

74
go.mod
View File

@ -1,77 +1,83 @@
module github.com/bakito/adguardhome-sync
go 1.24.2
go 1.25.1
require (
github.com/caarlos0/env/v11 v11.3.1
github.com/gin-gonic/gin v1.10.0
github.com/go-faker/faker/v4 v4.6.1
github.com/gin-gonic/gin v1.11.0
github.com/go-faker/faker/v4 v4.7.0
github.com/go-resty/resty/v2 v2.16.5
github.com/google/uuid v1.6.0
github.com/jinzhu/copier v0.4.0
github.com/oapi-codegen/runtime v1.1.1
github.com/onsi/ginkgo/v2 v2.23.4
github.com/onsi/gomega v1.37.0
github.com/prometheus/client_golang v1.22.0
github.com/oapi-codegen/runtime v1.1.2
github.com/onsi/ginkgo/v2 v2.27.1
github.com/onsi/gomega v1.38.2
github.com/prometheus/client_golang v1.23.2
github.com/robfig/cron/v3 v3.0.1
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
github.com/spf13/cobra v1.9.1
go.uber.org/mock v0.5.2
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
github.com/spf13/cobra v1.10.1
go.uber.org/mock v0.6.0
go.uber.org/zap v1.27.0
golang.org/x/mod v0.24.0
golang.org/x/mod v0.29.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.33.1
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979
k8s.io/apimachinery v0.34.1
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
)
require (
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.13.2 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/bytedance/sonic v1.14.0 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/go-playground/validator/v10 v10.27.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.54.1 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/ugorji/go/codec v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.16.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/tools v0.32.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/tools v0.37.0 // indirect
google.golang.org/protobuf v1.36.9 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
)

177
go.sum
View File

@ -1,67 +1,76 @@
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-faker/faker/v4 v4.6.1 h1:xUyVpAjEtB04l6XFY0V/29oR332rOSPWV4lU8RwDt4k=
github.com/go-faker/faker/v4 v4.6.1/go.mod h1:arSdxNCSt7mOhdk8tEolvHeIJ7eX4OX80wXjKKvkKBY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE=
github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
github.com/go-faker/faker/v4 v4.7.0 h1:VboC02cXHl/NuQh5lM2W8b87yp4iFXIu59x4w0RZi4E=
github.com/go-faker/faker/v4 v4.7.0/go.mod h1:u1dIRP5neLB6kTzgyVjdBOV5R1uP7BdxkcWk7tiKQXk=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY=
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE=
github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
@ -69,10 +78,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -81,61 +88,77 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI=
github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/onsi/ginkgo/v2 v2.27.1 h1:0LJC8MpUSQnfnp4n/3W3GdlmJP3ENGF0ZPzjQGLPP7s=
github.com/onsi/ginkgo/v2 v2.27.1/go.mod h1:wmy3vCqiBjirARfVhAqFpYt8uvX0yaFe+GudAqqcCqA=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg=
github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -144,56 +167,62 @@ go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@ -202,19 +231,17 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg=
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

View File

@ -14,14 +14,27 @@ import (
"github.com/go-resty/resty/v2"
"go.uber.org/zap"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/internal/types"
"github.com/bakito/adguardhome-sync/internal/utils"
)
const envRedirectPolicyNoOfRedirects = "REDIRECT_POLICY_NO_OF_REDIRECTS"
type Error struct {
message string
errorCode int
}
func (e *Error) Error() string {
return e.message
}
func (e *Error) Code() int {
return e.errorCode
}
var (
l = log.GetLogger("client")
// ErrSetupNeeded custom error.
@ -36,7 +49,10 @@ func detailedError(resp *resty.Response, err error) error {
if err != nil {
e += ": " + err.Error()
}
return errors.New(e)
return &Error{
message: e,
errorCode: resp.StatusCode(),
}
}
// New create a new client.
@ -131,6 +147,8 @@ type Client interface {
SetDhcpConfig(status *model.DhcpStatus) error
AddDHCPStaticLease(lease model.DhcpStaticLease) error
DeleteDHCPStaticLease(lease model.DhcpStaticLease) error
TLSConfig() (*model.TlsConfig, error)
SetTLSConfig(tls *model.TlsConfig) error
}
type client struct {
@ -450,3 +468,14 @@ func (cl *client) SetProfileInfo(profile *model.ProfileInfo) error {
cl.log.With("language", profile.Language, "theme", profile.Theme).Info("Set profile")
return cl.doPut(cl.client.R().EnableTrace().SetBody(profile), "/profile/update")
}
func (cl *client) TLSConfig() (*model.TlsConfig, error) {
tlsc := &model.TlsConfig{}
err := cl.doGet(cl.client.R().EnableTrace().SetResult(tlsc), "/tls/status")
return tlsc, err
}
func (cl *client) SetTLSConfig(tlsc *model.TlsConfig) error {
cl.log.With("enabled", tlsc.Enabled).Info("Set TLS config")
return cl.doPost(cl.client.R().EnableTrace().SetBody(tlsc), "/tls/configure")
}

View File

@ -12,10 +12,10 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/internal/client"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/types"
"github.com/bakito/adguardhome-sync/internal/utils"
)
var (

View File

@ -13,9 +13,9 @@ import (
"go.uber.org/zap"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/internal/types"
)
var l = log.GetLogger("client")

View File

@ -3,7 +3,7 @@ package client
import (
"context"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/internal/client/model"
)
type Client interface {

View File

@ -5,7 +5,7 @@ import (
"github.com/go-resty/resty/v2"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/internal/client/model"
)
var _ model.HttpRequestDoer = &adapter{}

View File

@ -9,7 +9,7 @@ import (
"go.uber.org/zap"
"k8s.io/utils/ptr"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/internal/utils"
)
// Clone the config.
@ -490,3 +490,7 @@ func sumUp(t, o *[]int) *[]int {
}
return t
}
func (c *TlsConfig) Equals(config *TlsConfig) bool {
return utils.JSONEquals(c, config)
}

View File

@ -1,6 +1,6 @@
// Package model provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT.
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT.
package model
import (
@ -195,6 +195,9 @@ type AddressesInfo struct {
// BlockedService defines model for BlockedService.
type BlockedService struct {
// GroupId The ID of the group, that the service belongs to.
GroupId *string `json:"group_id,omitempty"`
// IconSvg The SVG icon as a Base64-encoded string to make it easier to embed it into a data URL.
IconSvg string `json:"icon_svg"`
@ -211,6 +214,7 @@ type BlockedService struct {
// BlockedServicesAll defines model for BlockedServicesAll.
type BlockedServicesAll struct {
BlockedServices []BlockedService `json:"blocked_services"`
Groups interface{} `json:"groups"`
}
// BlockedServicesArray defines model for BlockedServicesArray.
@ -303,7 +307,7 @@ type Client struct {
// SafeSearch Safe search settings.
SafeSearch *SafeSearchConfig `json:"safe_search,omitempty"`
SafebrowsingEnabled *bool `json:"safebrowsing_enabled,omitempty"`
// Deprecated:
// Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
SafesearchEnabled *bool `json:"safesearch_enabled,omitempty"`
Tags *[]string `json:"tags,omitempty"`
Upstreams *[]string `json:"upstreams,omitempty"`
@ -369,7 +373,7 @@ type ClientFindSubEntry struct {
// SafeSearch Safe search settings.
SafeSearch *SafeSearchConfig `json:"safe_search,omitempty"`
SafebrowsingEnabled *bool `json:"safebrowsing_enabled,omitempty"`
// Deprecated:
// Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
SafesearchEnabled *bool `json:"safesearch_enabled,omitempty"`
Upstreams *[]string `json:"upstreams,omitempty"`
UseGlobalBlockedServices *bool `json:"use_global_blocked_services,omitempty"`
@ -426,16 +430,23 @@ type DNSConfig struct {
BlockingMode *DNSConfigBlockingMode `json:"blocking_mode,omitempty"`
// BootstrapDns Bootstrap servers, port is optional after colon. Empty value will reset it to default values.
BootstrapDns *[]string `json:"bootstrap_dns,omitempty"`
CacheOptimistic *bool `json:"cache_optimistic,omitempty"`
CacheSize *int `json:"cache_size,omitempty"`
CacheTtlMax *int `json:"cache_ttl_max,omitempty"`
CacheTtlMin *int `json:"cache_ttl_min,omitempty"`
DisableIpv6 *bool `json:"disable_ipv6,omitempty"`
DnssecEnabled *bool `json:"dnssec_enabled,omitempty"`
EdnsCsCustomIp *string `json:"edns_cs_custom_ip,omitempty"`
EdnsCsEnabled *bool `json:"edns_cs_enabled,omitempty"`
EdnsCsUseCustom *bool `json:"edns_cs_use_custom,omitempty"`
BootstrapDns *[]string `json:"bootstrap_dns,omitempty"`
// CacheEnabled Enables or disables the DNS response cache.
//
// If `cache_enabled` is `true`, the companion field `cache_size` must
// be present and greater than 0, or the `dns.cache_size` setting in
// the configuration file must already be greater than 0.
CacheEnabled *bool `json:"cache_enabled,omitempty"`
CacheOptimistic *bool `json:"cache_optimistic,omitempty"`
CacheSize *int `json:"cache_size,omitempty"`
CacheTtlMax *int `json:"cache_ttl_max,omitempty"`
CacheTtlMin *int `json:"cache_ttl_min,omitempty"`
DisableIpv6 *bool `json:"disable_ipv6,omitempty"`
DnssecEnabled *bool `json:"dnssec_enabled,omitempty"`
EdnsCsCustomIp *string `json:"edns_cs_custom_ip,omitempty"`
EdnsCsEnabled *bool `json:"edns_cs_enabled,omitempty"`
EdnsCsUseCustom *bool `json:"edns_cs_use_custom,omitempty"`
// FallbackDns List of fallback DNS servers used when upstream DNS servers are not responding. Empty value will clear the list.
FallbackDns *[]string `json:"fallback_dns,omitempty"`
@ -618,7 +629,7 @@ type FilterCheckHostResponse struct {
// FilterId In case if there's a rule applied to this DNS request, this is ID of the filter list that the rule belongs to.
// Deprecated: use `rules[*].filter_list_id` instead.
// Deprecated:
// Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
FilterId *int `json:"filter_id,omitempty"`
// IpAddrs Set if reason=Rewrite
@ -629,7 +640,7 @@ type FilterCheckHostResponse struct {
// Rule Filtering rule applied to the request (if any).
// Deprecated: use `rules[*].text` instead.
// Deprecated:
// Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
Rule *string `json:"rule,omitempty"`
// Rules Applied rules.
@ -830,7 +841,7 @@ type QueryLogItem struct {
// FilterId In case if there's a rule applied to this DNS request, this is ID of the filter list that the rule belongs to.
// Deprecated: use `rules[*].filter_list_id` instead.
// Deprecated:
// Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
FilterId *int `json:"filterId,omitempty"`
// OriginalAnswer Answer from upstream server (optional)
@ -844,7 +855,7 @@ type QueryLogItem struct {
// Rule Filtering rule applied to the request (if any).
// Deprecated: use `rules[*].text` instead.
// Deprecated:
// Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
Rule *string `json:"rule,omitempty"`
// Rules Applied rules.
@ -919,11 +930,20 @@ type RewriteEntry struct {
// Domain Domain name
Domain *string `json:"domain,omitempty"`
// Enabled Optional. If omitted on add, defaults to `true`. On update, omitted preserves previous value.
Enabled *bool `json:"enabled,omitempty"`
}
// RewriteList Rewrite rules array
type RewriteList = []RewriteEntry
// RewriteSettings DNS rewrite settings
type RewriteSettings struct {
// Enabled indicates whether rewrites are applied
Enabled bool `json:"enabled"`
}
// RewriteUpdate Rewrite rule update object
type RewriteUpdate struct {
// Target Rewrite rule
@ -985,6 +1005,12 @@ type ServerStatus struct {
Version string `json:"version"`
}
// ServiceGroup defines model for ServiceGroup.
type ServiceGroup struct {
// Id The ID of this group.
Id string `json:"id"`
}
// SetProtectionRequest Protection state configuration
type SetProtectionRequest struct {
// Duration Duration of a pause, in milliseconds. Enabled should be false.
@ -1165,6 +1191,9 @@ type DhcpStaticLeaseBody = DhcpStaticLease
// RewriteEntryBody Rewrite rule
type RewriteEntryBody = RewriteEntry
// RewriteSettingsBody DNS rewrite settings
type RewriteSettingsBody = RewriteSettings
// RewriteUpdateBody Rewrite rule update object
type RewriteUpdateBody = RewriteUpdate
@ -1316,6 +1345,9 @@ type RewriteAddJSONRequestBody = RewriteEntry
// RewriteDeleteJSONRequestBody defines body for RewriteDelete for application/json ContentType.
type RewriteDeleteJSONRequestBody = RewriteEntry
// RewriteSettingsUpdateJSONRequestBody defines body for RewriteSettingsUpdate for application/json ContentType.
type RewriteSettingsUpdateJSONRequestBody = RewriteSettings
// RewriteUpdateJSONRequestBody defines body for RewriteUpdate for application/json ContentType.
type RewriteUpdateJSONRequestBody = RewriteUpdate
@ -1713,6 +1745,14 @@ type ClientInterface interface {
// RewriteList request
RewriteList(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
// RewriteSettingsGet request
RewriteSettingsGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
// RewriteSettingsUpdateWithBody request with any body
RewriteSettingsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
RewriteSettingsUpdate(ctx context.Context, body RewriteSettingsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// RewriteUpdateWithBody request with any body
RewriteUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@ -2837,6 +2877,42 @@ func (c *AdguardHomeClient) RewriteList(ctx context.Context, reqEditors ...Reque
return c.Client.Do(req)
}
func (c *AdguardHomeClient) RewriteSettingsGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewRewriteSettingsGetRequest(c.Server)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *AdguardHomeClient) RewriteSettingsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewRewriteSettingsUpdateRequestWithBody(c.Server, contentType, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *AdguardHomeClient) RewriteSettingsUpdate(ctx context.Context, body RewriteSettingsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewRewriteSettingsUpdateRequest(c.Server, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *AdguardHomeClient) RewriteUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewRewriteUpdateRequestWithBody(c.Server, contentType, body)
if err != nil {
@ -5354,6 +5430,73 @@ func NewRewriteListRequest(server string) (*http.Request, error) {
return req, nil
}
// NewRewriteSettingsGetRequest generates requests for RewriteSettingsGet
func NewRewriteSettingsGetRequest(server string) (*http.Request, error) {
var err error
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/rewrite/settings")
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
}
return req, nil
}
// NewRewriteSettingsUpdateRequest calls the generic RewriteSettingsUpdate builder with application/json body
func NewRewriteSettingsUpdateRequest(server string, body RewriteSettingsUpdateJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
return NewRewriteSettingsUpdateRequestWithBody(server, "application/json", bodyReader)
}
// NewRewriteSettingsUpdateRequestWithBody generates requests for RewriteSettingsUpdate with any type of body
func NewRewriteSettingsUpdateRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
var err error
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/rewrite/settings/update")
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("PUT", queryURL.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", contentType)
return req, nil
}
// NewRewriteUpdateRequest calls the generic RewriteUpdate builder with application/json body
func NewRewriteUpdateRequest(server string, body RewriteUpdateJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
@ -6300,6 +6443,14 @@ type ClientWithResponsesInterface interface {
// RewriteListWithResponse request
RewriteListWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*RewriteListResp, error)
// RewriteSettingsGetWithResponse request
RewriteSettingsGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*RewriteSettingsGetResp, error)
// RewriteSettingsUpdateWithBodyWithResponse request with any body
RewriteSettingsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RewriteSettingsUpdateResp, error)
RewriteSettingsUpdateWithResponse(ctx context.Context, body RewriteSettingsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*RewriteSettingsUpdateResp, error)
// RewriteUpdateWithBodyWithResponse request with any body
RewriteUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RewriteUpdateResp, error)
@ -7636,6 +7787,49 @@ func (r RewriteListResp) StatusCode() int {
return 0
}
type RewriteSettingsGetResp struct {
Body []byte
HTTPResponse *http.Response
JSON200 *RewriteSettings
}
// Status returns HTTPResponse.Status
func (r RewriteSettingsGetResp) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r RewriteSettingsGetResp) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type RewriteSettingsUpdateResp struct {
Body []byte
HTTPResponse *http.Response
}
// Status returns HTTPResponse.Status
func (r RewriteSettingsUpdateResp) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r RewriteSettingsUpdateResp) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type RewriteUpdateResp struct {
Body []byte
HTTPResponse *http.Response
@ -8844,6 +9038,32 @@ func (c *ClientWithResponses) RewriteListWithResponse(ctx context.Context, reqEd
return ParseRewriteListResp(rsp)
}
// RewriteSettingsGetWithResponse request returning *RewriteSettingsGetResp
func (c *ClientWithResponses) RewriteSettingsGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*RewriteSettingsGetResp, error) {
rsp, err := c.RewriteSettingsGet(ctx, reqEditors...)
if err != nil {
return nil, err
}
return ParseRewriteSettingsGetResp(rsp)
}
// RewriteSettingsUpdateWithBodyWithResponse request with arbitrary body returning *RewriteSettingsUpdateResp
func (c *ClientWithResponses) RewriteSettingsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RewriteSettingsUpdateResp, error) {
rsp, err := c.RewriteSettingsUpdateWithBody(ctx, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseRewriteSettingsUpdateResp(rsp)
}
func (c *ClientWithResponses) RewriteSettingsUpdateWithResponse(ctx context.Context, body RewriteSettingsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*RewriteSettingsUpdateResp, error) {
rsp, err := c.RewriteSettingsUpdate(ctx, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseRewriteSettingsUpdateResp(rsp)
}
// RewriteUpdateWithBodyWithResponse request with arbitrary body returning *RewriteUpdateResp
func (c *ClientWithResponses) RewriteUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RewriteUpdateResp, error) {
rsp, err := c.RewriteUpdateWithBody(ctx, contentType, body, reqEditors...)
@ -10369,6 +10589,48 @@ func ParseRewriteListResp(rsp *http.Response) (*RewriteListResp, error) {
return response, nil
}
// ParseRewriteSettingsGetResp parses an HTTP response from a RewriteSettingsGetWithResponse call
func ParseRewriteSettingsGetResp(rsp *http.Response) (*RewriteSettingsGetResp, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &RewriteSettingsGetResp{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
var dest RewriteSettings
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON200 = &dest
}
return response, nil
}
// ParseRewriteSettingsUpdateResp parses an HTTP response from a RewriteSettingsUpdateWithResponse call
func ParseRewriteSettingsUpdateResp(rsp *http.Response) (*RewriteSettingsUpdateResp, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &RewriteSettingsUpdateResp{
Body: bodyBytes,
HTTPResponse: rsp,
}
return response, nil
}
// ParseRewriteUpdateResp parses an HTTP response from a RewriteUpdateWithResponse call
func ParseRewriteUpdateResp(rsp *http.Response) (*RewriteUpdateResp, error) {
bodyBytes, err := io.ReadAll(rsp.Body)

View File

@ -5,8 +5,8 @@ import (
"github.com/onsi/gomega"
"go.uber.org/zap"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/internal/utils"
)
var _ = Describe("Types", func() {

View File

@ -8,9 +8,9 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/types"
"github.com/bakito/adguardhome-sync/internal/utils"
)
var _ = Describe("Types", func() {

View File

@ -150,6 +150,9 @@
},
"theme": {
"type": "boolean"
},
"tlsConfig": {
"type": "boolean"
}
},
"type": "object"

View File

@ -6,8 +6,8 @@ import (
"github.com/caarlos0/env/v11"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/internal/types"
)
var (
@ -102,8 +102,6 @@ func Get(configFile string, flags Flags) (*AppConfig, error) {
"Do not use single replica and numbered (list) replica config combined")
}
handleDeprecatedEnvVars(cfg)
if cfg.Replica != nil {
cfg.Replicas = []types.AdGuardInstance{*cfg.Replica}
cfg.Replica = nil

View File

@ -7,8 +7,8 @@ import (
. "github.com/onsi/gomega"
gm "go.uber.org/mock/gomock"
"github.com/bakito/adguardhome-sync/pkg/config"
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
"github.com/bakito/adguardhome-sync/internal/config"
flagsmock "github.com/bakito/adguardhome-sync/internal/mocks/flags"
)
var _ = Describe("Config", func() {
@ -229,16 +229,6 @@ var _ = Describe("Config", func() {
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
flags.EXPECT().GetBool(config.FlagFeatureDNSServerConfig).Return(true, nil).AnyTimes()
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
Ω(err).ShouldNot(HaveOccurred())
Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse())
})
It("should have the feature dns server config from the config DEPRECATED env var", func() {
setEnv("FEATURES_DNS_SERVERCONFIG", "false")
flags.EXPECT().Changed(config.FlagFeatureDNSServerConfig).Return(true).AnyTimes()
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
flags.EXPECT().GetBool(config.FlagFeatureDNSServerConfig).Return(true, nil).AnyTimes()
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
Ω(err).ShouldNot(HaveOccurred())
Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse())

57
internal/config/env.go Normal file
View File

@ -0,0 +1,57 @@
package config
import (
"fmt"
"os"
"strconv"
"github.com/caarlos0/env/v11"
"github.com/bakito/adguardhome-sync/internal/types"
)
// Manually collect replicas from env.
func enrichReplicasFromEnv(initialReplicas []types.AdGuardInstance) ([]types.AdGuardInstance, error) {
var replicas []types.AdGuardInstance
for _, v := range os.Environ() {
if envReplicasURLPattern.MatchString(v) {
sm := envReplicasURLPattern.FindStringSubmatch(v)
id, _ := strconv.Atoi(sm[1])
if id <= 0 {
return nil, fmt.Errorf("numbered replica env variables must have a number id >= 1, got %q", v)
}
if id > len(initialReplicas) {
replicas = append(replicas, types.AdGuardInstance{URL: sm[2]})
} else {
re := initialReplicas[id-1]
re.URL = sm[2]
replicas = append(replicas, re)
}
}
}
if len(replicas) == 0 {
replicas = initialReplicas
}
for i := range replicas {
reID := i + 1
// keep the previously set value
replicaDhcpServer := replicas[i].DHCPServerEnabled
replicas[i].DHCPServerEnabled = nil
if err := env.ParseWithOptions(&replicas[i], env.Options{Prefix: fmt.Sprintf("REPLICA%d_", reID)}); err != nil {
return nil, err
}
if replicas[i].DHCPServerEnabled == nil {
replicas[i].DHCPServerEnabled = replicaDhcpServer
}
if replicas[i].APIPath == "" {
replicas[i].APIPath = "/control"
}
}
return replicas, nil
}

View File

@ -6,7 +6,7 @@ import (
"gopkg.in/yaml.v3"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/types"
)
func readFile(cfg *types.Config, path string) (string, error) {

View File

@ -22,6 +22,7 @@ const (
FlagFeatureClient = "feature-client-settings"
FlagFeatureServices = "feature-services"
FlagFeatureFilters = "feature-filters"
FlagFeatureTLSConfig = "feature-tls-config"
FlagOriginURL = "origin-url"
FlagOriginWebURL = "origin-web-url"

View File

@ -1,7 +1,7 @@
package config
import (
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/types"
)
func readFlags(cfg *types.Config, flags Flags) error {
@ -173,8 +173,13 @@ func (fr *flagReader) readFeatureFlags() error {
}); err != nil {
return err
}
return fr.setBoolFlag(FlagFeatureFilters, func(cgf *types.Config, value bool) {
if err := fr.setBoolFlag(FlagFeatureFilters, func(cgf *types.Config, value bool) {
fr.cfg.Features.Filters = value
}); err != nil {
return err
}
return fr.setBoolFlag(FlagFeatureTLSConfig, func(cgf *types.Config, value bool) {
fr.cfg.Features.TLSConfig = value
})
}

View File

@ -7,8 +7,8 @@ import (
. "github.com/onsi/gomega"
gm "go.uber.org/mock/gomock"
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
"github.com/bakito/adguardhome-sync/pkg/types"
flagsmock "github.com/bakito/adguardhome-sync/internal/mocks/flags"
"github.com/bakito/adguardhome-sync/internal/types"
)
var _ = Describe("Config", func() {

View File

@ -11,8 +11,8 @@ import (
"gopkg.in/yaml.v3"
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/client"
"github.com/bakito/adguardhome-sync/internal/types"
"github.com/bakito/adguardhome-sync/version"
)

View File

@ -10,8 +10,8 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/bakito/adguardhome-sync/pkg/test/matchers"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/test/matchers"
"github.com/bakito/adguardhome-sync/internal/types"
"github.com/bakito/adguardhome-sync/version"
)

View File

@ -6,7 +6,7 @@ import (
. "github.com/onsi/gomega"
"gopkg.in/yaml.v3"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/types"
)
var _ = Describe("Config", func() {

View File

@ -3,8 +3,8 @@ package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/log"
)
const StatsTotal = "total"

View File

@ -6,7 +6,7 @@ import (
. "github.com/onsi/gomega"
"k8s.io/utils/ptr"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/internal/client/model"
)
var _ = Describe("Metrics", func() {

View File

@ -4,7 +4,7 @@ import (
"slices"
"strings"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/internal/client/model"
)
const labelTotal = "Total"

View File

@ -1,9 +1,9 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/bakito/adguardhome-sync/pkg/client (interfaces: Client)
// Source: github.com/bakito/adguardhome-sync/internal/client (interfaces: Client)
//
// Generated by this command:
//
// mockgen -package client -destination pkg/mocks/client/mock.go github.com/bakito/adguardhome-sync/pkg/client Client
// mockgen -package client -destination internal/mocks/client/mock.go github.com/bakito/adguardhome-sync/internal/client Client
//
// Package client is a generated GoMock package.
@ -12,7 +12,7 @@ package client
import (
reflect "reflect"
model "github.com/bakito/adguardhome-sync/pkg/client/model"
model "github.com/bakito/adguardhome-sync/internal/client/model"
gomock "go.uber.org/mock/gomock"
)
@ -509,6 +509,20 @@ func (mr *MockClientMockRecorder) SetStatsConfig(sc any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStatsConfig", reflect.TypeOf((*MockClient)(nil).SetStatsConfig), sc)
}
// SetTLSConfig mocks base method.
func (m *MockClient) SetTLSConfig(tls *model.TlsConfig) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetTLSConfig", tls)
ret0, _ := ret[0].(error)
return ret0
}
// SetTLSConfig indicates an expected call of SetTLSConfig.
func (mr *MockClientMockRecorder) SetTLSConfig(tls any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTLSConfig", reflect.TypeOf((*MockClient)(nil).SetTLSConfig), tls)
}
// Setup mocks base method.
func (m *MockClient) Setup() error {
m.ctrl.T.Helper()
@ -568,6 +582,21 @@ func (mr *MockClientMockRecorder) Status() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockClient)(nil).Status))
}
// TLSConfig mocks base method.
func (m *MockClient) TLSConfig() (*model.TlsConfig, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TLSConfig")
ret0, _ := ret[0].(*model.TlsConfig)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// TLSConfig indicates an expected call of TLSConfig.
func (mr *MockClientMockRecorder) TLSConfig() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TLSConfig", reflect.TypeOf((*MockClient)(nil).TLSConfig))
}
// ToggleFiltering mocks base method.
func (m *MockClient) ToggleFiltering(enabled bool, interval int) error {
m.ctrl.T.Helper()

View File

@ -1,9 +1,9 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/bakito/adguardhome-sync/pkg/config (interfaces: Flags)
// Source: github.com/bakito/adguardhome-sync/internal/config (interfaces: Flags)
//
// Generated by this command:
//
// mockgen -package client -destination pkg/mocks/flags/mock.go github.com/bakito/adguardhome-sync/pkg/config Flags
// mockgen -package client -destination internal/mocks/flags/mock.go github.com/bakito/adguardhome-sync/internal/config Flags
//
// Package client is a generated GoMock package.

View File

@ -3,9 +3,9 @@ package sync
import (
"go.uber.org/zap"
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/internal/client"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/utils"
)
var (
@ -236,6 +236,22 @@ var (
}
return nil
}
tlsConfig = func(ac *actionContext) error {
tlsc, err := ac.client.TLSConfig()
if err != nil {
return err
}
if !tlsc.Equals(ac.origin.tlsConfig) {
if err := ac.client.SetTLSConfig(ac.origin.tlsConfig); err != nil {
ac.rl.With("enabled", ac.origin.tlsConfig.Enabled, "error", err).Error("error setting tls config")
if !ac.cfg.ContinueOnError {
return err
}
}
}
return nil
}
)
func syncFilterType(

View File

@ -3,9 +3,9 @@ package sync
import (
"go.uber.org/zap"
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/client"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/types"
)
func setupActions(cfg *types.Config) (actions []syncAction) {
@ -68,6 +68,11 @@ func setupActions(cfg *types.Config) (actions []syncAction) {
action("DHCP static leases", actionDHCPStaticLeases),
)
}
if cfg.Features.TLSConfig {
actions = append(actions,
action("TLS config", tlsConfig),
)
}
return actions
}

View File

@ -16,18 +16,12 @@ import (
"github.com/gin-gonic/gin"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/metrics"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/internal/metrics"
"github.com/bakito/adguardhome-sync/internal/sync/static"
"github.com/bakito/adguardhome-sync/version"
)
var (
//go:embed index.html
index []byte
//go:embed favicon.ico
favicon []byte
)
func (w *worker) handleSync(c *gin.Context) {
l.With("remote-addr", c.Request.RemoteAddr).Info("Starting sync from API")
w.sync()
@ -43,35 +37,28 @@ func (w *worker) handleRoot(c *gin.Context) {
"Build": version.Build,
"SyncStatus": w.status(),
"Stats": map[string]any{
"Labels": getLast24Hours(),
"DNS": dns,
"Blocked": blocked,
"BlockedPercentage": fmt.Sprintf(
"%.2f",
(float64(*total.NumBlockedFiltering)*100.0)/float64(*total.NumDnsQueries),
),
"Malware": malware,
"MalwarePercentage": fmt.Sprintf(
"%.2f",
(float64(*total.NumReplacedSafebrowsing)*100.0)/float64(*total.NumDnsQueries),
),
"Adult": adult,
"AdultPercentage": fmt.Sprintf(
"%.2f",
(float64(*total.NumReplacedParental)*100.0)/float64(*total.NumDnsQueries),
),
"TotalDNS": total.NumDnsQueries,
"TotalBlocked": total.NumBlockedFiltering,
"TotalMalware": total.NumReplacedSafebrowsing,
"TotalAdult": total.NumReplacedParental,
"Labels": getLast24Hours(),
"DNS": dns,
"Blocked": blocked,
"BlockedPercentage": percent(total.NumBlockedFiltering, total.NumDnsQueries),
"Malware": malware,
"MalwarePercentage": percent(total.NumReplacedSafebrowsing, total.NumDnsQueries),
"Adult": adult,
"AdultPercentage": percent(total.NumReplacedParental, total.NumDnsQueries),
"TotalDNS": total.NumDnsQueries,
"TotalBlocked": total.NumBlockedFiltering,
"TotalMalware": total.NumReplacedSafebrowsing,
"TotalAdult": total.NumReplacedParental,
},
},
)
}
func (w *worker) handleFavicon(c *gin.Context) {
c.Data(http.StatusOK, "image/x-icon", favicon)
func percent(a, b *int) string {
if a == nil || b == nil || *b == 0 {
return "0.00"
}
return fmt.Sprintf("%.2f", (float64(*a)*100.0)/float64(*b))
}
func (w *worker) handleLogs(c *gin.Context) {
@ -87,6 +74,24 @@ func (w *worker) handleStatus(c *gin.Context) {
c.JSON(http.StatusOK, w.status())
}
func (w *worker) handleHealthz(c *gin.Context) {
status := w.status()
if status.Origin.Status != "success" {
c.Status(http.StatusServiceUnavailable)
return
}
for _, replica := range status.Replicas {
if replica.Status != "success" {
c.Status(http.StatusServiceUnavailable)
return
}
}
c.Status(http.StatusOK)
}
func (w *worker) listenAndServe() {
sl := l.With("port", w.cfg.API.Port)
if w.cfg.API.TLS.Enabled() {
@ -100,9 +105,27 @@ func (w *worker) listenAndServe() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Recovery())
r.HEAD("/healthz", w.handleHealthz)
r.GET("/healthz", w.handleHealthz)
var group gin.IRouter = r
if w.cfg.API.Username != "" && w.cfg.API.Password != "" {
r.Use(gin.BasicAuth(map[string]string{w.cfg.API.Username: w.cfg.API.Password}))
group = r.Group("/", gin.BasicAuth(map[string]string{w.cfg.API.Username: w.cfg.API.Password}))
}
group.POST("/api/v1/sync", w.handleSync)
group.GET("/api/v1/logs", w.handleLogs)
group.POST("/api/v1/clear-logs", w.handleClearLogs)
group.GET("/api/v1/status", w.handleStatus)
static.HandleResources(group, w.cfg.API.DarkMode)
group.GET("/", w.handleRoot)
if w.cfg.API.Metrics.Enabled {
group.GET("/metrics", metrics.Handler())
go w.startScraping()
}
httpServer := &http.Server{
Addr: fmt.Sprintf(":%d", w.cfg.API.Port),
Handler: r,
@ -110,18 +133,7 @@ func (w *worker) listenAndServe() {
ReadHeaderTimeout: 1 * time.Second,
}
r.SetHTMLTemplate(template.Must(template.New("index.html").Parse(string(index))))
r.POST("/api/v1/sync", w.handleSync)
r.GET("/api/v1/logs", w.handleLogs)
r.POST("/api/v1/clear-logs", w.handleClearLogs)
r.GET("/api/v1/status", w.handleStatus)
r.GET("/favicon.ico", w.handleFavicon)
r.GET("/", w.handleRoot)
if w.cfg.API.Metrics.Enabled {
r.GET("/metrics", metrics.Handler())
go w.startScraping()
}
r.SetHTMLTemplate(template.Must(template.New("index.html").Parse(static.Index())))
go func() {
var err error

View File

@ -0,0 +1,30 @@
package sync
import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Percent", func() {
DescribeTable("calculating percentage",
func(a, b *int, want string) {
Expect(percent(a, b)).To(Equal(want))
},
Entry("both inputs are nil", nil, nil, "0.00"),
Entry("a is nil, b is non-zero", nil, intPtr(10), "0.00"),
Entry("b is nil, a is non-zero", intPtr(10), nil, "0.00"),
Entry("b is zero", intPtr(10), intPtr(0), "0.00"),
Entry("normal case with positive int values", intPtr(25), intPtr(100), "25.00"),
Entry("a and b are equal", intPtr(50), intPtr(50), "100.00"),
Entry("a is zero, b is positive", intPtr(0), intPtr(50), "0.00"),
Entry("large positive values", intPtr(1000), intPtr(4000), "25.00"),
Entry("a greater than b", intPtr(150), intPtr(100), "150.00"),
Entry("negative values for a and b", intPtr(-25), intPtr(-50), "50.00"),
Entry("a is positive, b is negative", intPtr(25), intPtr(-50), "-50.00"),
Entry("a is negative, b is positive", intPtr(-25), intPtr(50), "-50.00"),
)
})
func intPtr(i int) *int {
return &i
}

View File

@ -3,8 +3,8 @@ package sync
import (
"time"
"github.com/bakito/adguardhome-sync/pkg/metrics"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/internal/metrics"
"github.com/bakito/adguardhome-sync/internal/types"
)
func (w *worker) startScraping() {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,16 +1,8 @@
<html lang="en">
<head>
<title>AdGuardHome sync</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.7.1.min.js">
</script>
{{- if .DarkMode }}
<link rel="stylesheet" href="https://bootswatch.com/5/darkly/bootstrap.min.css"
crossorigin="anonymous">
{{- else }}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
{{- end }}
<title>AdGuard Home sync</title>
<script type="text/javascript" src="lib/jquery.js"></script>
<link rel="stylesheet" href="lib/bootstrap.css">
<script type="text/javascript">
$(document).ready(function () {
$("#showLogs").click(function () {
@ -86,10 +78,13 @@
<body>
<div class="container-fluid px-4">
<div class="row">
<p class="h1">
AdGuardHome sync
<p class="h6">{{ .Version }} ({{ .Build }})</p>
</p>
<div class="d-flex align-items-center mb-3">
<img src="logo.svg" alt="Logo" class="me-3" style="height: 4em;">
<div>
<h1 class="mb-0">AdGuard Home sync</h1>
<p class="h6 text-muted mb-0">{{ .Version }} ({{ .Build }})</p>
</div>
</div>
</div>
{{- if .Metrics }}
<div class="row g-4 d-flex">
@ -165,16 +160,10 @@
</div>
</div>
<!-- openssl dgst -sha384 -binary popper.min.js | openssl base64 -A -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"
integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"
integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous">
</script>
<script src="lib/popper.js" ></script>
<script src="lib/bootstrap.js" ></script>
{{- if .Metrics }}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"ŝ
integrity="sha384-vsrfeLOOY6KuIYKDlmVH5UiBmgIdB1oEf7p01YgWHuqmOHfZr374+odEv96n9tNC" crossorigin="anonymous">
</script>
<script src="lib/chart.js" ></script>
<script>
// Function to create minimal line charts
function createChart(canvasId, data) {

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" id="svg3" version="1.2" viewBox="0 0 1000 1000"><defs id="defs3"><linearGradient id="swatch26"><stop style="stop-color:#000;stop-opacity:1" id="stop26" offset="0"/></linearGradient><linearGradient id="swatch25"><stop style="stop-color:#407b28;stop-opacity:1" id="stop25" offset="0"/></linearGradient></defs><path id="path1" fill="#68bc71" d="m 993.75002,114.1 c 0,171.8 3.1,595.3 -493.8,885.9 C 3.0500233,709.4 6.2500233,285.9 6.2500233,114.1 159.35002,35.9 345.25002,0 499.95002,0 c 154.7,0 340.6,35.9 493.8,114.1 z"/><path id="path2" fill="#67b279" d="M500 1000C3.1 709.4 6.2 285.9 6.2 114.1 159.4 35.9 345.3 0 500 0z"/><path id="path3" fill="#fff" d="m 225,449.6 c 15,-11.7 80,-53.4 128.3,1.6 L 453.3,569.6 720,297.9 c 11.7,-10 31.7,-23.3 55,-5 L 455,716.2 Z" style="display:none"/><circle style="display:none;fill:#fff;fill-opacity:.5;stroke:#fff;stroke-width:8e-08;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-opacity:.502604" id="path18" cx="-500" cy="426" r="400" transform="scale(-1,1)"/><path id="path12-8" style="fill:#fff;fill-opacity:1;stroke:#fff;stroke-width:4.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-opacity:1" d="m -75.867249,555.75073 c -1.469322,-39.92741 -12.296964,-76.43624 -30.823861,-104.61661 -21.05517,28.18037 -47.89663,45.38022 -75.18829,53.68483 l 42.51192,20.42415 c -33.35434,61.94297 -101.60764,105.3289 -167.51689,101.23666 -42.42317,-1.43193 -82.3318,-22.18867 -112.01355,-52.33871 -21.09944,-21.43232 -53.37423,-31.44115 -79.38397,-16.1329 l -10.3958,6.11853 c 43.49744,68.86447 120.54256,113.80911 201.79332,112.04834 87.97224,-4.41047 162.60077,-62.73987 194.96448,-137.74518 z M -537.90127,346.51705 c 1.46924,39.92741 12.29681,76.43626 30.82364,104.61667 21.05523,-28.18031 47.89674,-45.38011 75.18842,-53.68467 l -42.51189,-20.42423 c 33.35441,-61.94281 101.60759,-105.32857 167.51673,-101.23635 42.4233,1.43194 82.33203,22.18879 112.01381,52.33897 21.0994,21.43235 53.37417,31.44124 79.38393,16.13305 l 10.39581,-6.11852 c -43.49739,-68.86468 -120.54264,-113.8095 -201.79355,-112.04872 -87.97208,4.41046 -162.60049,62.73965 -194.96429,137.74477 z" transform="matrix(0,-1.3167476,1.3167476,0,-94.029776,21.910887)"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,80 @@
package static
import (
_ "embed"
"net/http"
"github.com/gin-gonic/gin"
)
var (
//go:embed index.html
index string
//go:embed favicon.ico
favicon []byte
//go:embed logo.svg
logo []byte
//go:embed bootstrap.min-5.3.3.js
bootstrapJS []byte
// https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css
//go:embed bootstrap.min-5.3.3.css
bootstrapCSS []byte
// https://bootswatch.com/5/darkly/bootstrap.min.css
//go:embed bootstrap.min-darkly-5.3.css
bootstrapDarkCSS []byte
// https://code.jquery.com/jquery-3.7.1.min.js
//go:embed jquery-3.7.1.min.js
jquery []byte
// https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js
//go:embed popper.min-2.9.2.js
popper []byte
// https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js
//go:embed chart.umd.min-4.4.7.js
chart []byte
)
func handleFavicon(c *gin.Context) {
c.Data(http.StatusOK, "image/x-icon", favicon)
}
func handleLogo(c *gin.Context) {
c.Data(http.StatusOK, "image/svg+xml", logo)
}
func Index() string {
return index
}
func HandleResources(group gin.IRouter, dark bool) {
group.GET("/favicon.ico", handleFavicon)
group.GET("/logo.svg", handleLogo)
group.GET("/lib/jquery.js", handleJS(jquery))
group.GET("/lib/popper.js", handleJS(popper))
group.GET("/lib/chart.js", handleJS(chart))
group.GET("/lib/bootstrap.js", handleJS(bootstrapJS))
if dark {
group.GET("/lib/bootstrap.css", handleCSS(bootstrapDarkCSS))
} else {
group.GET("/lib/bootstrap.css", handleCSS(bootstrapCSS))
}
}
func handleJS(bytes []byte) gin.HandlerFunc {
return func(c *gin.Context) {
c.Data(http.StatusOK, "application/javascript", bytes)
}
}
func handleCSS(bytes []byte) gin.HandlerFunc {
return func(c *gin.Context) {
c.Data(http.StatusOK, "text/css", bytes)
}
}

View File

@ -3,6 +3,7 @@ package sync
import (
"errors"
"fmt"
"net/http"
"runtime"
"sort"
"time"
@ -10,13 +11,13 @@ import (
"github.com/robfig/cron/v3"
"go.uber.org/zap"
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/metrics"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/pkg/versions"
"github.com/bakito/adguardhome-sync/internal/client"
"github.com/bakito/adguardhome-sync/internal/client/model"
"github.com/bakito/adguardhome-sync/internal/log"
"github.com/bakito/adguardhome-sync/internal/metrics"
"github.com/bakito/adguardhome-sync/internal/types"
"github.com/bakito/adguardhome-sync/internal/utils"
"github.com/bakito/adguardhome-sync/internal/versions"
"github.com/bakito/adguardhome-sync/version"
)
@ -184,7 +185,14 @@ func (w *worker) sync() {
o.profileInfo, err = oc.ProfileInfo()
if err != nil {
sl.With("error", err).Error("Error getting profileInfo info")
return
// Workaround for https://github.com/AdguardTeam/AdGuardHome/issues/7987
// and https://github.com/AdguardTeam/AdGuardHome/issues/7985
clientErr := &client.Error{}
if !w.cfg.ContinueOnError || !errors.As(err, &clientErr) || clientErr.Code() != http.StatusUnauthorized {
return
}
}
o.parental, err = oc.Parental()
@ -256,6 +264,14 @@ func (w *worker) sync() {
}
}
if w.cfg.Features.TLSConfig {
o.tlsConfig, err = oc.TLSConfig()
if err != nil {
sl.With("error", err).Error("Error getting tls config")
return
}
}
w.actions = setupActions(w.cfg)
replicas := w.cfg.UniqueReplicas()
@ -361,4 +377,5 @@ type origin struct {
safeSearch *model.SafeSearchConfig
profileInfo *model.ProfileInfo
safeBrowsing bool
tlsConfig *model.TlsConfig
}

View File

@ -8,12 +8,12 @@ import (
. "github.com/onsi/gomega"
gm "go.uber.org/mock/gomock"
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/client/model"
clientmock "github.com/bakito/adguardhome-sync/pkg/mocks/client"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/bakito/adguardhome-sync/pkg/versions"
"github.com/bakito/adguardhome-sync/internal/client"
"github.com/bakito/adguardhome-sync/internal/client/model"
clientmock "github.com/bakito/adguardhome-sync/internal/mocks/client"
"github.com/bakito/adguardhome-sync/internal/types"
"github.com/bakito/adguardhome-sync/internal/utils"
"github.com/bakito/adguardhome-sync/internal/versions"
)
var _ = Describe("Sync", func() {
@ -594,6 +594,7 @@ var _ = Describe("Sync", func() {
GeneralSettings: true,
StatsConfig: true,
QueryLogConfig: true,
TLSConfig: true,
},
}
})
@ -614,6 +615,7 @@ var _ = Describe("Sync", func() {
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
cl.EXPECT().DhcpConfig().Return(&model.DhcpStatus{}, nil)
cl.EXPECT().TLSConfig().Return(&model.TlsConfig{}, nil)
// replica
cl.EXPECT().Host()
@ -633,6 +635,7 @@ var _ = Describe("Sync", func() {
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
cl.EXPECT().DhcpConfig().Return(&model.DhcpStatus{}, nil)
cl.EXPECT().TLSConfig().Return(&model.TlsConfig{}, nil)
w.sync()
})
It("should not sync DHCP", func() {
@ -653,6 +656,7 @@ var _ = Describe("Sync", func() {
cl.EXPECT().StatsConfig().Return(&model.PutStatsConfigUpdateRequest{}, nil)
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
cl.EXPECT().TLSConfig().Return(&model.TlsConfig{}, nil)
// replica
cl.EXPECT().Host()
@ -671,6 +675,7 @@ var _ = Describe("Sync", func() {
cl.EXPECT().Clients().Return(&model.Clients{}, nil)
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
cl.EXPECT().TLSConfig().Return(&model.TlsConfig{}, nil)
w.sync()
})
It("origin version is too small", func() {
@ -696,6 +701,7 @@ var _ = Describe("Sync", func() {
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
cl.EXPECT().DhcpConfig().Return(&model.DhcpStatus{}, nil)
cl.EXPECT().TLSConfig().Return(&model.TlsConfig{}, nil)
// replica
cl.EXPECT().Host().Times(2)

View File

@ -22,6 +22,7 @@ func NewFeatures(enabled bool) Features {
Services: enabled,
Filters: enabled,
Theme: enabled,
TLSConfig: false,
}
}
@ -35,7 +36,8 @@ type Features struct {
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" documentation:"Sync client settings" env:"FEATURES_CLIENT_SETTINGS"`
Services bool `json:"services" yaml:"services" documentation:"Sync services" env:"FEATURES_SERVICES"`
Filters bool `json:"filters" yaml:"filters" documentation:"Sync filters" env:"FEATURES_FILTERS"`
Theme bool `json:"theme" yaml:"theme" documentation:"Sync the weg UI theme" env:"FEATURES_THEME"`
Theme bool `json:"theme" yaml:"theme" documentation:"Sync the web UI theme" env:"FEATURES_THEME"`
TLSConfig bool `json:"tlsConfig" yaml:"tlsConfig" documentation:"Sync the TLS config" env:"FEATURES_TLS_CONFIG"`
}
// DHCP features.
@ -95,5 +97,8 @@ func (f *Features) collectDisabled() []string {
if !f.Filters {
features = append(features, "Filters")
}
if !f.TLSConfig {
features = append(features, "TLSConfig")
}
return features
}

View File

@ -27,7 +27,7 @@ type Config struct {
// Multiple replica instances
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty" faker:"slice_len=2"`
Cron string `json:"cron,omitempty" yaml:"cron,omitempty" documentation:"Cron expression for the sync interval" env:"CRON"`
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" documentation:"Run the sung on startup" env:"RUN_ON_START"`
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" documentation:"Run the sync on startup" env:"RUN_ON_START"`
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" documentation:"Print current config only and stop the application" env:"PRINT_CONFIG_ONLY"`
ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" documentation:"Continue sync on errors" env:"CONTINUE_ON_ERROR"`
API API `json:"api,omitempty" yaml:"api,omitempty"`
@ -36,12 +36,12 @@ type Config struct {
// API configuration.
type API struct {
Port int `documentation:"API port" env:"API_PORT" json:"port,omitempty" yaml:"port,omitempty"`
Username string `documentation:"API username" env:"API_USERNAME" json:"username,omitempty" yaml:"username,omitempty"`
Password string `documentation:"API password" env:"API_PASSWORD" json:"password,omitempty" yaml:"password,omitempty"`
DarkMode bool `documentation:"API dark mode" env:"API_DARK_MODE" json:"darkMode,omitempty" yaml:"darkMode,omitempty"`
Metrics Metrics ` json:"metrics,omitempty" yaml:"metrics,omitempty"`
TLS TLS ` json:"tls,omitempty" yaml:"tls,omitempty"`
Port int `documentation:"API port (API is disabled if port is set to 0)" env:"API_PORT" json:"port,omitempty" yaml:"port,omitempty"`
Username string `documentation:"API username" env:"API_USERNAME" json:"username,omitempty" yaml:"username,omitempty"`
Password string `documentation:"API password" env:"API_PASSWORD" json:"password,omitempty" yaml:"password,omitempty"`
DarkMode bool `documentation:"API dark mode" env:"API_DARK_MODE" json:"darkMode,omitempty" yaml:"darkMode,omitempty"`
Metrics Metrics ` json:"metrics,omitempty" yaml:"metrics,omitempty"`
TLS TLS ` json:"tls,omitempty" yaml:"tls,omitempty"`
}
// Metrics configuration.

View File

@ -102,11 +102,11 @@ var _ = Describe("Types", func() {
Context("LogDisabled", func() {
It("should log all features", func() {
f := NewFeatures(false)
Ω(f.collectDisabled()).Should(HaveLen(11))
Ω(f.collectDisabled()).Should(HaveLen(12))
})
It("should log no features", func() {
f := NewFeatures(true)
Ω(f.collectDisabled()).Should(BeEmpty())
Ω(f.collectDisabled()).Should(HaveLen(1))
})
})
})

View File

@ -4,7 +4,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/bakito/adguardhome-sync/pkg/versions"
"github.com/bakito/adguardhome-sync/internal/versions"
)
var _ = Describe("Versions", func() {
@ -14,6 +14,11 @@ var _ = Describe("Versions", func() {
Ω(versions.IsNewerThan("v0.106.9", "v0.106.10")).Should(BeFalse())
Ω(versions.IsNewerThan("v0.106.10", "0.106.9")).Should(BeTrue())
Ω(versions.IsNewerThan("v0.106.9", "0.106.10")).Should(BeFalse())
// tests for #607
Ω(versions.IsNewerThan("v0.108.0-b.72", versions.MinAgh)).Should(BeTrue())
Ω(versions.IsNewerThan("0.108.0-b.72", versions.MinAgh)).Should(BeTrue())
Ω(versions.IsNewerThan(versions.MinAgh, "v0.108.0-b.72")).Should(BeFalse())
Ω(versions.IsNewerThan(versions.MinAgh, "0.108.0-b.72")).Should(BeFalse())
})
})
Context("IsSame", func() {

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" id="svg3" version="1.2" viewBox="0 0 1000 1000"><defs id="defs3"><linearGradient id="swatch26"><stop style="stop-color:#000;stop-opacity:1" id="stop26" offset="0"/></linearGradient><linearGradient id="swatch25"><stop style="stop-color:#407b28;stop-opacity:1" id="stop25" offset="0"/></linearGradient></defs><path id="path1" fill="#68bc71" d="m 993.75002,114.1 c 0,171.8 3.1,595.3 -493.8,885.9 C 3.0500233,709.4 6.2500233,285.9 6.2500233,114.1 159.35002,35.9 345.25002,0 499.95002,0 c 154.7,0 340.6,35.9 493.8,114.1 z"/><path id="path2" fill="#67b279" d="M500 1000C3.1 709.4 6.2 285.9 6.2 114.1 159.4 35.9 345.3 0 500 0z"/><path id="path3" fill="#fff" d="m 225,449.6 c 15,-11.7 80,-53.4 128.3,1.6 L 453.3,569.6 720,297.9 c 11.7,-10 31.7,-23.3 55,-5 L 455,716.2 Z" style="display:none"/><circle style="display:none;fill:#fff;fill-opacity:.5;stroke:#fff;stroke-width:8e-08;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-opacity:.502604" id="path18" cx="-500" cy="426" r="400" transform="scale(-1,1)"/><path id="path12-8" style="fill:#fff;fill-opacity:1;stroke:#fff;stroke-width:4.00001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-opacity:1" d="m -75.867249,555.75073 c -1.469322,-39.92741 -12.296964,-76.43624 -30.823861,-104.61661 -21.05517,28.18037 -47.89663,45.38022 -75.18829,53.68483 l 42.51192,20.42415 c -33.35434,61.94297 -101.60764,105.3289 -167.51689,101.23666 -42.42317,-1.43193 -82.3318,-22.18867 -112.01355,-52.33871 -21.09944,-21.43232 -53.37423,-31.44115 -79.38397,-16.1329 l -10.3958,6.11853 c 43.49744,68.86447 120.54256,113.80911 201.79332,112.04834 87.97224,-4.41047 162.60077,-62.73987 194.96448,-137.74518 z M -537.90127,346.51705 c 1.46924,39.92741 12.29681,76.43626 30.82364,104.61667 21.05523,-28.18031 47.89674,-45.38011 75.18842,-53.68467 l -42.51189,-20.42423 c 33.35441,-61.94281 101.60759,-105.32857 167.51673,-101.23635 42.4233,1.43194 82.33203,22.18879 112.01381,52.33897 21.0994,21.43235 53.37417,31.44124 79.38393,16.13305 l 10.39581,-6.11852 c -43.49739,-68.86468 -120.54264,-113.8095 -201.79355,-112.04872 -87.97208,4.41046 -162.60049,62.73965 -194.96429,137.74477 z" transform="matrix(0,-1.3167476,1.3167476,0,-94.029776,21.910887)"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,139 +0,0 @@
package config_test
import (
"fmt"
"os"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/bakito/adguardhome-sync/pkg/config"
)
var envVars = []string{
"FEATURES_GENERAL_SETTINGS",
"FEATURES_QUERY_LOG_CONFIG",
"FEATURES_STATS_CONFIG",
"FEATURES_CLIENT_SETTINGS",
"FEATURES_SERVICES",
"FEATURES_FILTERS",
"FEATURES_THEME",
"FEATURES_DHCP_SERVER_CONFIG",
"FEATURES_DHCP_STATIC_LEASES",
"FEATURES_DNS_SERVER_CONFIG",
"FEATURES_DNS_ACCESS_LISTS",
"FEATURES_DNS_REWRITES",
"REPLICA1_INTERFACE_NAME",
"REPLICA1_DHCP_SERVER_ENABLED",
}
var deprecatedEnvVars = []string{
"FEATURES_GENERALSETTINGS",
"FEATURES_QUERYLOGCONFIG",
"FEATURES_STATSCONFIG",
"FEATURES_CLIENTSETTINGS",
"FEATURES_SERVICES",
"FEATURES_FILTERS",
"FEATURES_DHCP_SERVERCONFIG",
"FEATURES_DHCP_STATICLEASES",
"FEATURES_DNS_SERVERCONFIG",
"FEATURES_DNS_ACCESSLISTS",
"FEATURES_DNS_REWRITES",
"REPLICA1_INTERFACENAME",
"REPLICA1_DHCPSERVERENABLED",
}
var _ = Describe("Config", func() {
Context("deprecated", func() {
BeforeEach(func() {
for _, envVar := range deprecatedEnvVars {
Ω(os.Setenv(envVar, "false")).ShouldNot(HaveOccurred())
}
})
AfterEach(func() {
for _, envVar := range deprecatedEnvVars {
Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred())
}
})
Context("Get", func() {
It("features should be false", func() {
cfg, err := config.Get("", nil)
Ω(err).ShouldNot(HaveOccurred())
verifyFeatures(cfg, false)
})
})
})
Context("current", func() {
BeforeEach(func() {
for _, envVar := range envVars {
Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred())
}
})
AfterEach(func() {
for _, envVar := range envVars {
Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred())
}
})
Context("Get", func() {
It("features should be true by default", func() {
cfg, err := config.Get("", nil)
Ω(err).ShouldNot(HaveOccurred())
verifyFeatures(cfg, true)
})
It("features should be true by default", func() {
cfg, err := config.Get("", nil)
Ω(err).ShouldNot(HaveOccurred())
verifyFeatures(cfg, true)
})
It("features should be false", func() {
for _, envVar := range envVars {
Ω(os.Setenv(envVar, "false")).ShouldNot(HaveOccurred())
}
cfg, err := config.Get("", nil)
Ω(err).ShouldNot(HaveOccurred())
verifyFeatures(cfg, false)
})
Context("interface name", func() {
It("should set interface name of replica 1", func() {
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_INTERFACE_NAME", "1"), "eth0")).ShouldNot(HaveOccurred())
cfg, err := config.Get("", nil)
Ω(err).ShouldNot(HaveOccurred())
Ω(cfg.Get().Replicas[0].InterfaceName).Should(Equal("eth0"))
})
})
Context("dhcp server", func() {
It("should enable the dhcp server of replica 1", func() {
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "true")).ShouldNot(HaveOccurred())
cfg, err := config.Get("", nil)
Ω(err).ShouldNot(HaveOccurred())
Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeTrue())
})
It("should disable the dhcp server of replica 1", func() {
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "false")).ShouldNot(HaveOccurred())
cfg, err := config.Get("", nil)
Ω(err).ShouldNot(HaveOccurred())
Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeFalse())
})
})
})
})
})
func verifyFeatures(cfg *config.AppConfig, value bool) {
Ω(cfg.Get().Features.GeneralSettings).Should(Equal(value))
Ω(cfg.Get().Features.QueryLogConfig).Should(Equal(value))
Ω(cfg.Get().Features.StatsConfig).Should(Equal(value))
Ω(cfg.Get().Features.ClientSettings).Should(Equal(value))
Ω(cfg.Get().Features.Services).Should(Equal(value))
Ω(cfg.Get().Features.Filters).Should(Equal(value))
Ω(cfg.Get().Features.DHCP.ServerConfig).Should(Equal(value))
Ω(cfg.Get().Features.DHCP.StaticLeases).Should(Equal(value))
Ω(cfg.Get().Features.DNS.ServerConfig).Should(Equal(value))
Ω(cfg.Get().Features.DNS.AccessLists).Should(Equal(value))
Ω(cfg.Get().Features.DNS.Rewrites).Should(Equal(value))
}

View File

@ -1,146 +0,0 @@
package config
import (
"fmt"
"os"
"strconv"
"strings"
"github.com/caarlos0/env/v11"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/pkg/utils"
)
func handleDeprecatedEnvVars(cfg *types.Config) {
if val, ok := checkDeprecatedEnvVar("RUNONSTART", "RUN_ON_START"); ok {
cfg.RunOnStart, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("API_DARKMODE", "API_DARK_MODE"); ok {
cfg.API.DarkMode, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_GENERALSETTINGS", "FEATURES_GENERAL_SETTINGS"); ok {
cfg.Features.GeneralSettings, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_QUERYLOGCONFIG", "FEATURES_QUERY_LOG_CONFIG"); ok {
cfg.Features.QueryLogConfig, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_STATSCONFIG", "FEATURES_STATS_CONFIG"); ok {
cfg.Features.StatsConfig, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_CLIENTSETTINGS", "FEATURES_CLIENT_SETTINGS"); ok {
cfg.Features.ClientSettings, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_DHCP_SERVERCONFIG", "FEATURES_DHCP_SERVER_CONFIG"); ok {
cfg.Features.DHCP.ServerConfig, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_DHCP_STATICLEASES", "FEATURES_DHCP_STATIC_LEASES"); ok {
cfg.Features.DHCP.StaticLeases, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_DNS_ACCESSLISTS", "FEATURES_DNS_ACCESS_LISTS"); ok {
cfg.Features.DNS.AccessLists, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("FEATURES_DNS_SERVERCONFIG", "FEATURES_DNS_SERVER_CONFIG"); ok {
cfg.Features.DNS.ServerConfig, _ = strconv.ParseBool(val)
}
if cfg.Replica != nil {
if val, ok := checkDeprecatedEnvVar("REPLICA_WEBURL", "REPLICA_WEB_URL"); ok {
cfg.Replica.WebURL = val
}
if val, ok := checkDeprecatedEnvVar("REPLICA_AUTOSETUP", "REPLICA_AUTO_SETUP"); ok {
cfg.Replica.AutoSetup, _ = strconv.ParseBool(val)
}
if val, ok := checkDeprecatedEnvVar("REPLICA_INTERFACENAME", "REPLICA_INTERFACE_NAME"); ok {
cfg.Replica.InterfaceName = val
}
if val, ok := checkDeprecatedEnvVar("REPLICA_DHCPSERVERENABLED", "REPLICA_DHCP_SERVER_ENABLED"); ok {
if b, err := strconv.ParseBool(val); err != nil {
cfg.Replica.DHCPServerEnabled = utils.Ptr(b)
}
}
}
}
func checkDeprecatedEnvVar(oldName, newName string) (string, bool) {
old, oldOK := os.LookupEnv(oldName)
if oldOK {
logger.With("deprecated", oldName, "replacement", newName).
Warn("Deprecated env variable is used, please use the correct one")
}
newVal, newOK := os.LookupEnv(newName)
if newOK {
return newVal, true
}
return old, oldOK
}
func checkDeprecatedReplicaEnvVar(oldPattern, newPattern string, replicaID int) (string, bool) {
return checkDeprecatedEnvVar(fmt.Sprintf(oldPattern, replicaID), fmt.Sprintf(newPattern, replicaID))
}
// Manually collect replicas from env.
func enrichReplicasFromEnv(initialReplicas []types.AdGuardInstance) ([]types.AdGuardInstance, error) {
var replicas []types.AdGuardInstance
for _, v := range os.Environ() {
if envReplicasURLPattern.MatchString(v) {
sm := envReplicasURLPattern.FindStringSubmatch(v)
id, _ := strconv.Atoi(sm[1])
if id <= 0 {
return nil, fmt.Errorf("numbered replica env variables must have a number id >= 1, got %q", v)
}
if id > len(initialReplicas) {
replicas = append(replicas, types.AdGuardInstance{URL: sm[2]})
} else {
re := initialReplicas[id-1]
re.URL = sm[2]
replicas = append(replicas, re)
}
}
}
if len(replicas) == 0 {
replicas = initialReplicas
}
for i := range replicas {
reID := i + 1
// keep previously set value
replicaDhcpServer := replicas[i].DHCPServerEnabled
replicas[i].DHCPServerEnabled = nil
if err := env.ParseWithOptions(&replicas[i], env.Options{Prefix: fmt.Sprintf("REPLICA%d_", reID)}); err != nil {
return nil, err
}
if replicas[i].DHCPServerEnabled == nil {
replicas[i].DHCPServerEnabled = replicaDhcpServer
}
if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_APIPATH", "REPLICA%d_API_PATH", reID); ok {
replicas[i].APIPath = val
}
if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_INSECURESKIPVERIFY", "REPLICA%d_INSECURE_SKIP_VERIFY", reID); ok {
replicas[i].InsecureSkipVerify = strings.EqualFold(val, "true")
}
if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_AUTOSETUP", "REPLICA%d_AUTO_SETUP", reID); ok {
replicas[i].AutoSetup = strings.EqualFold(val, "true")
}
if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_INTERFACENAME", "REPLICA%d_INTERFACE_NAME", reID); ok {
replicas[i].InterfaceName = val
}
if dhcpEnabled, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_DHCPSERVERENABLED", "REPLICA%d_DHCP_SERVER_ENABLED", reID); ok {
if strings.EqualFold(dhcpEnabled, "true") {
replicas[i].DHCPServerEnabled = utils.Ptr(true)
} else if strings.EqualFold(dhcpEnabled, "false") {
replicas[i].DHCPServerEnabled = utils.Ptr(false)
}
}
if replicas[i].APIPath == "" {
replicas[i].APIPath = "/control"
}
}
return replicas, nil
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1,6 +1,6 @@
#!/bin/bash
set -e
echo "## AdGuardHome.yaml of latest replica" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
kubectl exec adguardhome-replica-latest -- cat /opt/adguardhome/conf/AdGuardHome.yaml >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "## AdGuardHome.yaml of latest replica" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
kubectl exec adguardhome-replica-latest -- cat /opt/adguardhome/conf/AdGuardHome.yaml >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

View File

@ -1,3 +1,5 @@
#!/bin/bash
kubectl wait --for=jsonpath='{.status.phase}'=Running pod/adguardhome-sync --timeout=1m
kubectl describe pod/adguardhome-sync
kubectl logs pod/adguardhome-sync

View File

@ -153,7 +153,12 @@ filtering:
blocking_mode: default
parental_block_host: family-block.dns.adguard.com
safebrowsing_block_host: standard-block.dns.adguard.com
rewrites: []
rewrites:
- domain: foo.com
answer: 1.2.3.4
- domain: bar.com
answer: 1.2.3.3
safebrowsing_cache_size: 1048576
safesearch_cache_size: 1048576
parental_cache_size: 1048576

View File

@ -1,11 +1,12 @@
replica:
versions:
- v0.107.40
- v0.107.43
- v0.107.63
- v0.107.67
- v0.107.68
- latest
mode: env
kubectl:
repository: bitnami/kubectl
tag: "1.30"
repository: bitnamisecure/kubectl
tag: "latest"