From 7ab38dd825af0e157e9c56c49372a965f9929e93 Mon Sep 17 00:00:00 2001 From: jesse-matsec <101210230+jesse-matsec@users.noreply.github.com> Date: Sat, 24 Jun 2023 11:12:48 -0400 Subject: [PATCH 01/79] dnscontrol get-zones --help typo fix (#2459) --- commands/getZones.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/getZones.go b/commands/getZones.go index 6a09468ee..89d39da91 100644 --- a/commands/getZones.go +++ b/commands/getZones.go @@ -70,7 +70,7 @@ EXAMPLES: dnscontrol get-zones gmain GANDI_V5 example.com other.com dnscontrol get-zones cfmain CLOUDFLAREAPI all dnscontrol get-zones --format=tsv bind BIND example.com - dnscontrol get-zones --format=djs --out=draft.js glcoud GCLOUD example.com`, + dnscontrol get-zones --format=djs --out=draft.js gcloud GCLOUD example.com`, } }()) From 0f1a256311901758b02e10619689183e78fd8ae6 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sun, 25 Jun 2023 10:38:46 -0600 Subject: [PATCH 02/79] CHORE: Update dependencies (#2460) --- go.mod | 44 ++++++++++----------- go.sum | 121 ++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 99 insertions(+), 66 deletions(-) diff --git a/go.mod b/go.mod index 172718366..56b6bfc3f 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,11 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.18.0 - github.com/aws/aws-sdk-go-v2/config v1.18.25 - github.com/aws/aws-sdk-go-v2/credentials v1.13.24 - github.com/aws/aws-sdk-go-v2/service/route53 v1.28.1 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.14.10 + github.com/aws/aws-sdk-go-v2 v1.18.1 + github.com/aws/aws-sdk-go-v2/config v1.18.27 + github.com/aws/aws-sdk-go-v2/credentials v1.13.26 + github.com/aws/aws-sdk-go-v2/service/route53 v1.28.3 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.15.0 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 @@ -33,7 +33,7 @@ require ( github.com/hashicorp/vault/api v1.9.2 github.com/jarcoal/httpmock v1.0.8 // indirect github.com/jinzhu/copier v0.3.5 - github.com/miekg/dns v1.1.54 + github.com/miekg/dns v1.1.55 github.com/mittwald/go-powerdns v0.6.2 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 github.com/nrdcg/goinwx v0.8.2 @@ -47,11 +47,11 @@ require ( github.com/softlayer/softlayer-go v1.1.2 github.com/stretchr/testify v1.8.4 github.com/transip/gotransip/v6 v6.20.0 - github.com/urfave/cli/v2 v2.25.5 + github.com/urfave/cli/v2 v2.25.7 github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 - golang.org/x/net v0.10.0 - golang.org/x/oauth2 v0.8.0 - google.golang.org/api v0.125.0 + golang.org/x/net v0.11.0 + golang.org/x/oauth2 v0.9.0 + google.golang.org/api v0.128.0 gopkg.in/ns1/ns1-go.v2 v2.7.4 ) @@ -64,7 +64,7 @@ require ( github.com/mattn/go-isatty v0.0.19 github.com/vultr/govultr/v2 v2.17.2 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - golang.org/x/text v0.9.0 + golang.org/x/text v0.10.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -76,14 +76,14 @@ require ( github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -101,7 +101,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.4 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect github.com/googleapis/gax-go/v2 v2.10.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -132,10 +132,10 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.9.0 // indirect + golang.org/x/crypto v0.10.0 // indirect golang.org/x/mod v0.9.0 // indirect golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sys v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.7.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index da124540b..815ee4c4c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds= cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= @@ -19,6 +20,7 @@ github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcP github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 h1:AJKJCKcb/psppPl/9CUiQQnTG+Bce0/cIweD5w5Q7aQ= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= github.com/G-Core/gcore-dns-sdk-go v0.2.6 h1:R82ANd7BnhIe2mV/12Ebdx9QYVl2++E4kfDIu97JEOk= @@ -29,38 +31,39 @@ github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 h1:vfVc5pSCq58lj github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36/go.mod h1:MwE/QxFCN65F0hKGWFHUh2U2o1p2tMPNR1zHkX6vEh8= github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 h1:F1j7z+/DKEsYqZNoxC6wvfmaiDneLsQOFQmuq9NADSY= github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2/go.mod h1:QlXr/TrICfQ/ANa76sLeQyhAJyNR9sEcfNuZBkY9jgY= +github.com/alecthomas/kong v0.2.2/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= -github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.25 h1:JuYyZcnMPBiFqn87L2cRppo+rNwgah6YwD3VuyvaW6Q= -github.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4= -github.com/aws/aws-sdk-go-v2/credentials v1.13.24 h1:PjiYyls3QdCrzqUN35jMWtUK1vqVZ+zLfdOa/UPFDp0= -github.com/aws/aws-sdk-go-v2/credentials v1.13.24/go.mod h1:jYPYi99wUOPIFi0rhiOvXeSEReVOzBqFNOX5bXYoG2o= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 h1:jJPgroehGvjrde3XufFIJUZVK5A2L9a3KwSFgKy9n8w= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 h1:gGLG7yKaXG02/jBlg210R7VgQIotiQntNhsCFejawx8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 h1:0iKliEXAcCa2qVtRs7Ot5hItA2MsufrphbRFlz1Owxo= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= -github.com/aws/aws-sdk-go-v2/service/route53 v1.28.1 h1:8e1fgdyer5IqBPtiWNsVLY/XFucmNTtYMqADyCFXTgQ= -github.com/aws/aws-sdk-go-v2/service/route53 v1.28.1/go.mod h1:9SEpwqaALzp34eCT6w5PTh4SDDT84wxfMRx9VJSJPsk= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.14.10 h1:BSgJnMWjJtrnZeRnJIMt+YheRxNESIenlZL/xP2Xtt4= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.14.10/go.mod h1:ZCAB0DgknPFchQTI0rWjWlLe6U/2eDBqPMzVAjkZuzQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 h1:UBQjaMTCKwyUYwiVnUt6toEJwGXsLBI6al083tpjJzY= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 h1:PkHIIJs8qvq0e5QybnZoG1K/9QTrLr9OsqCIo59jOBA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk= -github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 h1:2DQLAKDteoEDI8zpCzqBMaZlJuoE9iTYD0gFmXVax9E= -github.com/aws/aws-sdk-go-v2/service/sts v1.19.0/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8= +github.com/aws/aws-sdk-go-v2 v1.18.1 h1:+tefE750oAb7ZQGzla6bLkOwfcQCEtC5y2RqoqCeqKo= +github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.27 h1:Az9uLwmssTE6OGTpsFqOnaGpLnKDqNYOJzWuC6UAYzA= +github.com/aws/aws-sdk-go-v2/config v1.18.27/go.mod h1:0My+YgmkGxeqjXZb5BYme5pc4drjTnM+x1GJ3zv42Nw= +github.com/aws/aws-sdk-go-v2/credentials v1.13.26 h1:qmU+yhKmOCyujmuPY7tf5MxR/RKyZrOPO3V4DobiTUk= +github.com/aws/aws-sdk-go-v2/credentials v1.13.26/go.mod h1:GoXt2YC8jHUBbA4jr+W3JiemnIbkXOfxSXcisUsZ3os= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 h1:LxK/bitrAr4lnh9LnIS6i7zWbCOdMsfzKFBI6LUCS0I= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4/go.mod h1:E1hLXN/BL2e6YizK1zFlYd8vsfi2GTjbjBazinMmeaM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 h1:A5UqQEmPaCFpedKouS4v+dHCTUo2sKqhoKO9U5kxyWo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 h1:srIVS45eQuewqz6fKKu6ZGXaq6FuFg5NzgQBAM6g8Y4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28/go.mod h1:7VRpKQQedkfIEXb4k52I7swUnZP0wohVajJMRn3vsUw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 h1:LWA+3kDM8ly001vJ1X1waCuLJdtTl48gwkPKWy9sosI= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35/go.mod h1:0Eg1YjxE0Bhn56lx+SHJwCzhW+2JGtizsrx+lCqrfm0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 h1:bkRyG4a929RCnpVSTvLM2j/T4ls015ZhhYApbmYs15s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28/go.mod h1:jj7znCIg05jXlaGBlFMGP8+7UN3VtCkRBG2spnmRQkU= +github.com/aws/aws-sdk-go-v2/service/route53 v1.28.3 h1:nJbE4+tHd8xpM1RB1ZF0/xTJnFd/ATz42ZC35lwXx0w= +github.com/aws/aws-sdk-go-v2/service/route53 v1.28.3/go.mod h1:Cd4MnFoV+6fELBrgWXJ4Y09FrSkn/VjNPkOr1Yr1muU= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.15.0 h1:H7c53dt/1Wsp3fWbu5v5+XVNsThWzmxzYdyYLltWtec= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.15.0/go.mod h1:k75fR3BhOo/0umex9ICEJ+CKTA55qxvFWAlyVHTS6Qg= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 h1:nneMBM2p79PGWBQovYO/6Xnc2ryRMw3InnDJq1FHkSY= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.12/go.mod h1:HuCOxYsF21eKrerARYO6HapNeh9GBNq7fius2AcwodY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 h1:2qTR7IFk7/0IN/adSFhYu9Xthr0zVFTgBrmPldILn80= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12/go.mod h1:E4VrHCPzmVB/KFXtqBGKb3c8zpbNBgKe3fisDNLAW5w= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 h1:XFJ2Z6sNUUcAz9poj+245DMkrHE4h2j5I9/xD50RHfE= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.2/go.mod h1:dp0yLPsLBOi++WTxzCjA/oZqi6NPIhoR+uF7GeMU9eg= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= @@ -78,9 +81,11 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 h1:awE2kiwdJa409MC5i3OH9fJHCr2yE75yHuWWoA5zx8Q= github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5/go.mod h1:1usm1EQvugrIio3ODIAMrDG9NzA86AHIqhZCxJgNdxY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -89,9 +94,11 @@ github.com/cloudflare/cloudflare-go v0.68.0/go.mod h1:b6oSYwhXmZUdaF83Od/uefT092 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -108,6 +115,7 @@ github.com/digitalocean/godo v1.99.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM= github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -115,7 +123,9 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/exoscale/egoscale v0.90.2 h1:oGSJy5Dxbcn5m5F0/DcnU4WXJg+2j3g+UgEu4yyKG9M= github.com/exoscale/egoscale v0.90.2/go.mod h1:NDhQbdGNKwnLVC2YGTB6ds9WIPw+V5ckvEEV8ho7pFE= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -125,6 +135,7 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho= github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -156,6 +167,7 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -188,6 +200,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v35 v35.3.0 h1:fU+WBzuukn0VssbayTT+Zo3/ESKX9JYWjbZTLOTEyho= github.com/google/go-github/v35 v35.3.0/go.mod h1:yWB7uCcVWaUbUP74Aq3whuMySRMatyRmq5U9FTNlbio= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -202,8 +215,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4= +github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.10.0 h1:ebSgKfMxynOdxw8QQuFOKMgomqeLGPqNLQox2bo42zg= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -222,6 +235,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -240,6 +254,7 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= @@ -324,8 +339,9 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= -github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= +github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -339,13 +355,17 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nrdcg/goinwx v0.8.2 h1:RmjiHlEA+lzi3toXyPSaE6hWnBQ0+G+1u7w8C6Fpp4g= github.com/nrdcg/goinwx v0.8.2/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/oracle/oci-go-sdk/v32 v32.0.0 h1:SSbzrQO3WRcPJEZ8+b3SFPYsPtkFM96clqrp03lrwbU= github.com/oracle/oci-go-sdk/v32 v32.0.0/go.mod h1:aZc4jC59IuNP3cr5y1nj555QvwojMX2nMJaBiozuuEs= github.com/ovh/go-ovh v1.1.0 h1:bHXZmw8nTgZin4Nv7JuaLs0KG5x54EQR7migYTd1zrk= @@ -369,6 +389,7 @@ github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0= github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY= @@ -376,6 +397,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -383,6 +405,9 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -390,10 +415,13 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/softlayer/softlayer-go v1.1.2 h1:rUSSGCyaxymvTOsaFjwr+cGxA8muw3xg2LSrIMNcN/c= github.com/softlayer/softlayer-go v1.1.2/go.mod h1:hvAbzGH4LRXA6yXY8BNx99yoqZ7urfDdtl9mvBf0G+g= github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e h1:3OgWYFw7jxCZPcvAg+4R8A50GZ+CCkARF10lxu2qDsQ= github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e/go.mod h1:fKZCUVdirrxrBpwd9wb+lSoVixvpwAu8eHzbQB2tums= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -416,8 +444,8 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= -github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc= -github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= @@ -445,8 +473,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= @@ -477,12 +505,12 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= +golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -515,12 +543,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -528,8 +557,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -550,8 +579,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/api v0.125.0 h1:7xGvEY4fyWbhWMHf3R2/4w7L4fXyfpRGE9g6lp8+DCk= -google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg= +google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -561,7 +590,10 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -599,6 +631,7 @@ gopkg.in/errgo.v1 v1.0.0-20161222125816-442357a80af5/go.mod h1:u0ALmqvLRxLI95fkd gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= +gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= gopkg.in/httprequest.v1 v1.1.1/go.mod h1:/CkavNL+g3qLOrpFHVrEx4NKepeqR4XTZWNj4sGGjz0= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= From 31bf652e3409a15be649ab65d64382aa9df94553 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 28 Jun 2023 08:35:59 -0600 Subject: [PATCH 03/79] ANNOUNCEMENT: Proposal to no longer generate 32-bit binaries (#2464) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1de52b29c..cec66a659 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ See [dnscontrol-action](https://github.com/koenrh/dnscontrol-action) or [gacts/i ## Deprecation warnings (updated 2023-02-18) +- **32-bit binaries will no longer be distributed after September 10, 2023.** There is a proposal to stop shipping 32-bit binaries (packages and containers). If no objections are raised by Sept 10, 2023, new releases will not include them. See https://github.com/StackExchange/dnscontrol/issues/2461 for details. - **Call for new volunteer maintainers for NAMEDOTCOM and SOFTLAYER.** These providers have no maintainer. Maintainers respond to PRs and fix bugs in a timely manner, and try to stay on top of protocol changes. - **ACME/Let's Encrypt support is frozen and will be removed after December 31, 2022.** The `get-certs` command (renews certs via Let's Encrypt) has no maintainer. There are other projects that do a better job. If you don't use this feature, please do not start. If you do use this feature, please plan on migrating to something else. See discussion in [issues/1400](https://github.com/StackExchange/dnscontrol/issues/1400) - **get-zones syntax changes in v3.16** Starting in [v3.16](documentation/v316.md), the command line arguments for `dnscontrol get-zones` changes. For backwards compatibility change `provider` to `-`. See documentation for details. From 449e2a77e5e68db3f65349a47d44a5b77565b481 Mon Sep 17 00:00:00 2001 From: Atma Rutledge <42352142+atma-stackoverflow@users.noreply.github.com> Date: Tue, 1 Aug 2023 07:40:59 -0600 Subject: [PATCH 04/79] FOUND-1643: FEATURE: Adding rate limit to CSCGlobal (#2490) --- build/build.go | 7 +++++++ go.sum | 33 --------------------------------- providers/cscglobal/api.go | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/build/build.go b/build/build.go index 5d5ea56c7..736618f3c 100644 --- a/build/build.go +++ b/build/build.go @@ -24,8 +24,15 @@ func main() { cmd := exec.Command("go", "build", "-o", out, "-ldflags", flags, pkg) os.Setenv("GOOS", goos) os.Setenv("GO111MODULE", "on") + os.Setenv("CGO_ENABLED", "0") cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout + + // For now just build for amd64 everywhere + if os.Getenv("GOARCH") == "" { + os.Setenv("GOARCH", "amd64") + } + err := cmd.Run() if err != nil { log.Fatal(err) diff --git a/go.sum b/go.sum index 815ee4c4c..518054f05 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds= cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= @@ -20,7 +19,6 @@ github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcP github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 h1:AJKJCKcb/psppPl/9CUiQQnTG+Bce0/cIweD5w5Q7aQ= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= github.com/G-Core/gcore-dns-sdk-go v0.2.6 h1:R82ANd7BnhIe2mV/12Ebdx9QYVl2++E4kfDIu97JEOk= @@ -31,7 +29,6 @@ github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 h1:vfVc5pSCq58lj github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36/go.mod h1:MwE/QxFCN65F0hKGWFHUh2U2o1p2tMPNR1zHkX6vEh8= github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 h1:F1j7z+/DKEsYqZNoxC6wvfmaiDneLsQOFQmuq9NADSY= github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2/go.mod h1:QlXr/TrICfQ/ANa76sLeQyhAJyNR9sEcfNuZBkY9jgY= -github.com/alecthomas/kong v0.2.2/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= @@ -81,11 +78,9 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 h1:awE2kiwdJa409MC5i3OH9fJHCr2yE75yHuWWoA5zx8Q= github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5/go.mod h1:1usm1EQvugrIio3ODIAMrDG9NzA86AHIqhZCxJgNdxY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -94,11 +89,9 @@ github.com/cloudflare/cloudflare-go v0.68.0/go.mod h1:b6oSYwhXmZUdaF83Od/uefT092 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -115,7 +108,6 @@ github.com/digitalocean/godo v1.99.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM= github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -123,9 +115,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/exoscale/egoscale v0.90.2 h1:oGSJy5Dxbcn5m5F0/DcnU4WXJg+2j3g+UgEu4yyKG9M= github.com/exoscale/egoscale v0.90.2/go.mod h1:NDhQbdGNKwnLVC2YGTB6ds9WIPw+V5ckvEEV8ho7pFE= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -135,7 +125,6 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho= github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -167,7 +156,6 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -200,7 +188,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v35 v35.3.0 h1:fU+WBzuukn0VssbayTT+Zo3/ESKX9JYWjbZTLOTEyho= github.com/google/go-github/v35 v35.3.0/go.mod h1:yWB7uCcVWaUbUP74Aq3whuMySRMatyRmq5U9FTNlbio= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -235,7 +222,6 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -254,7 +240,6 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= @@ -339,7 +324,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -355,17 +339,13 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nrdcg/goinwx v0.8.2 h1:RmjiHlEA+lzi3toXyPSaE6hWnBQ0+G+1u7w8C6Fpp4g= github.com/nrdcg/goinwx v0.8.2/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/oracle/oci-go-sdk/v32 v32.0.0 h1:SSbzrQO3WRcPJEZ8+b3SFPYsPtkFM96clqrp03lrwbU= github.com/oracle/oci-go-sdk/v32 v32.0.0/go.mod h1:aZc4jC59IuNP3cr5y1nj555QvwojMX2nMJaBiozuuEs= github.com/ovh/go-ovh v1.1.0 h1:bHXZmw8nTgZin4Nv7JuaLs0KG5x54EQR7migYTd1zrk= @@ -389,7 +369,6 @@ github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0= github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY= @@ -397,7 +376,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -405,9 +383,6 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -415,13 +390,10 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= -github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/softlayer/softlayer-go v1.1.2 h1:rUSSGCyaxymvTOsaFjwr+cGxA8muw3xg2LSrIMNcN/c= github.com/softlayer/softlayer-go v1.1.2/go.mod h1:hvAbzGH4LRXA6yXY8BNx99yoqZ7urfDdtl9mvBf0G+g= github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e h1:3OgWYFw7jxCZPcvAg+4R8A50GZ+CCkARF10lxu2qDsQ= github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e/go.mod h1:fKZCUVdirrxrBpwd9wb+lSoVixvpwAu8eHzbQB2tums= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -549,7 +521,6 @@ golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXR golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -590,10 +561,7 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -631,7 +599,6 @@ gopkg.in/errgo.v1 v1.0.0-20161222125816-442357a80af5/go.mod h1:u0ALmqvLRxLI95fkd gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= -gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= gopkg.in/httprequest.v1 v1.1.1/go.mod h1:/CkavNL+g3qLOrpFHVrEx4NKepeqR4XTZWNj4sGGjz0= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/providers/cscglobal/api.go b/providers/cscglobal/api.go index 69a2bc104..df141d753 100644 --- a/providers/cscglobal/api.go +++ b/providers/cscglobal/api.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "log" "net/http" "os" "sort" @@ -642,6 +643,12 @@ func (client *providerClient) geturl(url string) ([]byte, error) { req.Header.Add("Authorization", "Bearer "+client.token) req.Header.Add("Accept", "application/json") + // Default CSCGlobal rate limit is twenty requests per second + var backoff = time.Second + + const maxBackoff = time.Second * 15 + +retry: resp, err := hclient.Do(req) if err != nil { return nil, err @@ -654,6 +661,22 @@ func (client *providerClient) geturl(url string) ([]byte, error) { if resp.StatusCode == 400 { // 400, error message is in the body as plain text + // Apparently CSCGlobal uses status code 400 for rate limit, grump + + if string(bodyString) == "Requests exceeded API Rate limit." { + // a simple exponential back-off with a 3-minute max. + log.Printf("Delaying %v due to ratelimit\n", backoff) + time.Sleep(backoff) + backoff = backoff + (backoff / 2) + if backoff > maxBackoff { + return nil, fmt.Errorf("CSC Global API timeout max backoff (geturl): %s URL: %s%s", + bodyString, + req.Host, req.URL.RequestURI()) + } + + goto retry + } + return nil, fmt.Errorf("CSC Global API error (geturl): %s URL: %s%s", bodyString, req.Host, req.URL.RequestURI()) From 7a3e30b2b5bbdbb02201985901b956886b9a28e6 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Fri, 4 Aug 2023 10:23:39 -0400 Subject: [PATCH 05/79] CHORE: Update goreleaser config for new NFPM format (#2467) Co-authored-by: SignalRichard <20459042+SignalRichard@users.noreply.github.com> --- .goreleaser.yml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index c4a37762d..ce104e6f7 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -47,27 +47,31 @@ universal_binaries: id: build nfpms: - - file_name_template: '{{ .ProjectName }}-{{ .Version }}.{{ .Arch }}' - id: packages_rpm + - id: packages_rpm + file_name_template: >- + {{ .ProjectName }}- + {{ .Version }}. + {{- if eq .Arch "386" }}i386 + {{- else if eq .Arch "amd64" }}x86_64 + {{- else }}{{ .Arch }}{{ end }} homepage: https://docs.dnscontrol.org/ description: "DNSControl: Infrastructure as Code for DNS Zones" maintainer: 'Tom Limoncelli ' license: MIT formats: - rpm - replacements: - 386: i386 - amd64: x86_64 - - file_name_template: '{{ .ProjectName }}-{{ .Version }}.{{ .Arch }}' - id: packages_deb + - id: packages_deb + file_name_template: >- + {{ .ProjectName }}- + {{ .Version }}. + {{- if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} homepage: https://docs.dnscontrol.org/ description: "DNSControl: Infrastructure as Code for DNS Zones" maintainer: 'Tom Limoncelli ' license: MIT formats: - deb - replacements: - 386: i386 dockers: - image_templates: - &amd_image "stackexchange/{{.ProjectName}}:{{ .Version }}-amd64" From acd47d57ad7611aec797f189b89e955d04c36e7d Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Fri, 4 Aug 2023 10:54:17 -0400 Subject: [PATCH 06/79] CORE: Update docs CCI -> GHA (#2496) --- .../release-engineering/circleci_release.png | Bin 82472 -> 0 bytes documentation/release-engineering.md | 92 ++++-------------- 2 files changed, 21 insertions(+), 71 deletions(-) delete mode 100644 documentation/assets/release-engineering/circleci_release.png diff --git a/documentation/assets/release-engineering/circleci_release.png b/documentation/assets/release-engineering/circleci_release.png deleted file mode 100644 index 735fdd1bfdac679915fd0736331201da63c6f08b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82472 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 z 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Þ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 a++#7SbEOY5r(r)pwKvjAQk4?M!T$#(MK(GB diff --git a/documentation/release-engineering.md b/documentation/release-engineering.md index 869911ec2..bdb27d6b8 100644 --- a/documentation/release-engineering.md +++ b/documentation/release-engineering.md @@ -2,15 +2,15 @@ These are the instructions for producing a release. -CircleCI will do most of the work for you. You will need to edit the draft release notes. +GitHub Actions (GHA) will do most of the work for you. You will need to edit the draft release notes and click a button to make the release public. Please change the version number as appropriate. Substitute (for example) -`v3.28.0` any place you see `$VERSION` in this doc. +`v4.2.0` any place you see `$VERSION` in this doc. ## Step 1. Rebuild generated files ```shell -export VERSION=v3.28.0 +export VERSION=v4.2.0 git checkout master git pull go fmt ./... @@ -22,26 +22,21 @@ git commit -a -m "Update generated files for $VERSION" ## Step 2. Tag the commit in master that you want to release ```shell -export VERSION=v3.28.0 +export VERSION=v4.2.0 git tag -m "Release $VERSION" -a $VERSION git push origin --tags ``` -See [Git Docs](https://git-scm.com/book/en/v2/Git-Basics-Tagging) for more examples. - Soon after -CircleCI will start a [build](https://app.circleci.com/pipelines/github/StackExchange/dnscontrol) Workflow and produce all of the artifacts for the release. - -![CircleCI Release Screenshot](assets/release-engineering/circleci_release.png) +GitHub will start an [Action](https://github.com/StackExchange/dnscontrol/actions) Workflow called "draft release" which will build all release binaries and write the draft release notes. ## Step 3. Create the release notes The draft release notes are created for you. In this step you'll edit them. -The CircleCI build uses [GoReleaser](https://goreleaser.com/) which produces the [GitHub Release](https://github.com/StackExchange/dnscontrol/releases) with Release Notes derived from the commit history between now and the last tag. +The GHA workflow uses [GoReleaser](https://goreleaser.com/) which produces the [GitHub Release](https://github.com/StackExchange/dnscontrol/releases) with Release Notes derived from the commit history between now and the last tag. These notes are just a draft and needs considerable editing. -You can also find a copy of the release notes in the CircleCI `release` job Artifacts. -These release notes will be used in multiple places (release notes, email announcements, etc.) +These release notes are used elsewhere, in particular the email step. Release notes style guide: @@ -118,59 +113,38 @@ If you are at Stack Overflow: ## Tip: How to bump the major version If you bump the major version, you need to change all the source -files. The last time this was done (v2 -> v3) these two commands +files. The last time this was done (v3 -> v4) these two commands were used. They're included her for reference. ```shell # Make all the changes: -sed -i.bak -e 's@github.com.StackExchange.dnscontrol.v2@github.com/StackExchange/dnscontrol/v4@g' go.* $(fgrep -lri --include '*.go' github.com/StackExchange/dnscontrol/v2 *) +sed -i.bak -e 's@github.com.StackExchange.dnscontrol.v3@github.com/StackExchange/dnscontrol/v4@g' go.* $(fgrep -lri --include '*.go' github.com/StackExchange/dnscontrol/v3 *) # Delete the backup files: find * -name \*.bak -delete ``` -## Tip: Configuring CircleCI integration tests +## Tip: Configuring GHA integration tests ### Overview -CircleCI is configured to run an integration test for any provider listed in the "provider" list. However the test is skipped if the `*_DOMAIN` variable is not set. For example, the GCLOUD provider integration test is only run if `GCLOUD_DOMAIN` is set. +GHA is configured to run an integration test for any provider listed in the "provider" list. However the test is skipped if the `*_DOMAIN` variable is not set. For example, the Google Cloud provider integration test is only run if `GCLOUD_DOMAIN` is set. * Q: Where is the list of providers to run integration tests on? -* A: In `.circleci/config.yml` look for the "provider" list: - -Example: - -```yaml -workflows: - build: - jobs: - - integration-tests: - matrix: - parameters: - provider: - - GCLOUD -``` +* A: In `.github/workflows/build.yml`: (1) the "PROVIDERS" list, (2) the `integrtests-diff1` section, (3) the `integrtests-diff2` section. * Q: Where are non-secret environment variables stored? -* A: In `.circleci/config.yml` look for: - -```yaml -jobs: - integration-tests: - environment: # environment variables for the build itself - GCLOUD_EMAIL: dnscontrol@dnscontrol-dev.iam.gserviceaccount.com - GCLOUD_PROJECT: dnscontrol-dev -``` +* A: GHA calls them "Variables". Update them here: https://github.com/StackExchange/dnscontrol/settings/variables/actions * Q: Where are SECRET environment variables stored? -* A: In the project: [project settings / environment variables](https://app.circleci.com/settings/project/github/StackExchange/dnscontrol/environment-variables) +* A: GHA calls them "Secrets". Update them here: https://github.com/StackExchange/dnscontrol/settings/secrets/actions ### How do I add a single new integration test? -1. Edit `.circleci/config.yml` -2. Add the name of the provider (ALL CAPS) to the "provider" list. -3. Any non-secret env variables needed? Add them to the "environment" section. -4. Any secrets? Add them to the [project settings / environment variables](https://app.circleci.com/settings/project/github/StackExchange/dnscontrol/environment-variables) -5. Add the `_DOMAIN` environment variable to [project settings / environment variables](https://app.circleci.com/settings/project/github/StackExchange/dnscontrol/environment-variables). It is not secret, but must be set as part of the project. +1. Edit `.github/workflows/build.yml` +2. Add the `FOO_DOMAIN` variable name of the provider to the "PROVIDERS" list. +3. Set the `FOO_DOMAIN` variables in GHA via https://github.com/StackExchange/dnscontrol/settings/variables/actions +4. All other variables should be stored as secrets (for consistency). Add them to both the `integrtests-diff1` section and the `integrtests-diff2` section. +Set them in GHA via https://github.com/StackExchange/dnscontrol/settings/secrets/actions ### How do I add a "bring your own keys" integration test? @@ -180,36 +154,12 @@ Overview: You will fork the repo and add any secrets to your fork. For security If you already have a fork, be sure to use the "sync fork" button on the main page to sync with master. -2. Create a CircleCI account +2. In your fork, set the `${DOMAIN}_DOMAIN` variable in GHA via Settings :: Secrets and variables :: Actions :: Variables. - Go to [circleci.com](https://circleci.com/signup/) and follow the instructions. - -3. Set up a CircleCI project - - On the projects page, find "dnscontrol". Click "Set Up Project". Use the "Fastest" method (use the existing `.circleci/config.yml` file). - - If you get the error message below, go to the "Organization Settings" (left nav). Then "Security" (left nav) and set "Allow Uncertified Orbs" under "Orb Security Settings" to "Yes". - - >"Orb cloudsmith/cloudsmith@1.0.5 not loaded. To use this orb, an organization admin must opt-in to using third party orbs in Organization Security settings." - -4. Add the secret env variables: - - Go to Project Settings (for this project), and "Environment Variables". - - * Add env variable `provider_DOMAIN` where "provider" is the all caps name of the provider. For example add `BIND_DOMAIN` with the value "example.com" +3. In your fork, set any secrets in GHA via Settings :: Secrets and variables :: Actions :: Secrets. 5. Start a build - From the pipelines page, you can trigger a build by setting the branch to "master" then click "trigger". - - Merges to "master" result in the software being built. Merges to any other branch causes integration tests to run. - - Verify that your tests are working properly by making a branch. You'll see on the `Run integration tests for _____ provider` step the results of the test. - - Some notes: - - * Tests that are skipped take about 3 seconds to complete. In other words, if you look at a list of tests, you can tell which ones were skipped by looking at the completion time. - * Free accounts don't have access to `2xlarge` instanace. You'll either need to upgrade your CircleCI account or change `2xlarge` to `large` in `.circleci/config.yml` in your fork. Please be careful to not include that file when you send a PR. See [#1935](https://github.com/StackExchange/dnscontrol/issues/1935) (Anyone have tips on how to make that easier?) ## Tip: How to rebuild flattener From 1ea9f4ced69bb8570ad847390a2acdd530bd3260 Mon Sep 17 00:00:00 2001 From: asn-iac <134323752+asn-iac@users.noreply.github.com> Date: Tue, 8 Aug 2023 07:47:39 -0700 Subject: [PATCH 07/79] GCLOUD: Support "private domains" plus many bugfixes (#2482) Co-authored-by: Tom Limoncelli --- documentation/providers/gcloud.md | 31 ++++ integrationTest/integration_test.go | 1 + providers/gcloud/gcloudProvider.go | 258 ++++++++++++++++++++-------- 3 files changed, 223 insertions(+), 67 deletions(-) diff --git a/documentation/providers/gcloud.md b/documentation/providers/gcloud.md index 4c0900b21..aba14354f 100644 --- a/documentation/providers/gcloud.md +++ b/documentation/providers/gcloud.md @@ -90,6 +90,37 @@ will enable it on your account, responding with a list of names to use in the `n > `name_server_set` only applies on `create-domains` at the moment. Additional work needs to be done to support it during `push` +## Private Domains + +This optional feature allows for the instantiation of Google Cloud DNS zones with the `Visibility` field set to `private` and with specific Google Cloud VPC Networks granted visibility to the zone. + +Example: + +{% code title="dnsconfig.js" %} +```javascript +var REG_NAMECOM = NewRegistrar("name.com"); +var DSP_GCLOUD = NewDnsProvider("gcloud", { + "visibility": "private", + "networks": [ + "https://www.googleapis.com/compute/v1/projects/mydnsproject/global/networks/myvpcnetwork", + "my2ndvpcnetwork" + ] +}); + +D("example.tld", REG_NAMECOM, DnsProvider(DSP_GCLOUD), + A("test", "1.2.3.4") +); +``` +{% endcode %} + +> `visiblity` and `networks` only applies on `create-domains` at the moment. Neither setting is enforced by the provider after a zone is created. Additional work is required to support modifications to `networks` visibility during `push`, however the API will not permit `visibility` to be modified on an existing zone. + +> `networks` may be specified using the network name if the VPC network exists in `project_id` + +> multiple network urls may be specified in `networks` + +> split horizon zones using the `GCLOUD` provider are currently only supported when the providers' credentials target separate `project_id` values + # Debugging credentials You can test your `creds.json` entry with the command: `dnscontrol check-creds foo GCLOUD` where `foo` is the name of key used in `creds.json`. Error messages you might see: diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 84ea11289..8a0ff010f 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -1294,6 +1294,7 @@ func makeTests(t *testing.T) []*TestGroup { //"GANDI_V5", // Their API is so damn slow. We'll add it back as needed. //"HEDNS", // No paging done. No need to test. //"MSDNS", // No paging done. No need to test. + "GCLOUD", "HEXONET", "HOSTINGDE", // Pages. "ROUTE53", // Batches up changes in pages. diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index a7333b47f..e922200dd 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" "log" - "net/http" + "regexp" "strings" "time" @@ -21,6 +21,8 @@ import ( "google.golang.org/api/option" ) +const selfLinkBasePath = "https://www.googleapis.com/compute/v1/projects/" + var features = providers.DocumentationNotes{ providers.CanGetZones: providers.Can(), providers.CanUseAlias: providers.Can(), @@ -36,6 +38,12 @@ var features = providers.DocumentationNotes{ providers.DocOfficiallySupported: providers.Can(), } +var ( + visibilityCheck = regexp.MustCompile("^(public|private)$") + networkURLCheck = regexp.MustCompile("^" + selfLinkBasePath + "[a-z][-a-z0-9]{4,28}[a-z0-9]/global/networks/[a-z]([-a-z0-9]{0,61}[a-z0-9])?$") + networkNameCheck = regexp.MustCompile("^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$") +) + func sPtr(s string) *string { return &s } @@ -56,6 +64,9 @@ type gcloudProvider struct { // diff1 oldRRsMap map[string]map[key]*gdns.ResourceRecordSet zoneNameMap map[string]string + // provider metadata fields + Visibility string `json:"visibility"` + Networks []string `json:"networks"` } type errNoExist struct { @@ -73,28 +84,22 @@ func New(cfg map[string]string, metadata json.RawMessage) (providers.DNSServiceP // fix it if we find that. ctx := context.Background() - var hc *http.Client + var opt option.ClientOption if key, ok := cfg["private_key"]; ok { cfg["private_key"] = strings.Replace(key, "\\n", "\n", -1) raw, err := json.Marshal(cfg) if err != nil { return nil, err } - config, err := gauth.JWTConfigFromJSON(raw, "https://www.googleapis.com/auth/ndev.clouddns.readwrite") + config, err := gauth.JWTConfigFromJSON(raw, gdns.NdevClouddnsReadwriteScope) if err != nil { return nil, err } - hc = config.Client(ctx) + opt = option.WithTokenSource(config.TokenSource(ctx)) } else { - var err error - hc, err = gauth.DefaultClient(ctx, "https://www.googleapis.com/auth/ndev.clouddns.readwrite") - if err != nil { - return nil, fmt.Errorf("no creds.json private_key found and ADC failed with:\n%s", err) - } + opt = option.WithScopes(gdns.NdevClouddnsReadwriteScope) } - // FIXME(tlim): Is it a problem that ctx is included with hc and in - // the call to NewService? Seems redundant. - dcli, err := gdns.NewService(ctx, option.WithHTTPClient(hc)) + dcli, err := gdns.NewService(ctx, opt) if err != nil { return nil, err } @@ -111,17 +116,53 @@ func New(cfg map[string]string, metadata json.RawMessage) (providers.DNSServiceP oldRRsMap: map[string]map[key]*gdns.ResourceRecordSet{}, zoneNameMap: map[string]string{}, } + if len(metadata) != 0 { + err := json.Unmarshal(metadata, g) + if err != nil { + return nil, err + } + if len(g.Visibility) != 0 { + if ok := visibilityCheck.MatchString(g.Visibility); !ok { + return nil, fmt.Errorf("GCLOUD :visibility set but not one of \"public\" or \"private\"") + } + printer.Printf("GCLOUD :visibility %s configured\n", g.Visibility) + } + for i, v := range g.Networks { + if ok := networkURLCheck.MatchString(v); ok { + // the user specified a fully qualified network url + continue + } + if ok := networkNameCheck.MatchString(v); !ok { + return nil, fmt.Errorf("GCLOUD :networks set but %s does not appear to be a valid network name or url", v) + } + // assume target vpc network exists in the same project as the dns zones + g.Networks[i] = fmt.Sprintf("%s%s/global/networks/%s", selfLinkBasePath, g.project, v) + } + } return g, g.loadZoneInfo() } func (g *gcloudProvider) loadZoneInfo() error { + // TODO(asn-iac): In order to fully support split horizon domains within the same GCP project, + // need to parse the zone Visibility field from *ManagedZone, but currently + // gcloudProvider.zones is map[string]*gdns.ManagedZone + // where the map keys are the zone dns names. A given GCP project can have + // multiple zones of the same dns name. if g.zones != nil { return nil } g.zones = map[string]*gdns.ManagedZone{} pageToken := "" for { + retry: resp, err := g.client.ManagedZones.List(g.project).PageToken(pageToken).Do() + var check *googleapi.ServerResponse + if resp != nil { + check = &resp.ServerResponse + } + if retryNeeded(check, err) { + goto retry + } if err != nil { return err } @@ -203,6 +244,20 @@ func (g *gcloudProvider) getZoneSets(domain string) (models.Records, error) { return existingRecords, err } +type msgs struct { + Additions, Deletions []string +} + +type orderedChanges struct { + Change *gdns.Change + Msgs msgs +} + +type correctionValues struct { + Change *gdns.Change + Msgs string +} + // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { @@ -229,30 +284,25 @@ func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis return nil, fmt.Errorf("incdiff error: %w", err) } - changedKeys := map[key]bool{} - var msgs []string + changedKeys := map[key]string{} for _, c := range create { - msgs = append(msgs, fmt.Sprint(c)) - changedKeys[keyForRec(c.Desired)] = true + changedKeys[keyForRec(c.Desired)] = fmt.Sprintln(c) } for _, d := range delete { - msgs = append(msgs, fmt.Sprint(d)) - changedKeys[keyForRec(d.Existing)] = true + changedKeys[keyForRec(d.Existing)] = fmt.Sprintln(d) } for _, m := range modify { - msgs = append(msgs, fmt.Sprint(m)) - changedKeys[keyForRec(m.Existing)] = true + changedKeys[keyForRec(m.Existing)] = fmt.Sprintln(m) } if len(changedKeys) == 0 { return nil, nil } - chg := &gdns.Change{Kind: "dns#change"} - for ck := range changedKeys { - // remove old version (if present) - if old, ok := oldRRs[ck]; ok { - chg.Deletions = append(chg.Deletions, old) - } - // collect records to replace with + chg := orderedChanges{Change: &gdns.Change{}, Msgs: msgs{}} + // create slices of Deletions and Additions + // that can be split into properly ordered batches + // if necessary. Retain the string messages from + // differ in the same order + for ck, msg := range changedKeys { newRRs := &gdns.ResourceRecordSet{ Name: ck.Name, Type: ck.Type, @@ -265,35 +315,92 @@ func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis } } if len(newRRs.Rrdatas) > 0 { - chg.Additions = append(chg.Additions, newRRs) + // if we have Rrdatas because the key from differ + // exists in normalized config, + // check whether the key also has data in oldRRs. + // if so, this is actually a modify operation, insert + // the Addition and Deletion at the beginning of the slices + // to ensure they are executed in the same batch + if old, ok := oldRRs[ck]; ok { + chg.Change.Additions = append([]*gdns.ResourceRecordSet{newRRs}, chg.Change.Additions...) + chg.Change.Deletions = append([]*gdns.ResourceRecordSet{old}, chg.Change.Deletions...) + chg.Msgs.Additions = append([]string{msg}, chg.Msgs.Additions...) + chg.Msgs.Deletions = append([]string{""}, chg.Msgs.Deletions...) + } else { + // otherwise this is a pure Addition + chg.Change.Additions = append(chg.Change.Additions, newRRs) + chg.Msgs.Additions = append(chg.Msgs.Additions, msg) + } + } else { + // there is no Rrdatas from normalized config for this key. + // it must be a Deletion, use the ResourceRecordSet from + // oldRRs + if old, ok := oldRRs[ck]; ok { + chg.Change.Deletions = append(chg.Change.Deletions, old) + chg.Msgs.Deletions = append(chg.Msgs.Deletions, msg) + } } } - // FIXME(tlim): Google will return an error if too many changes are - // specified in a single request. We should split up very large - // batches. This can be reliably reproduced with the 1201 - // integration test. The error you get is: - // googleapi: Error 403: The change would exceed quota for additions per change., quotaExceeded - //log.Printf("PAUSE STT = %+v %v\n", err, resp) - //log.Printf("PAUSE ERR = %+v %v\n", err, resp) - - runChange := func() error { - retry: - resp, err := g.client.Changes.Create(g.project, zoneName, chg).Do() - if retryNeeded(resp, err) { - goto retry + // create a slice of Changes in batches of at most + // 1000 Deletions and 1000 Additions per Change. + // create a slice of strings that aligns with the batch + // to output with each correction/Change + const batchMax = 1000 + setBatchLen := func(len int) int { + if len > batchMax { + return batchMax } - if err != nil { - return fmt.Errorf("runChange error: %w", err) + return len + } + chgSet := []correctionValues{} + for len(chg.Change.Deletions) > 0 { + b := setBatchLen(len(chg.Change.Deletions)) + chgSet = append(chgSet, correctionValues{Change: &gdns.Change{Deletions: chg.Change.Deletions[:b:b], Kind: "dns#change"}, Msgs: "\n" + strings.Join(chg.Msgs.Deletions[:b:b], "")}) + chg.Change.Deletions = chg.Change.Deletions[b:] + chg.Msgs.Deletions = chg.Msgs.Deletions[b:] + } + for i := 0; len(chg.Change.Additions) > 0; i++ { + b := setBatchLen(len(chg.Change.Additions)) + if len(chgSet) == i { + chgSet = append(chgSet, correctionValues{Change: &gdns.Change{Additions: chg.Change.Additions[:b:b], Kind: "dns#change"}, Msgs: "\n" + strings.Join(chg.Msgs.Additions[:b:b], "")}) + } else { + chgSet[i].Change.Additions = chg.Change.Additions[:b:b] + chgSet[i].Msgs += strings.Join(chg.Msgs.Additions[:b:b], "") } - return nil + chg.Change.Additions = chg.Change.Additions[b:] + chg.Msgs.Additions = chg.Msgs.Additions[b:] + } + // create a Correction for each gdns.Change + // that needs to be executed + corrections := []*models.Correction{} + makeCorrection := func(chg *gdns.Change, msgs string) { + runChange := func() error { + retry: + resp, err := g.client.Changes.Create(g.project, zoneName, chg).Do() + var check *googleapi.ServerResponse + if resp != nil { + check = &resp.ServerResponse + } + if retryNeeded(check, err) { + goto retry + } + if err != nil { + return fmt.Errorf("runChange error: %w", err) + } + return nil + } + corrections = append(corrections, + &models.Correction{ + Msg: strings.TrimSuffix(msgs, "\n"), + F: runChange, + }) + } + for _, v := range chgSet { + makeCorrection(v.Change, v.Msgs) } - return []*models.Correction{{ - Msg: strings.Join(msgs, "\n"), - F: runChange, - }}, nil - + return corrections, nil } func nativeToRecord(set *gdns.ResourceRecordSet, rec, origin string) (*models.RecordConfig, error) { @@ -326,7 +433,15 @@ func (g *gcloudProvider) getRecords(domain string) ([]*gdns.ResourceRecordSet, s if pageToken != "" { call = call.PageToken(pageToken) } + retry: resp, err := call.Do() + var check *googleapi.ServerResponse + if resp != nil { + check = &resp.ServerResponse + } + if retryNeeded(check, err) { + goto retry + } if err != nil { return nil, "", err } @@ -354,24 +469,33 @@ func (g *gcloudProvider) EnsureZoneExists(domain string) error { return nil } var mz *gdns.ManagedZone - if g.nameServerSet != nil { - printer.Printf("Adding zone for %s to gcloud account with name_server_set %s\n", domain, *g.nameServerSet) - mz = &gdns.ManagedZone{ - DnsName: domain + ".", - NameServerSet: *g.nameServerSet, - Name: "zone-" + strings.Replace(domain, ".", "-", -1), - Description: "zone added by dnscontrol", - } - } else { - printer.Printf("Adding zone for %s to gcloud account \n", domain) - mz = &gdns.ManagedZone{ - DnsName: domain + ".", - Name: "zone-" + strings.Replace(domain, ".", "-", -1), - Description: "zone added by dnscontrol", - } + printer.Printf("Adding zone for %s to gcloud account ", domain) + mz = &gdns.ManagedZone{ + DnsName: domain + ".", + Name: "zone-" + strings.Replace(domain, ".", "-", -1), + Description: "zone added by dnscontrol", } - g.zones = nil // reset cache - _, err = g.client.ManagedZones.Create(g.project, mz).Do() + if g.nameServerSet != nil { + mz.NameServerSet = *g.nameServerSet + printer.Printf("with name_server_set %s ", *g.nameServerSet) + } + if len(g.Visibility) != 0 { + mz.Visibility = g.Visibility + printer.Printf("with %s visibility ", g.Visibility) + // prevent possible GCP resource name conflicts when split horizon can be properly implemented + mz.Name = strings.Replace(mz.Name, "zone-", "zone-"+g.Visibility+"-", 1) + } + if g.Networks != nil { + mzn := make([]*gdns.ManagedZonePrivateVisibilityConfigNetwork, len(g.Networks)) + printer.Printf("for network(s) ") + for _, v := range g.Networks { + printer.Printf("%s ", v) + mzn = append(mzn, &gdns.ManagedZonePrivateVisibilityConfigNetwork{NetworkUrl: v}) + } + mz.PrivateVisibilityConfig = &gdns.ManagedZonePrivateVisibilityConfig{Networks: mzn} + } + printer.Printf("\n") + g.zones[domain+"."], err = g.client.ManagedZones.Create(g.project, mz).Do() return err } @@ -383,7 +507,7 @@ const maxBackoff = time.Minute * 3 // Maximum backoff delay var backoff = initialBackoff var backoff404 = false // Set if the last call requested a retry of a 404 -func retryNeeded(resp *gdns.Change, err error) bool { +func retryNeeded(resp *googleapi.ServerResponse, err error) bool { if err != nil { return false // Not an error. } From d6a12bc3a0b427440d8d71a9d4d2bc95c85b6076 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 8 Aug 2023 11:41:30 -0400 Subject: [PATCH 08/79] CHORE: Fix release automation (#2498) --- Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1d0ab6bed..24769b974 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,14 @@ # syntax = docker/dockerfile:1.4 -FROM alpine:3.18.0@sha256:02bb6f428431fbc2809c5d1b41eab5a68350194fb508869a33cb1af4444c9b11 as RUN +FROM alpine:3.18.2@sha256:25fad2a32ad1f6f510e528448ae1ec69a28ef81916a004d3629874104f8a7f70 as RUN + # Add runtime dependencies # - tzdata: Go time required external dependency eg: TRANSIP and possibly others # - ca-certificates: Needed for https to work properly -RUN --mount=type=cache,target=/var/cache/apk \ - apk update \ - && apk add tzdata ca-certificates \ - && update-ca-certificates +RUN --mount=type=cache,target=/var/cache/apk apk update +RUN --mount=type=cache,target=/var/cache/apk apk add --no-cache tzdata ca-certificates +RUN --mount=type=cache,target=/var/cache/apk update-ca-certificates COPY dnscontrol /usr/local/bin/ From 5c44e7eef93f22778b2dddf05debd261707a1169 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 8 Aug 2023 11:42:27 -0400 Subject: [PATCH 09/79] CHORE: Update deps (#2500) --- go.mod | 62 ++++++++++++++-------------- go.sum | 128 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 95 insertions(+), 95 deletions(-) diff --git a/go.mod b/go.mod index 56b6bfc3f..82cae1964 100644 --- a/go.mod +++ b/go.mod @@ -11,17 +11,17 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.18.1 - github.com/aws/aws-sdk-go-v2/config v1.18.27 - github.com/aws/aws-sdk-go-v2/credentials v1.13.26 - github.com/aws/aws-sdk-go-v2/service/route53 v1.28.3 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.15.0 + github.com/aws/aws-sdk-go-v2 v1.20.1 + github.com/aws/aws-sdk-go-v2/config v1.18.33 + github.com/aws/aws-sdk-go-v2/credentials v1.13.32 + github.com/aws/aws-sdk-go-v2/service/route53 v1.29.2 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.16.2 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 github.com/cloudflare/cloudflare-go v0.68.0 - github.com/digitalocean/godo v1.99.0 + github.com/digitalocean/godo v1.100.0 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 github.com/exoscale/egoscale v0.90.2 @@ -46,12 +46,12 @@ require ( github.com/robertkrimen/otto v0.2.1 github.com/softlayer/softlayer-go v1.1.2 github.com/stretchr/testify v1.8.4 - github.com/transip/gotransip/v6 v6.20.0 + github.com/transip/gotransip/v6 v6.21.0 github.com/urfave/cli/v2 v2.25.7 github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 - golang.org/x/net v0.11.0 - golang.org/x/oauth2 v0.9.0 - google.golang.org/api v0.128.0 + golang.org/x/net v0.14.0 + golang.org/x/oauth2 v0.11.0 + google.golang.org/api v0.135.0 gopkg.in/ns1/ns1-go.v2 v2.7.4 ) @@ -63,28 +63,28 @@ require ( github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-isatty v0.0.19 github.com/vultr/govultr/v2 v2.17.2 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - golang.org/x/text v0.10.0 + golang.org/x/exp v0.0.0-20230807204917-050eac23e9de + golang.org/x/text v0.12.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/compute v1.19.3 // indirect + cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect - github.com/aws/smithy-go v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 // indirect + github.com/aws/smithy-go v1.14.1 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect @@ -101,8 +101,8 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.4 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect - github.com/googleapis/gax-go/v2 v2.10.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -132,16 +132,16 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.10.0 // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.9.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.7.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect - google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect + google.golang.org/grpc v1.57.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect diff --git a/go.sum b/go.sum index 518054f05..bf1763746 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk= @@ -35,34 +35,34 @@ github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x0 github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.18.1 h1:+tefE750oAb7ZQGzla6bLkOwfcQCEtC5y2RqoqCeqKo= -github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.27 h1:Az9uLwmssTE6OGTpsFqOnaGpLnKDqNYOJzWuC6UAYzA= -github.com/aws/aws-sdk-go-v2/config v1.18.27/go.mod h1:0My+YgmkGxeqjXZb5BYme5pc4drjTnM+x1GJ3zv42Nw= -github.com/aws/aws-sdk-go-v2/credentials v1.13.26 h1:qmU+yhKmOCyujmuPY7tf5MxR/RKyZrOPO3V4DobiTUk= -github.com/aws/aws-sdk-go-v2/credentials v1.13.26/go.mod h1:GoXt2YC8jHUBbA4jr+W3JiemnIbkXOfxSXcisUsZ3os= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 h1:LxK/bitrAr4lnh9LnIS6i7zWbCOdMsfzKFBI6LUCS0I= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4/go.mod h1:E1hLXN/BL2e6YizK1zFlYd8vsfi2GTjbjBazinMmeaM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 h1:A5UqQEmPaCFpedKouS4v+dHCTUo2sKqhoKO9U5kxyWo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 h1:srIVS45eQuewqz6fKKu6ZGXaq6FuFg5NzgQBAM6g8Y4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28/go.mod h1:7VRpKQQedkfIEXb4k52I7swUnZP0wohVajJMRn3vsUw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 h1:LWA+3kDM8ly001vJ1X1waCuLJdtTl48gwkPKWy9sosI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35/go.mod h1:0Eg1YjxE0Bhn56lx+SHJwCzhW+2JGtizsrx+lCqrfm0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 h1:bkRyG4a929RCnpVSTvLM2j/T4ls015ZhhYApbmYs15s= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28/go.mod h1:jj7znCIg05jXlaGBlFMGP8+7UN3VtCkRBG2spnmRQkU= -github.com/aws/aws-sdk-go-v2/service/route53 v1.28.3 h1:nJbE4+tHd8xpM1RB1ZF0/xTJnFd/ATz42ZC35lwXx0w= -github.com/aws/aws-sdk-go-v2/service/route53 v1.28.3/go.mod h1:Cd4MnFoV+6fELBrgWXJ4Y09FrSkn/VjNPkOr1Yr1muU= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.15.0 h1:H7c53dt/1Wsp3fWbu5v5+XVNsThWzmxzYdyYLltWtec= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.15.0/go.mod h1:k75fR3BhOo/0umex9ICEJ+CKTA55qxvFWAlyVHTS6Qg= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 h1:nneMBM2p79PGWBQovYO/6Xnc2ryRMw3InnDJq1FHkSY= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.12/go.mod h1:HuCOxYsF21eKrerARYO6HapNeh9GBNq7fius2AcwodY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 h1:2qTR7IFk7/0IN/adSFhYu9Xthr0zVFTgBrmPldILn80= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12/go.mod h1:E4VrHCPzmVB/KFXtqBGKb3c8zpbNBgKe3fisDNLAW5w= -github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 h1:XFJ2Z6sNUUcAz9poj+245DMkrHE4h2j5I9/xD50RHfE= -github.com/aws/aws-sdk-go-v2/service/sts v1.19.2/go.mod h1:dp0yLPsLBOi++WTxzCjA/oZqi6NPIhoR+uF7GeMU9eg= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= -github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/aws-sdk-go-v2 v1.20.1 h1:rZBf5DWr7YGrnlTK4kgDQGn1ltqOg5orCYb/UhOFZkg= +github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= +github.com/aws/aws-sdk-go-v2/config v1.18.33 h1:JKcw5SFxFW/rpM4mOPjv0VQ11E2kxW13F3exWOy7VZU= +github.com/aws/aws-sdk-go-v2/config v1.18.33/go.mod h1:hXO/l9pgY3K5oZJldamP0pbZHdPqqk+4/maa7DSD3cA= +github.com/aws/aws-sdk-go-v2/credentials v1.13.32 h1:lIH1eKPcCY1ylR4B6PkBGRWMHO3aVenOKJHWiS4/G2w= +github.com/aws/aws-sdk-go-v2/credentials v1.13.32/go.mod h1:lL8U3v/Y79YRG69WlAho0OHIKUXCyFvSXaIvfo81sls= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 h1:DK/9C+UN/X+1+Wm8pqaDksQr2tSLzq+8X1/rI/ZxKEQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8/go.mod h1:ce7BgLQfYr5hQFdy67oX2svto3ufGtm6oBvmsHScI1Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 h1:c8ed/T9T2K5I+h/JzmF5tpI46+OODQ74dzmdo+QnaMg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 h1:hNeAAymUY5gu11WrrmFb3CVIp9Dar9hbo44yzzcQpzA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 h1:fc0ukRAiP1syoSGZYu+DaE+FulSYhTiJ8WpVu5jElU4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39/go.mod h1:WLAW8PT7+JhjZfLSWe7WEJaJu0GNo0cKc2Zyo003RBs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 h1:dGAseBFEYxth10V23b5e2mAS+tX7oVbfYHD6dnDdAsg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= +github.com/aws/aws-sdk-go-v2/service/route53 v1.29.2 h1:6rbDtLVUDUBMCciu5ipjwGpGq1roAFXCVhliS2S+SAE= +github.com/aws/aws-sdk-go-v2/service/route53 v1.29.2/go.mod h1:rsvxuoKwhm9C5yWTqQ2zYtlb/aSkM+StNs/jcy93QQw= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.16.2 h1:+QM69OrWCsp5A6g1oQyC4Rbl9U9F0/xBvugb1N0Ha/U= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.16.2/go.mod h1:sVEjwdvFyw2UY9cvFeeWgVq4y2QEILPcmRF2glyTshM= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 h1:A2RlEMo4SJSwbNoUUgkxTAEMduAy/8wG3eB2b2lP4gY= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.2/go.mod h1:ju+nNXUunfIFamXUIZQiICjnO/TPlOmWcYhZcSy7xaE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 h1:OJELEgyaT2kmaBGZ+myyZbTTLobfe3ox3FSh5eYK9Qs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2/go.mod h1:ubDBBaDFs1GHijSOTi8ljppML15GLG0HxhILtbjNNYQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 h1:ympg1+Lnq33XLhcK/xTG4yZHPs1Oyxu+6DEWbl7qOzA= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.2/go.mod h1:FQ/DQcOfESELfJi5ED+IPPAjI5xC6nxtSolVVB773jM= +github.com/aws/smithy-go v1.14.1 h1:EFKMUmH/iHMqLiwoEDx2rRjRQpI1YCn5jTysoaDujFs= +github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -103,8 +103,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI= github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw= -github.com/digitalocean/godo v1.99.0 h1:gUHO7n9bDaZFWvbzOum4bXE0/09ZuYA9yA8idQHX57E= -github.com/digitalocean/godo v1.99.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib1YhopUc8NA= +github.com/digitalocean/godo v1.100.0 h1:3MuDCh9Hw0MCBwV8GbHBiGrKZXCZ+VJfAY8iNCW+Mks= +github.com/digitalocean/godo v1.100.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib1YhopUc8NA= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= @@ -202,10 +202,10 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4= -github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go/v2 v2.10.0 h1:ebSgKfMxynOdxw8QQuFOKMgomqeLGPqNLQox2bo42zg= -github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= @@ -410,8 +410,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/transip/gotransip/v6 v6.20.0 h1:AuvwyOZ51f2brzMbTqlRy/wmaM3kF7Vx5Wds8xcDflY= -github.com/transip/gotransip/v6 v6.20.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= +github.com/transip/gotransip/v6 v6.21.0 h1:UIcO7uxhSuMbBjte960ypm/mZqqntuHo44Qk08RLzqM= +github.com/transip/gotransip/v6 v6.21.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -445,19 +445,19 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20230807204917-050eac23e9de h1:l5Za6utMv/HsBWWqzt4S8X17j+kt1uVETUX5UFhn2rE= +golang.org/x/exp v0.0.0-20230807204917-050eac23e9de/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -477,12 +477,12 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= -golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -490,8 +490,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -515,8 +515,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -528,8 +528,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -550,8 +550,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg= -google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= +google.golang.org/api v0.135.0 h1:6Vgfj6uPMXcyy66waYWBwmkeNB+9GmUlJDOzkukPQYQ= +google.golang.org/api v0.135.0/go.mod h1:Bp77uRFgwsSKI0BWH573F5Q6wSlznwI2NFayLOp/7mQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -560,10 +560,10 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e h1:S83+ibolgyZ0bqz7KEsUOPErxcv4VzlszxY+31OfB/E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -572,8 +572,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -586,8 +586,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 59cbb73a9f01fdf3beb24394e7c292965ab489f7 Mon Sep 17 00:00:00 2001 From: Gaspard d'Hautefeuille Date: Tue, 8 Aug 2023 17:55:16 +0200 Subject: [PATCH 10/79] OVH: Add DMARC support (#2485) Co-authored-by: Tom Limoncelli --- go.mod | 2 +- go.sum | 4 ++-- providers/ovh/ovhProvider.go | 4 ++-- providers/ovh/protocol.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 82cae1964..9f6006044 100644 --- a/go.mod +++ b/go.mod @@ -137,7 +137,7 @@ require ( golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/tools v0.11.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect google.golang.org/grpc v1.57.0 // indirect diff --git a/go.sum b/go.sum index bf1763746..d2ebf1b8e 100644 --- a/go.sum +++ b/go.sum @@ -544,8 +544,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= 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= diff --git a/providers/ovh/ovhProvider.go b/providers/ovh/ovhProvider.go index a5d74f8ed..ba18f800a 100644 --- a/providers/ovh/ovhProvider.go +++ b/providers/ovh/ovhProvider.go @@ -227,8 +227,8 @@ func nativeToRecord(r *Record, origin string) (*models.RecordConfig, error) { rtype := r.FieldType - // ovh uses a custom type for SPF and DKIM - if rtype == "SPF" || rtype == "DKIM" { + // ovh uses a custom type for SPF, DKIM and DMARC + if rtype == "SPF" || rtype == "DKIM" || rtype == "DMARC" { rtype = "TXT" } diff --git a/providers/ovh/protocol.go b/providers/ovh/protocol.go index 71691bcf9..4d67c72b6 100644 --- a/providers/ovh/protocol.go +++ b/providers/ovh/protocol.go @@ -143,7 +143,7 @@ func (c *ovhProvider) updateRecordFunc(old *Record, rc *models.RecordConfig, fqd if c.isDKIMRecord(rc) { // When DKIM value is longer than 255, the MODIFY fails with "Try to alter read-only properties: fieldType" // Setting FieldType to empty string results in the property not being altered, hence error does not occur. - record.FieldType = "" + record.FieldType = "DKIM" } err := c.client.CallAPI("PUT", fmt.Sprintf("/domain/zone/%s/record/%d", fqdn, old.ID), &record, &Void{}, true) From 1d9646d4ff2f9ca7313cb558674d6c5d2ad54f9b Mon Sep 17 00:00:00 2001 From: asn-iac <134323752+asn-iac@users.noreply.github.com> Date: Tue, 8 Aug 2023 09:02:49 -0700 Subject: [PATCH 11/79] Adjust Error message formatting for preview/push (#2477) Co-authored-by: Tom Limoncelli --- commands/previewPush.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/previewPush.go b/commands/previewPush.go index e40610d24..c1915deac 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -181,7 +181,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { if lister, ok := provider.Driver.(providers.ZoneLister); ok && !push { zones, err := lister.ListZones() if err != nil { - out.Errorf("ERROR: %s", err.Error()) + out.Errorf("ERROR: %s\n", err.Error()) return } aceZoneName, _ := idna.ToASCII(domain.Name) @@ -208,7 +208,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { nsList, err := nameservers.DetermineNameserversForProviders(domain, providersWithExistingZone) if err != nil { - out.Errorf("ERROR: %s", err.Error()) + out.Errorf("ERROR: %s\n", err.Error()) return } domain.Nameservers = nsList From 38b0be5d3fa0e63b3a84e9fc81eaffc4c2e0f2d9 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Tue, 15 Aug 2023 14:45:31 -0700 Subject: [PATCH 12/79] Fix types for SPF_BUILDER (#2487) Co-authored-by: str4d <4993799+str4d@users.noreply.github.com> Co-authored-by: Tom Limoncelli --- build/generate/functionTypes.go | 5 + commands/types/dnscontrol.d.ts | 2128 ++++++++--------- .../{record => domain}/SPF_BUILDER.md | 4 +- 3 files changed, 1071 insertions(+), 1066 deletions(-) rename documentation/functions/{record => domain}/SPF_BUILDER.md (99%) diff --git a/build/generate/functionTypes.go b/build/generate/functionTypes.go index 498fa7584..62b2d68a8 100644 --- a/build/generate/functionTypes.go +++ b/build/generate/functionTypes.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "regexp" + "sort" "strings" "golang.org/x/text/cases" @@ -187,6 +188,10 @@ func generateFunctionTypes() (string, error) { } } + sort.Slice(funcs, func(i, j int) bool { + return funcs[i].Name < funcs[j].Name + }) + content := "" for _, f := range funcs { content += f.String() diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index 5f18095b9..e19bce20c 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -369,6 +369,50 @@ declare function AZURE_ALIAS(name: string, type: "A" | "AAAA" | "CNAME", target: */ declare function CAA(name: string, tag: "issue" | "issuewild" | "iodef", value: string, ...modifiers: RecordModifier[]): DomainModifier; +/** + * DNSControl contains a `CAA_BUILDER` which can be used to simply create + * [`CAA()`](../domain/CAA.md) records for your domains. Instead of creating each [`CAA()`](../domain/CAA.md) record + * individually, you can simply configure your report mail address, the + * authorized certificate authorities and the builder cares about the rest. + * + * ## Example + * + * For example you can use: + * + * ```javascript + * CAA_BUILDER({ + * label: "@", + * iodef: "mailto:test@example.com", + * iodef_critical: true, + * issue: [ + * "letsencrypt.org", + * "comodoca.com", + * ], + * issuewild: "none", + * }) + * ``` + * + * The parameters are: + * + * * `label:` The label of the CAA record. (Optional. Default: `"@"`) + * * `iodef:` Report all violation to configured mail address. + * * `iodef_critical:` This can be `true` or `false`. If enabled and CA does not support this record, then certificate issue will be refused. (Optional. Default: `false`) + * * `issue:` An array of CAs which are allowed to issue certificates. (Use `"none"` to refuse all CAs) + * * `issuewild:` An array of CAs which are allowed to issue wildcard certificates. (Can be simply `"none"` to refuse issuing wildcard certificates for all CAs) + * + * `CAA_BUILDER()` returns multiple records (when configured as example above): + * + * ```javascript + * CAA("@", "iodef", "mailto:test@example.com", CAA_CRITICAL) + * CAA("@", "issue", "letsencrypt.org") + * CAA("@", "issue", "comodoca.com") + * CAA("@", "issuewild", ";") + * ``` + * + * @see https://docs.dnscontrol.org/language-reference/record-modifiers/caa_builder + */ +declare function CAA_BUILDER(opts: { label?: string; iodef: string; iodef_critical?: boolean; issue: string[]; issuewild: string }): RecordModifier; + /** * `CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to * generate a HTTP 301 permanent redirect. @@ -475,6 +519,129 @@ declare function CLOUDNS_WR(name: string, target: string, ...modifiers: RecordMo */ declare function CNAME(name: string, target: string, ...modifiers: RecordModifier[]): DomainModifier; +/** + * `D` adds a new Domain for DNSControl to manage. The first two arguments are required: the domain name (fully qualified `example.com` without a trailing dot), and the + * name of the registrar (as previously declared with [NewRegistrar](NewRegistrar.md)). Any number of additional arguments may be included to add DNS Providers with [DNSProvider](NewDnsProvider.md), + * add records with [A](../domain/A.md), [CNAME](../domain/CNAME.md), and so forth, or add metadata. + * + * Modifier arguments are processed according to type as follows: + * + * - A function argument will be called with the domain object as it's only argument. Most of the [built-in modifier functions](https://docs.dnscontrol.org/language-reference/domain-modifiers) return such functions. + * - An object argument will be merged into the domain's metadata collection. + * - An array argument will have all of it's members evaluated recursively. This allows you to combine multiple common records or modifiers into a variable that can + * be used like a macro in multiple domains. + * + * ```javascript + * // simple domain + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * A("@","1.2.3.4"), + * CNAME("test", "foo.example2.com.") + * ); + * + * // "macro" for records that can be mixed into any zone + * var GOOGLE_APPS_DOMAIN_MX = [ + * MX("@", 1, "aspmx.l.google.com."), + * MX("@", 5, "alt1.aspmx.l.google.com."), + * MX("@", 5, "alt2.aspmx.l.google.com."), + * MX("@", 10, "alt3.aspmx.l.google.com."), + * MX("@", 10, "alt4.aspmx.l.google.com."), + * ] + * + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * A("@","1.2.3.4"), + * CNAME("test", "foo.example2.com."), + * GOOGLE_APPS_DOMAIN_MX + * ); + * ``` + * + * # Split Horizon DNS + * + * DNSControl supports Split Horizon DNS. Simply + * define the domain two or more times, each with + * their own unique parameters. + * + * To differentiate the different domains, specify the domains as + * `domain.tld!tag`, such as `example.com!inside` and + * `example.com!outside`. + * + * ```javascript + * var REG_THIRDPARTY = NewRegistrar("ThirdParty"); + * var DNS_INSIDE = NewDnsProvider("Cloudflare"); + * var DNS_OUTSIDE = NewDnsProvider("bind"); + * + * D("example.com!inside", REG_THIRDPARTY, DnsProvider(DNS_INSIDE), + * A("www", "10.10.10.10") + * ); + * + * D("example.com!outside", REG_THIRDPARTY, DnsProvider(DNS_OUTSIDE), + * A("www", "20.20.20.20") + * ); + * + * D_EXTEND("example.com!inside", + * A("internal", "10.99.99.99") + * ); + * ``` + * + * A domain name without a `!` is assigned a tag that is the empty + * string. For example, `example.com` and `example.com!` are equivalent. + * However, we strongly recommend against using the empty tag, as it + * risks creating confusion. In other words, if you have `domain.tld` + * and `domain.tld!external` you now require humans to remember that + * `domain.tld` is the external one. I mean... the internal one. You + * may have noticed this mistake, but will your coworkers? Will you in + * six months? You get the idea. + * + * DNSControl command line flag `--domains` matches the full name (with the "!"). If you + * define domains `example.com!george` and `example.com!john` then: + * + * * `--domains=example.com` will not match either domain. + * * `--domains='example.com!george'` will match only match the first. + * * `--domains='example.com!george",example.com!john` will match both. + * + * NOTE: The quotes are required if your shell treats `!` as a special + * character, which is probably does. If you see an error that mentions + * `event not found` you probably forgot the quotes. + * + * @see https://docs.dnscontrol.org/language-reference/top-level-functions/d + */ +declare function D(name: string, registrar: string, ...modifiers: DomainModifier[]): void; + +/** + * `DEFAULTS` allows you to declare a set of default arguments to apply to all subsequent domains. Subsequent calls to [`D`](D.md) will have these + * arguments passed as if they were the first modifiers in the argument list. + * + * ## Example + * + * We want to create backup zone files for all domains, but not actually register them. Also create a [`DefaultTTL`](../domain/DefaultTTL.md). + * The domain `example.com` will have the defaults set. + * + * ```javascript + * var COMMON = NewDnsProvider("foo"); + * DEFAULTS( + * DnsProvider(COMMON, 0), + * DefaultTTL("1d") + * ); + * + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * A("@","1.2.3.4") + * ); + * ``` + * + * If you want to clear the defaults, you can do the following. + * The domain `example2.com` will **not** have the defaults set. + * + * ```javascript + * DEFAULTS(); + * + * D("example2.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * A("@","1.2.3.4") + * ); + * ``` + * + * @see https://docs.dnscontrol.org/language-reference/top-level-functions/defaults + */ +declare function DEFAULTS(...modifiers: DomainModifier[]): void; + /** * `DISABLE_IGNORE_SAFETY_CHECK()` disables the safety check. Normally it is an * error to insert records that match an `IGNORE()` pattern. This disables that @@ -500,6 +667,163 @@ declare function CNAME(name: string, target: string, ...modifiers: RecordModifie */ declare const DISABLE_IGNORE_SAFETY_CHECK: DomainModifier; +/** + * DNSControl contains a `DMARC_BUILDER` which can be used to simply create + * DMARC policies for your domains. + * + * ## Example + * + * ### Simple example + * + * ```javascript + * DMARC_BUILDER({ + * policy: "reject", + * ruf: [ + * "mailto:mailauth-reports@example.com", + * ], + * }) + * ``` + * + * This yield the following record: + * + * ```text + * @ IN TXT "v=DMARC1; p=reject; ruf=mailto:mailauth-reports@example.com" + * ``` + * + * ### Advanced example + * + * ```javascript + * DMARC_BUILDER({ + * policy: "reject", + * subdomainPolicy: "quarantine", + * percent: 50, + * alignmentSPF: "r", + * alignmentDKIM: "strict", + * rua: [ + * "mailto:mailauth-reports@example.com", + * "https://dmarc.example.com/submit", + * ], + * ruf: [ + * "mailto:mailauth-reports@example.com", + * ], + * failureOptions: "1", + * reportInterval: "1h", + * }); + * ``` + * + * ```javascript + * DMARC_BUILDER({ + * label: "insecure", + * policy: "none", + * ruf: [ + * "mailto:mailauth-reports@example.com", + * ], + * failureOptions: { + * SPF: false, + * DKIM: true, + * }, + * }); + * ``` + * + * This yields the following records: + * + * ```text + * @ IN TXT "v=DMARC1; p=reject; sp=quarantine; adkim=s; aspf=r; pct=50; rua=mailto:mailauth-reports@example.com,https://dmarc.example.com/submit; ruf=mailto:mailauth-reports@example.com; fo=1; ri=3600" + * insecure IN TXT "v=DMARC1; p=none; ruf=mailto:mailauth-reports@example.com; fo=d" + * ``` + * + * ### Parameters + * + * * `label:` The DNS label for the DMARC record (`_dmarc` prefix is added, default: `"@"`) + * * `version:` The DMARC version to be used (default: `DMARC1`) + * * `policy:` The DMARC policy (`p=`), must be one of `"none"`, `"quarantine"`, `"reject"` + * * `subdomainPolicy:` The DMARC policy for subdomains (`sp=`), must be one of `"none"`, `"quarantine"`, `"reject"` (optional) + * * `alignmentSPF:` `"strict"`/`"s"` or `"relaxed"`/`"r"` alignment for SPF (`aspf=`, default: `"r"`) + * * `alignmentDKIM:` `"strict"`/`"s"` or `"relaxed"`/`"r"` alignment for DKIM (`adkim=`, default: `"r"`) + * * `percent:` Number between `0` and `100`, percentage for which policies are applied (`pct=`, default: `100`) + * * `rua:` Array of aggregate report targets (optional) + * * `ruf:` Array of failure report targets (optional) + * * `failureOptions:` Object or string; Object containing booleans `SPF` and `DKIM`, string is passed raw (`fo=`, default: `"0"`) + * * `failureFormat:` Format in which failure reports are requested (`rf=`, default: `"afrf"`) + * * `reportInterval:` Interval in which reports are requested (`ri=`) + * * `ttl:` Input for `TTL` method (optional) + * + * ### Caveats + * + * * TXT records are automatically split using `AUTOSPLIT`. + * * URIs in the `rua` and `ruf` arrays are passed raw. You must percent-encode all commas and exclamation points in the URI itself. + * + * @see https://docs.dnscontrol.org/language-reference/record-modifiers/dmarc_builder + */ +declare function DMARC_BUILDER(opts: { label?: string; version?: string; policy: 'none' | 'quarantine' | 'reject'; subdomainPolicy?: 'none' | 'quarantine' | 'reject'; alignmentSPF?: 'strict' | 's' | 'relaxed' | 'r'; alignmentDKIM?: 'strict' | 's' | 'relaxed' | 'r'; percent?: number; rua?: string[]; ruf?: string[]; failureOptions?: { SPF: boolean, DKIM: boolean } | string; failureFormat?: string; reportInterval?: Duration; ttl?: Duration }): RecordModifier; + +/** + * `DOMAIN_ELSEWHERE()` is a helper macro that lets you easily indicate that + * a domain's zones are managed elsewhere. That is, it permits you easily delegate + * a domain to a hard-coded list of DNS servers. + * + * `DOMAIN_ELSEWHERE` is useful when you control a domain's registrar but not the + * DNS servers. For example, suppose you own a domain but the DNS servers are run + * by someone else, perhaps a SaaS product you've subscribed to or a DNS server + * that is run by your brother-in-law who doesn't trust you with the API keys that + * would let you maintain the domain using DNSControl. You need an easy way to + * point (delegate) the domain at a specific list of DNS servers. + * + * For example these two statements are equivalent: + * + * ```javascript + * DOMAIN_ELSEWHERE("example.com", REG_MY_PROVIDER, ["ns1.foo.com", "ns2.foo.com"]); + * ``` + * + * ```javascript + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * NO_PURGE, + * NAMESERVER("ns1.foo.com"), + * NAMESERVER("ns2.foo.com") + * ); + * ``` + * + * NOTE: The [`NO_PURGE`](../domain/NO_PURGE.md) is used out of abundance of caution but since no + * `DnsProvider()` statements exist, no updates would be performed. + * + * @see https://docs.dnscontrol.org/language-reference/top-level-functions/domain_elsewhere + */ +declare function DOMAIN_ELSEWHERE(name: string, registrar: string, nameserver_names: string[]): void; + +/** + * `DOMAIN_ELSEWHERE_AUTO()` is similar to `DOMAIN_ELSEWHERE()` but instead of + * a hardcoded list of nameservers, a DnsProvider() is queried. + * + * `DOMAIN_ELSEWHERE_AUTO` is useful when you control a domain's registrar but the + * DNS zones are managed by another system. Luckily you have enough access to that + * other system that you can query it to determine the zone's nameservers. + * + * For example, suppose you own a domain but the DNS servers for it are in Azure. + * Further suppose that something in Azure maintains the zones (automatic or + * human). Azure picks the nameservers for the domains automatically, and that + * list may change occasionally. `DOMAIN_ELSEWHERE_AUTO` allows you to easily + * query Azure to determine the domain's delegations so that you do not need to + * hard-code them in your dnsconfig.js file. + * + * For example these two statements are equivalent: + * + * ```javascript + * DOMAIN_ELSEWHERE_AUTO("example.com", REG_NAMEDOTCOM, DSP_AZURE); + * ``` + * + * ```javascript + * D("example.com", REG_NAMEDOTCOM, + * NO_PURGE, + * DnsProvider(DSP_AZURE) + * ); + * ``` + * + * NOTE: The [`NO_PURGE`](../domain/NO_PURGE.md) is used to prevent DNSControl from changing the records. + * + * @see https://docs.dnscontrol.org/language-reference/top-level-functions/domain_elsewhere_auto + */ +declare function DOMAIN_ELSEWHERE_AUTO(name: string, domain: string, registrar: string, dnsProvider: string): void; + /** * DS adds a DS record to the domain. * @@ -521,6 +845,89 @@ declare const DISABLE_IGNORE_SAFETY_CHECK: DomainModifier; */ declare function DS(name: string, keytag: number, algorithm: number, digesttype: number, digest: string, ...modifiers: RecordModifier[]): DomainModifier; +/** + * `D_EXTEND` adds records (and metadata) to a domain previously defined + * by [`D()`](D.md). It can also be used to add subdomain records (and metadata) + * to a previously defined domain. + * + * The first argument is a domain name. If it exactly matches a + * previously defined domain, `D_EXTEND()` behaves the same as [`D()`](D.md), + * simply adding records as if they had been specified in the original + * [`D()`](D.md). + * + * If the domain name does not match an existing domain, but could be a + * (non-delegated) subdomain of an existing domain, the new records (and + * metadata) are added with the subdomain part appended to all record + * names (labels), and targets (as appropriate). See the examples below. + * + * Matching the domain name to previously-defined domains is done using a + * `longest match` algorithm. If `domain.tld` and `sub.domain.tld` are + * defined as separate domains via separate [`D()`](D.md) statements, then + * `D_EXTEND("sub.sub.domain.tld", ...)` would match `sub.domain.tld`, + * not `domain.tld`. + * + * Some operators only act on an apex domain (e.g. + * [`CF_REDIRECT`](../domain/CF_REDIRECT.md) and [`CF_TEMP_REDIRECT`](../domain/CF_TEMP_REDIRECT.md)). Using them + * in a `D_EXTEND` subdomain may not be what you expect. + * + * ```javascript + * D("domain.tld", REG_MY_PROVIDER, DnsProvider(DNS), + * A("@", "127.0.0.1"), // domain.tld + * A("www", "127.0.0.2"), // www.domain.tld + * CNAME("a", "b") // a.domain.tld -> b.domain.tld + * ); + * D_EXTEND("domain.tld", + * A("aaa", "127.0.0.3"), // aaa.domain.tld + * CNAME("c", "d") // c.domain.tld -> d.domain.tld + * ); + * D_EXTEND("sub.domain.tld", + * A("bbb", "127.0.0.4"), // bbb.sub.domain.tld + * A("ccc", "127.0.0.5"), // ccc.sub.domain.tld + * CNAME("e", "f") // e.sub.domain.tld -> f.sub.domain.tld + * ); + * D_EXTEND("sub.sub.domain.tld", + * A("ddd", "127.0.0.6"), // ddd.sub.sub.domain.tld + * CNAME("g", "h") // g.sub.sub.domain.tld -> h.sub.sub.domain.tld + * ); + * D_EXTEND("sub.domain.tld", + * A("@", "127.0.0.7"), // sub.domain.tld + * CNAME("i", "j") // i.sub.domain.tld -> j.sub.domain.tld + * ); + * ``` + * + * This will end up in the following modifications: (This output assumes the `--full` flag) + * + * ```text + * ******************** Domain: domain.tld + * ----- Getting nameservers from: cloudflare + * ----- DNS Provider: cloudflare...7 corrections + * #1: CREATE A aaa.domain.tld 127.0.0.3 + * #2: CREATE A bbb.sub.domain.tld 127.0.0.4 + * #3: CREATE A ccc.sub.domain.tld 127.0.0.5 + * #4: CREATE A ddd.sub.sub.domain.tld 127.0.0.6 + * #5: CREATE A sub.domain.tld 127.0.0.7 + * #6: CREATE A www.domain.tld 127.0.0.2 + * #7: CREATE A domain.tld 127.0.0.1 + * #8: CREATE CNAME a.domain.tld b.domain.tld. + * #9: CREATE CNAME c.domain.tld d.domain.tld. + * #10: CREATE CNAME e.sub.domain.tld f.sub.domain.tld. + * #11: CREATE CNAME g.sub.sub.domain.tld h.sub.sub.domain.tld. + * #12: CREATE CNAME i.sub.domain.tld j.sub.domain.tld. + * ``` + * + * ProTips: `D_EXTEND()` permits you to create very complex and + * sophisticated configurations, but you shouldn't. Be nice to the next + * person that edits the file, who may not be as expert as yourself. + * Enhance readability by putting any `D_EXTEND()` statements immediately + * after the original [`D()`](D.md), like in above example. Avoid the temptation + * to obscure the addition of records to existing domains with randomly + * placed `D_EXTEND()` statements. Don't build up a domain using loops of + * `D_EXTEND()` statements. You'll be glad you didn't. + * + * @see https://docs.dnscontrol.org/language-reference/top-level-functions/d_extend + */ +declare function D_EXTEND(name: string, ...modifiers: DomainModifier[]): void; + /** * DefaultTTL sets the TTL for all subsequent records following it in a domain that do not explicitly set one with [`TTL`](../record/TTL.md). If neither `DefaultTTL` or `TTL` exist for a record, * the record will inherit the DNSControl global internal default of 300 seconds. See also [`DEFAULTS`](../global/DEFAULTS.md) to override the internal defaults. @@ -983,6 +1390,30 @@ declare function IGNORE_TARGET(pattern: string, rType: string): DomainModifier; */ declare function INCLUDE(domain: string): DomainModifier; +/** + * Converts an IPv4 address from string to an integer. This allows performing mathematical operations with the IP address. + * + * ```javascript + * var addrA = IP("1.2.3.4") + * var addrB = addrA + 1 + * // addrB = 1.2.3.5 + * ``` + * + * NOTE: `IP()` does not accept IPv6 addresses (PRs gladly accepted!). IPv6 addresses are simply strings: + * + * ```javascript + * // IPv4 Var + * var addrA1 = IP("1.2.3.4"); + * var addrA2 = "1.2.3.4"; + * + * // IPv6 Var + * var addrAAAA = "0:0:0:0:0:0:0:0"; + * ``` + * + * @see https://docs.dnscontrol.org/language-reference/top-level-functions/ip + */ +declare function IP(ip: string): number; + /** * The parameter number types are as follows: * @@ -1075,6 +1506,247 @@ declare function INCLUDE(domain: string): DomainModifier; */ declare function LOC(deg1: number, min1: number, sec1: number, deg2: number, min2: number, sec2: number, altitude: number, size: number, horizontal_precision: number, vertical_precision: number): DomainModifier; +/** + * `LOC_BUILDER_DD({})` actually takes an object with the following properties: + * + * - label (optional, defaults to `@`) + * - x (float32) + * - y (float32) + * - alt (float32, optional) + * - ttl (optional) + * + * A helper to build [`LOC`](../domain/LOC.md) records. Supply four parameters instead of 12. + * + * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. + * + * The cartesian coordinates are decimal degrees, like you typically find in e.g. Google Maps. + * + * Examples. + * + * Big Ben: + * `51.50084265331501, -0.12462541415599787` + * + * The White House: + * `38.89775977858357, -77.03655125982903` + * + * ```javascript + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * LOC_BUILDER_DD({ + * label: "big-ben", + * x: 51.50084265331501, + * y: -0.12462541415599787, + * alt: 6, + * }) + * , LOC_BUILDER_DD({ + * label: "white-house", + * x: 38.89775977858357, + * y: -77.03655125982903, + * alt: 19, + * }) + * , LOC_BUILDER_DD({ + * label: "white-house-ttl", + * x: 38.89775977858357, + * y: -77.03655125982903, + * alt: 19, + * ttl: "5m", + * }) + * ); + * + * ``` + * + * Part of the series: + * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters + * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y + * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E + * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E + * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works + * + * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_dd + */ +declare function LOC_BUILDER_DD(opts: { label?: string; x: number; y: number; alt?: number; ttl?: Duration }): RecordModifier; + +/** + * `LOC_BUILDER_DMM({})` actually takes an object with the following properties: + * + * - label (string, optional, defaults to `@`) + * - str (string) + * - alt (float32, optional) + * - ttl (optional) + * + * A helper to build [`LOC`](../domain/LOC.md) records. Supply three parameters instead of 12. + * + * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. + * + * Accepts a string with decimal minutes (DMM) coordinates in the form: 25.24°S 153.15°E + * + * Note that the following are acceptable forms (symbols differ): + * * `25.24°S 153.15°E` + * * `25.24 S 153.15 E` + * * `25.24° S 153.15° E` + * * `25.24S 153.15E` + * + * ```javascript + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * LOC_BUILDER_STR({ + * label: "tasmania", + * str: "42°S 147°E", + * alt: 3, + * }) + * ); + * + * ``` + * + * Part of the series: + * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters + * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y + * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E + * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E + * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works + * + * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_dmm_str + */ +declare function LOC_BUILDER_DMM_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): RecordModifier; + +/** + * `LOC_BUILDER_DMS_STR({})` actually takes an object with the following properties: + * + * - label (string, optional, defaults to `@`) + * - str (string) + * - alt (float32, optional) + * - ttl (optional) + * + * A helper to build [`LOC`](../domain/LOC.md) records. Supply three parameters instead of 12. + * + * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. + * + * Accepts a string with degrees, minutes, and seconds (DMS) coordinates in the form: 41°24'12.2"N 2°10'26.5"E + * + * Note that the following are acceptable forms (symbols differ): + * * `33°51′31″S 151°12′51″E` + * * `33°51'31"S 151°12'51"E` + * * `33d51m31sS 151d12m51sE` + * * `33d51m31s S 151d12m51s E` + * + * ```javascript + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * LOC_BUILDER_DMS_STR({ + * label: "sydney-opera-house", + * str: "33°51′31″S 151°12′51″E", + * alt: 4, + * ttl: "5m", + * }) + * ); + * + * ``` + * + * Part of the series: + * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters + * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y + * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E + * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E + * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works + * + * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_dms_str + */ +declare function LOC_BUILDER_DMS_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): RecordModifier; + +/** + * `LOC_BUILDER_STR({})` actually takes an object with the following: properties. + * + * - label (optional, defaults to `@`) + * - str (string) + * - alt (float32, optional) + * - ttl (optional) + * + * A helper to build [`LOC`](../domain/LOC.md) records. Supply three parameters instead of 12. + * + * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. + * + * Accepts a string and tries all `LOC_BUILDER_DM*_STR({})` methods: + * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E + * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E + * + * ```javascript + * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), + * , LOC_BUILDER_STR({ + * label: "old-faithful", + * str: "44.46046°N 110.82815°W", + * alt: 2240, + * }) + * , LOC_BUILDER_STR({ + * label: "ribblehead-viaduct", + * str: "54.210436°N 2.370231°W", + * alt: 300, + * }) + * , LOC_BUILDER_STR({ + * label: "guinness-brewery", + * str: "53°20′40″N 6°17′20″W", + * alt: 300, + * }) + * ); + * + * ``` + * + * Part of the series: + * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters + * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y + * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E + * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E + * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works + * + * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_str + */ +declare function LOC_BUILDER_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): RecordModifier; + +/** + * DNSControl offers a `M365_BUILDER` which can be used to simply set up Microsoft 365 for a domain in an opinionated way. + * + * It defaults to a setup without support for legacy Skype for Business applications. + * It doesn't set up SPF or DMARC. See [`SPF_BUILDER`](/language-reference/record-modifiers/dmarc_builder) and [`DMARC_BUILDER`](/language-reference/record-modifiers/spf_builder). + * + * ## Example + * + * ### Simple example + * + * ```javascript + * M365_BUILDER({ + * initialDomain: "example.onmicrosoft.com", + * }); + * ``` + * + * This sets up `MX` records, Autodiscover, and DKIM. + * + * ### Advanced example + * + * ```javascript + * M365_BUILDER({ + * label: "test", + * mx: false, + * autodiscover: false, + * dkim: false, + * mdm: true, + * domainGUID: "test-example-com", // Can be automatically derived in this case, if example.com is the context. + * initialDomain: "example.onmicrosoft.com", + * }); + * ``` + * + * This sets up Mobile Device Management only. + * + * ### Parameters + * + * * `label` The label of the Microsoft 365 domain, useful if it is a subdomain (default: `"@"`) + * * `mx` Set an `MX` record? (default: `true`) + * * `autodiscover` Set Autodiscover `CNAME` record? (default: `true`) + * * `dkim` Set DKIM `CNAME` records? (default: `true`) + * * `skypeForBusiness` Set Skype for Business/Microsoft Teams records? (default: `false`) + * * `mdm` Set Mobile Device Management records? (default: `false`) + * * `domainGUID` The GUID of _this_ Microsoft 365 domain (default: ` +
  • + DNS reordering: How DNSControl determines the order of the changes +
  • diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index cecf11e51..050ec85c3 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -169,6 +169,7 @@ * [Debugging with dlv](debugging-with-dlv.md) * [ALIAS Records](alias.md) * [TXT record testing](testing-txt-records.md) +* [DNS records ordering](ordering.md) ## Release diff --git a/documentation/ordering.md b/documentation/ordering.md new file mode 100644 index 000000000..f30829504 --- /dev/null +++ b/documentation/ordering.md @@ -0,0 +1,39 @@ +# Ordering of DNS records + +DNSControl tries to automatically reorder the pending changes based on the dependencies of the records. +For example, if an A record and a CNAME that points to the A record are created at the same time, some providers require the A record to be created before the CNAME. + +Some providers explicitly require the targets of certain records like CNAMEs to exist, and source records to be valid. This makes it not always possible to "just" apply the pending changes in any order. This is why reordering the records based on the dependencies and the type of operation is required. + +## Practical example + +```js +D('example.com', REG_NONE, DnsProvider(DNS_BIND), + CNAME('foo', 'bar') + A('bar', '1.2.3.4'), +); +``` + +`foo` requires `bar` to exist. Thus `bar` needs to exist before `foo`. But when deleting these records, `foo` needs to be deleted before `bar`. + +## Unresolved records + +DNSControl can produce a warning stating it found `unresolved records` this is most likely because of a cycle in the targets of your records. For instance in the code sample below both `foo` and `bar` depend on each other and thus will produce the warning. + +Such updates will be done after all other updates to that domain. + +In this (contrived) example, it is impossible to know which CNAME should be created first. Therefore they will be done in a non-deterministic order after all other updates to that domain: + +```js +D('example.com', REG_NONE, DnsProvider(DNS_BIND), + CNAME('foo', 'bar') + CNAME('bar', 'foo'), +); +``` + + +## Disabling ordering + +The re-ordering feature can be disabled using the `--disableordering` global flag (it goes before `preview` or `push`). While the code has been extensively tested, it is new and you may still find a bug. This flag leaves the updates unordered and may require multiple `push` runs to complete the update. + +If you encounter any issues with the reordering please [open an issue](https://github.com/StackExchange/dnscontrol/issues). diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 2457c758c..66dadb8fe 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -1986,15 +1986,15 @@ func makeTests(t *testing.T) []*TestGroup { testgroup("IGNORE_TARGET function CNAME", tc("Create some records", cname("foo", "test.foo.com."), - cname("keep", "keep.example.com."), + cname("keep", "keeper.example.com."), ), tc("ignoring CNAME=test.foo.com.", ignoreTarget("test.foo.com.", "CNAME"), - cname("keep", "keep.example.com."), + cname("keep", "keeper.example.com."), ).ExpectNoChanges(), tc("ignoring CNAME=test.foo.com. and add", ignoreTarget("test.foo.com.", "CNAME"), - cname("keep", "keep.example.com."), + cname("keep", "keeper.example.com."), a("adding", "1.2.3.4"), cname("another", "www.example.com."), ), diff --git a/models/record.go b/models/record.go index 80b206223..9c958a808 100644 --- a/models/record.go +++ b/models/record.go @@ -455,6 +455,19 @@ func (rc *RecordConfig) ToRR() dns.RR { return rr } +// GetDependencies returns the FQDNs on which this record dependents +func (rc *RecordConfig) GetDependencies() []string { + + switch rc.Type { + case "NS", "SRV", "CNAME", "MX", "ALIAS", "AZURE_ALIAS", "R53_ALIAS": + return []string{ + rc.target, + } + } + + return []string{} +} + // RecordKey represents a resource record in a format used by some systems. type RecordKey struct { NameFQDN string @@ -554,6 +567,16 @@ func (recs Records) GroupedByFQDN() ([]string, map[string]Records) { return order, groups } +// GetAllDependencies concatinates all dependencies of all records +func (recs Records) GetAllDependencies() []string { + var dependencies []string + for _, rec := range recs { + dependencies = append(dependencies, rec.GetDependencies()...) + } + + return dependencies +} + // PostProcessRecords does any post-processing of the downloaded DNS records. // Deprecated. zonerecords.CorrectZoneRecords() calls Downcase directly. func PostProcessRecords(recs []*RecordConfig) { @@ -587,19 +610,21 @@ func Downcase(recs []*RecordConfig) { // CanonicalizeTargets turns Targets into FQDNs func CanonicalizeTargets(recs []*RecordConfig, origin string) { + originFQDN := origin + "." + for _, r := range recs { switch r.Type { // #rtype_variations case "AKAMAICDN", "ANAME", "CNAME", "DS", "MX", "NS", "NAPTR", "PTR", "SRV": // Target is a hostname that might be a shortname. Turn it into a FQDN. - r.target = dnsutil.AddOrigin(r.target, origin) + r.target = dnsutil.AddOrigin(r.target, originFQDN) case "A", "ALIAS", "CAA", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TLSA", "TXT": // Do nothing. case "SOA": if r.target != "DEFAULT_NOT_SET." { - r.target = dnsutil.AddOrigin(r.target, origin) // .target stores the Ns + r.target = dnsutil.AddOrigin(r.target, originFQDN) // .target stores the Ns } if r.SoaMbox != "DEFAULT_NOT_SET." { - r.SoaMbox = dnsutil.AddOrigin(r.SoaMbox, origin) + r.SoaMbox = dnsutil.AddOrigin(r.SoaMbox, originFQDN) } default: // TODO: we'd like to panic here, but custom record types complicate things. diff --git a/pkg/diff2/analyze.go b/pkg/diff2/analyze.go index fd55d32d0..e0ebf8114 100644 --- a/pkg/diff2/analyze.go +++ b/pkg/diff2/analyze.go @@ -32,6 +32,9 @@ func analyzeByRecordSet(cc *CompareConfig) ChangeList { } } } + + instructions = orderByDependencies(instructions) + return instructions } @@ -74,6 +77,8 @@ func analyzeByLabel(cc *CompareConfig) ChangeList { } } + instructions = orderByDependencies(instructions) + return instructions } @@ -89,6 +94,9 @@ func analyzeByRecord(cc *CompareConfig) ChangeList { instructions = append(instructions, cs...) } } + + instructions = orderByDependencies(instructions) + return instructions } diff --git a/pkg/diff2/analyze_test.go b/pkg/diff2/analyze_test.go index 809390448..898735b3e 100644 --- a/pkg/diff2/analyze_test.go +++ b/pkg/diff2/analyze_test.go @@ -18,40 +18,42 @@ func init() { color.NoColor = true } -var testDataAA1234 = makeRec("laba", "A", "1.2.3.4") // [0] +var testDataAA1234 = makeRec("laba", "A", "1.2.3.4") // [ 0] var testDataAA5678 = makeRec("laba", "A", "5.6.7.8") // var testDataAA1234ttl700 = makeRecTTL("laba", "A", "1.2.3.4", 700) // var testDataAA5678ttl700 = makeRecTTL("laba", "A", "5.6.7.8", 700) // -var testDataAMX10a = makeRec("laba", "MX", "10 laba") // [1] -var testDataCCa = makeRec("labc", "CNAME", "laba") // [2] -var testDataEA15 = makeRec("labe", "A", "10.10.10.15") // [3] -var e4 = makeRec("labe", "A", "10.10.10.16") // [4] -var e5 = makeRec("labe", "A", "10.10.10.17") // [5] -var e6 = makeRec("labe", "A", "10.10.10.18") // [6] -var e7 = makeRec("labg", "NS", "10.10.10.15") // [7] -var e8 = makeRec("labg", "NS", "10.10.10.16") // [8] -var e9 = makeRec("labg", "NS", "10.10.10.17") // [9] -var e10 = makeRec("labg", "NS", "10.10.10.18") // [10] -var e11mx = makeRec("labh", "MX", "22 ttt") // [11] -var e11 = makeRec("labh", "CNAME", "labd") // [11] +var testDataAMX10a = makeRec("laba", "MX", "10 laba") // [ 1] +var testDataCCa = makeRec("labc", "CNAME", "laba") // [ 2] +var testDataEA15 = makeRec("labe", "A", "10.10.10.15") // [ 3] +var e4 = makeRec("labe", "A", "10.10.10.16") // [ 4] +var e5 = makeRec("labe", "A", "10.10.10.17") // [ 5] +var e6 = makeRec("labe", "A", "10.10.10.18") // [ 6] +var e7 = makeRec("labg", "NS", "laba") // [ 7] +var e8 = makeRec("labg", "NS", "labb") // [ 8] +var e9 = makeRec("labg", "NS", "labc") // [ 9] +var e10 = makeRec("labg", "NS", "labe") // [10] +var e11mx = makeRec("labh", "MX", "22 ttt") // [11] +var e11 = makeRec("labh", "CNAME", "labd") // [11] var testDataApexMX1aaa = makeRec("", "MX", "1 aaa") -var testDataAA1234clone = makeRec("laba", "A", "1.2.3.4") // [0'] -var testDataAA12345 = makeRec("laba", "A", "1.2.3.5") // [1'] -var testDataAMX20b = makeRec("laba", "MX", "20 labb") // [2'] -var d3 = makeRec("labe", "A", "10.10.10.95") // [3'] -var d4 = makeRec("labe", "A", "10.10.10.96") // [4'] -var d5 = makeRec("labe", "A", "10.10.10.97") // [5'] -var d6 = makeRec("labe", "A", "10.10.10.98") // [6'] -var d7 = makeRec("labf", "TXT", "foo") // [7'] -var d8 = makeRec("labg", "NS", "10.10.10.10") // [8'] -var d9 = makeRec("labg", "NS", "10.10.10.15") // [9'] -var d10 = makeRec("labg", "NS", "10.10.10.16") // [10'] -var d11 = makeRec("labg", "NS", "10.10.10.97") // [11'] -var d12 = makeRec("labh", "A", "1.2.3.4") // [12'] +var testDataAA1234clone = makeRec("laba", "A", "1.2.3.4") // [ 0'] +var testDataAA12345 = makeRec("laba", "A", "1.2.3.5") // [ 1'] +var testDataAMX20b = makeRec("laba", "MX", "20 labb") // [ 2'] +var d3 = makeRec("labe", "A", "10.10.10.95") // [ 3'] +var d4 = makeRec("labe", "A", "10.10.10.96") // [ 4'] +var d5 = makeRec("labe", "A", "10.10.10.97") // [ 5'] +var d6 = makeRec("labe", "A", "10.10.10.98") // [ 6'] +var d7 = makeRec("labf", "TXT", "foo") // [ 7'] +var d8 = makeRec("labg", "NS", "labf") // [ 8'] +var d9 = makeRec("labg", "NS", "laba") // [ 9'] +var d10 = makeRec("labg", "NS", "labe") // [10'] +var d11 = makeRec("labg", "NS", "labb") // [11'] +var d12 = makeRec("labh", "A", "1.2.3.4") // [12'] +var d13 = makeRec("labc", "CNAME", "labe") // [13'] var testDataApexMX22bbb = makeRec("", "MX", "22 bbb") -func compareMsgs(t *testing.T, fnname, testname, testpart string, gotcc ChangeList, wantstring string) { +func compareMsgs(t *testing.T, fnname, testname, testpart string, gotcc ChangeList, wantstring string, wantstringdefault string) { + wantstring = coalesce(wantstring, wantstringdefault) t.Helper() gs := strings.TrimSpace(justMsgString(gotcc)) ws := strings.TrimSpace(wantstring) @@ -80,16 +82,17 @@ func Test_analyzeByRecordSet(t *testing.T) { } origin := "f.com" - existingSample := models.Records{testDataAA1234, testDataAMX10a, testDataCCa, testDataEA15, e4, e5, e6, e7, e8, e9, e10, e11} - desiredSample := models.Records{testDataAA1234clone, testDataAA12345, testDataAMX20b, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12} tests := []struct { name string args args wantMsgs string wantChangeRSet string + wantMsgsRSet string wantChangeLabel string + wantMsgsLabel string wantChangeRec string + wantMsgsRec string wantChangeZone string }{ @@ -113,30 +116,30 @@ func Test_analyzeByRecordSet(t *testing.T) { existing: models.Records{testDataAA1234, testDataAMX10a}, desired: models.Records{testDataAA1234clone, testDataAMX20b}, }, - wantMsgs: "± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)", + wantMsgs: "± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)", wantChangeRSet: ` ChangeList: len=1 00: Change: verb=CHANGE key={laba.f.com MX} - old=[10 laba] - new=[20 labb] - msg=["± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] + old=[10 laba.f.com.] + new=[20 labb.f.com.] + msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] `, wantChangeLabel: ` ChangeList: len=1 00: Change: verb=CHANGE key={laba.f.com } - old=[1.2.3.4 10 laba] - new=[1.2.3.4 20 labb] - msg=["± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] + old=[1.2.3.4 10 laba.f.com.] + new=[1.2.3.4 20 labb.f.com.] + msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] `, wantChangeRec: ` ChangeList: len=1 00: Change: verb=CHANGE key={laba.f.com MX} - old=[10 laba] - new=[20 labb] - msg=["± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] + old=[10 laba.f.com.] + new=[20 labb.f.com.] + msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] `, }, @@ -147,30 +150,30 @@ ChangeList: len=1 existing: models.Records{testDataAA1234, testDataApexMX1aaa}, desired: models.Records{testDataAA1234clone, testDataApexMX22bbb}, }, - wantMsgs: "± MODIFY f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)", + wantMsgs: "± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)", wantChangeRSet: ` ChangeList: len=1 00: Change: verb=CHANGE key={f.com MX} - old=[1 aaa] - new=[22 bbb] - msg=["± MODIFY f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)"] + old=[1 aaa.f.com.] + new=[22 bbb.f.com.] + msg=["± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)"] `, wantChangeLabel: ` ChangeList: len=1 00: Change: verb=CHANGE key={f.com } - old=[1 aaa] - new=[22 bbb] - msg=["± MODIFY f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)"] + old=[1 aaa.f.com.] + new=[22 bbb.f.com.] + msg=["± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)"] `, wantChangeRec: ` ChangeList: len=1 00: Change: verb=CHANGE key={f.com MX} - old=[1 aaa] - new=[22 bbb] - msg=["± MODIFY f.com MX (1 aaa ttl=300) -> (22 bbb ttl=300)"] + old=[1 aaa.f.com.] + new=[22 bbb.f.com.] + msg=["± MODIFY f.com MX (1 aaa.f.com. ttl=300) -> (22 bbb.f.com. ttl=300)"] `, }, @@ -182,41 +185,107 @@ ChangeList: len=1 desired: models.Records{testDataAA1234clone, testDataAA12345, testDataAMX20b}, }, wantMsgs: ` +± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300) + CREATE laba.f.com A 1.2.3.5 ttl=300 -± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300) - `, +`, + wantMsgsLabel: ` ++ CREATE laba.f.com A 1.2.3.5 ttl=300 +± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300) +`, wantChangeRSet: ` ChangeList: len=2 00: Change: verb=CHANGE + key={laba.f.com MX} + old=[10 laba.f.com.] + new=[20 labb.f.com.] + msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] +01: Change: verb=CHANGE key={laba.f.com A} old=[1.2.3.4] new=[1.2.3.4 1.2.3.5] msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"] -01: Change: verb=CHANGE - key={laba.f.com MX} - old=[10 laba] - new=[20 labb] - msg=["± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] - `, +`, wantChangeLabel: ` ChangeList: len=1 00: Change: verb=CHANGE key={laba.f.com } - old=[1.2.3.4 10 laba] - new=[1.2.3.4 1.2.3.5 20 labb] - msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300" "± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] + old=[1.2.3.4 10 laba.f.com.] + new=[1.2.3.4 1.2.3.5 20 labb.f.com.] + msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300" "± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] `, wantChangeRec: ` ChangeList: len=2 -00: Change: verb=CREATE +00: Change: verb=CHANGE + key={laba.f.com MX} + old=[10 laba.f.com.] + new=[20 labb.f.com.] + msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] +01: Change: verb=CREATE key={laba.f.com A} new=[1.2.3.5] msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"] +`, + }, + + { + name: "order forward and backward dependent records", + args: args{ + origin: origin, + existing: models.Records{testDataAA1234, testDataCCa}, + desired: models.Records{d13, d3}, + }, + wantMsgs: ` ++ CREATE labe.f.com A 10.10.10.95 ttl=300 +± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300) +- DELETE laba.f.com A 1.2.3.4 ttl=300 + `, + wantChangeRSet: ` +ChangeList: len=3 +00: Change: verb=CREATE + key={labe.f.com A} + new=[10.10.10.95] + msg=["+ CREATE labe.f.com A 10.10.10.95 ttl=300"] 01: Change: verb=CHANGE - key={laba.f.com MX} - old=[10 laba] - new=[20 labb] - msg=["± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] + key={labc.f.com CNAME} + old=[laba.f.com.] + new=[labe.f.com.] + msg=["± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300)"] +02: Change: verb=DELETE + key={laba.f.com A} + old=[1.2.3.4] + msg=["- DELETE laba.f.com A 1.2.3.4 ttl=300"] + `, + wantChangeLabel: ` +ChangeList: len=3 +00: Change: verb=CREATE + key={labe.f.com } + new=[10.10.10.95] + msg=["+ CREATE labe.f.com A 10.10.10.95 ttl=300"] +01: Change: verb=CHANGE + key={labc.f.com } + old=[laba.f.com.] + new=[labe.f.com.] + msg=["± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300)"] +02: Change: verb=DELETE + key={laba.f.com } + old=[1.2.3.4] + msg=["- DELETE laba.f.com A 1.2.3.4 ttl=300"] +`, + wantChangeRec: ` +ChangeList: len=3 +00: Change: verb=CREATE + key={labe.f.com A} + new=[10.10.10.95] + msg=["+ CREATE labe.f.com A 10.10.10.95 ttl=300"] +01: Change: verb=CHANGE + key={labc.f.com CNAME} + old=[laba.f.com.] + new=[labe.f.com.] + msg=["± MODIFY labc.f.com CNAME (laba.f.com. ttl=300) -> (labe.f.com. ttl=300)"] +02: Change: verb=DELETE + key={laba.f.com A} + old=[1.2.3.4] + msg=["- DELETE laba.f.com A 1.2.3.4 ttl=300"] `, }, @@ -224,154 +293,176 @@ ChangeList: len=2 name: "big", args: args{ origin: origin, - existing: existingSample, - desired: desiredSample, + existing: models.Records{testDataAA1234, testDataAMX10a, testDataCCa, testDataEA15, e4, e5, e6, e7, e8, e9, e10, e11}, + desired: models.Records{testDataAA1234clone, testDataAA12345, testDataAMX20b, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12}, }, wantMsgs: ` ++ CREATE labf.f.com TXT "foo" ttl=300 +± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300) +- DELETE labh.f.com CNAME labd.f.com. ttl=300 ++ CREATE labh.f.com A 1.2.3.4 ttl=300 +- DELETE labc.f.com CNAME laba.f.com. ttl=300 +± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300) +± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300) +± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300) +± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300) +± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300) + CREATE laba.f.com A 1.2.3.5 ttl=300 -± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300) -- DELETE labc.f.com CNAME laba ttl=300 + `, + wantChangeRSet: ` +ChangeList: len=8 +00: Change: verb=CREATE + key={labf.f.com TXT} + new=["foo"] + msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"] +01: Change: verb=CHANGE + key={labg.f.com NS} + old=[laba.f.com. labb.f.com. labc.f.com. labe.f.com.] + new=[laba.f.com. labb.f.com. labe.f.com. labf.f.com.] + msg=["± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)"] +02: Change: verb=DELETE + key={labh.f.com CNAME} + old=[labd.f.com.] + msg=["- DELETE labh.f.com CNAME labd.f.com. ttl=300"] +03: Change: verb=CREATE + key={labh.f.com A} + new=[1.2.3.4] + msg=["+ CREATE labh.f.com A 1.2.3.4 ttl=300"] +04: Change: verb=DELETE + key={labc.f.com CNAME} + old=[laba.f.com.] + msg=["- DELETE labc.f.com CNAME laba.f.com. ttl=300"] +05: Change: verb=CHANGE + key={labe.f.com A} + old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18] + new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98] + msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"] +06: Change: verb=CHANGE + key={laba.f.com MX} + old=[10 laba.f.com.] + new=[20 labb.f.com.] + msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] +07: Change: verb=CHANGE + key={laba.f.com A} + old=[1.2.3.4] + new=[1.2.3.4 1.2.3.5] + msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"] + `, + wantMsgsLabel: ` ++ CREATE labf.f.com TXT "foo" ttl=300 +± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300) +- DELETE labh.f.com CNAME labd.f.com. ttl=300 ++ CREATE labh.f.com A 1.2.3.4 ttl=300 +- DELETE labc.f.com CNAME laba.f.com. ttl=300 +± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300) +± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300) +± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300) +± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300) ++ CREATE laba.f.com A 1.2.3.5 ttl=300 +± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300) + `, + wantChangeLabel: ` +ChangeList: len=6 +00: Change: verb=CREATE + key={labf.f.com } + new=["foo"] + msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"] +01: Change: verb=CHANGE + key={labg.f.com } + old=[laba.f.com. labb.f.com. labc.f.com. labe.f.com.] + new=[laba.f.com. labb.f.com. labe.f.com. labf.f.com.] + msg=["± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)"] +02: Change: verb=CHANGE + key={labh.f.com } + old=[labd.f.com.] + new=[1.2.3.4] + msg=["- DELETE labh.f.com CNAME labd.f.com. ttl=300" "+ CREATE labh.f.com A 1.2.3.4 ttl=300"] +03: Change: verb=DELETE + key={labc.f.com } + old=[laba.f.com.] + msg=["- DELETE labc.f.com CNAME laba.f.com. ttl=300"] +04: Change: verb=CHANGE + key={labe.f.com } + old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18] + new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98] + msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"] +05: Change: verb=CHANGE + key={laba.f.com } + old=[1.2.3.4 10 laba.f.com.] + new=[1.2.3.4 1.2.3.5 20 labb.f.com.] + msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300" "± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] + `, + wantMsgsRec: ` ± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300) ± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300) ± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300) ± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300) + CREATE labf.f.com TXT "foo" ttl=300 -± MODIFY labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300) -± MODIFY labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300) -- DELETE labh.f.com CNAME labd ttl=300 +± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300) +- DELETE labh.f.com CNAME labd.f.com. ttl=300 + CREATE labh.f.com A 1.2.3.4 ttl=300 +- DELETE labc.f.com CNAME laba.f.com. ttl=300 +± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300) ++ CREATE laba.f.com A 1.2.3.5 ttl=300 `, - wantChangeRSet: ` -ChangeList: len=8 + wantChangeRec: ` +ChangeList: len=11 00: Change: verb=CHANGE - key={laba.f.com A} - old=[1.2.3.4] - new=[1.2.3.4 1.2.3.5] - msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"] + key={labe.f.com A} + old=[10.10.10.15] + new=[10.10.10.95] + msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)"] 01: Change: verb=CHANGE - key={laba.f.com MX} - old=[10 laba] - new=[20 labb] - msg=["± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] -02: Change: verb=DELETE - key={labc.f.com CNAME} - old=[laba] - msg=["- DELETE labc.f.com CNAME laba ttl=300"] + key={labe.f.com A} + old=[10.10.10.16] + new=[10.10.10.96] + msg=["± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)"] +02: Change: verb=CHANGE + key={labe.f.com A} + old=[10.10.10.17] + new=[10.10.10.97] + msg=["± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)"] 03: Change: verb=CHANGE key={labe.f.com A} - old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18] - new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98] - msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"] + old=[10.10.10.18] + new=[10.10.10.98] + msg=["± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"] 04: Change: verb=CREATE key={labf.f.com TXT} new=["foo"] msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"] 05: Change: verb=CHANGE key={labg.f.com NS} - old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18] - new=[10.10.10.10 10.10.10.15 10.10.10.16 10.10.10.97] - msg=["± MODIFY labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300)" "± MODIFY labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300)"] + old=[labc.f.com.] + new=[labf.f.com.] + msg=["± MODIFY labg.f.com NS (labc.f.com. ttl=300) -> (labf.f.com. ttl=300)"] 06: Change: verb=DELETE key={labh.f.com CNAME} - old=[labd] - msg=["- DELETE labh.f.com CNAME labd ttl=300"] + old=[labd.f.com.] + msg=["- DELETE labh.f.com CNAME labd.f.com. ttl=300"] 07: Change: verb=CREATE key={labh.f.com A} new=[1.2.3.4] msg=["+ CREATE labh.f.com A 1.2.3.4 ttl=300"] - `, - wantChangeLabel: ` -ChangeList: len=6 -00: Change: verb=CHANGE - key={laba.f.com } - old=[1.2.3.4 10 laba] - new=[1.2.3.4 1.2.3.5 20 labb] - msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300" "± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] -01: Change: verb=DELETE - key={labc.f.com } - old=[laba] - msg=["- DELETE labc.f.com CNAME laba ttl=300"] -02: Change: verb=CHANGE - key={labe.f.com } - old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18] - new=[10.10.10.95 10.10.10.96 10.10.10.97 10.10.10.98] - msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)" "± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)" "± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)" "± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"] -03: Change: verb=CREATE - key={labf.f.com } - new=["foo"] - msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"] -04: Change: verb=CHANGE - key={labg.f.com } - old=[10.10.10.15 10.10.10.16 10.10.10.17 10.10.10.18] - new=[10.10.10.10 10.10.10.15 10.10.10.16 10.10.10.97] - msg=["± MODIFY labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300)" "± MODIFY labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300)"] -05: Change: verb=CHANGE - key={labh.f.com } - old=[labd] - new=[1.2.3.4] - msg=["- DELETE labh.f.com CNAME labd ttl=300" "+ CREATE labh.f.com A 1.2.3.4 ttl=300"] - `, - wantChangeRec: ` -ChangeList: len=12 -00: Change: verb=CREATE +08: Change: verb=DELETE + key={labc.f.com CNAME} + old=[laba.f.com.] + msg=["- DELETE labc.f.com CNAME laba.f.com. ttl=300"] +09: Change: verb=CHANGE + key={laba.f.com MX} + old=[10 laba.f.com.] + new=[20 labb.f.com.] + msg=["± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"] +10: Change: verb=CREATE key={laba.f.com A} new=[1.2.3.5] msg=["+ CREATE laba.f.com A 1.2.3.5 ttl=300"] -01: Change: verb=CHANGE - key={laba.f.com MX} - old=[10 laba] - new=[20 labb] - msg=["± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"] -02: Change: verb=DELETE - key={labc.f.com CNAME} - old=[laba] - msg=["- DELETE labc.f.com CNAME laba ttl=300"] -03: Change: verb=CHANGE - key={labe.f.com A} - old=[10.10.10.15] - new=[10.10.10.95] - msg=["± MODIFY labe.f.com A (10.10.10.15 ttl=300) -> (10.10.10.95 ttl=300)"] -04: Change: verb=CHANGE - key={labe.f.com A} - old=[10.10.10.16] - new=[10.10.10.96] - msg=["± MODIFY labe.f.com A (10.10.10.16 ttl=300) -> (10.10.10.96 ttl=300)"] -05: Change: verb=CHANGE - key={labe.f.com A} - old=[10.10.10.17] - new=[10.10.10.97] - msg=["± MODIFY labe.f.com A (10.10.10.17 ttl=300) -> (10.10.10.97 ttl=300)"] -06: Change: verb=CHANGE - key={labe.f.com A} - old=[10.10.10.18] - new=[10.10.10.98] - msg=["± MODIFY labe.f.com A (10.10.10.18 ttl=300) -> (10.10.10.98 ttl=300)"] -07: Change: verb=CREATE - key={labf.f.com TXT} - new=["foo"] - msg=["+ CREATE labf.f.com TXT \"foo\" ttl=300"] -08: Change: verb=CHANGE - key={labg.f.com NS} - old=[10.10.10.17] - new=[10.10.10.10] - msg=["± MODIFY labg.f.com NS (10.10.10.17 ttl=300) -> (10.10.10.10 ttl=300)"] -09: Change: verb=CHANGE - key={labg.f.com NS} - old=[10.10.10.18] - new=[10.10.10.97] - msg=["± MODIFY labg.f.com NS (10.10.10.18 ttl=300) -> (10.10.10.97 ttl=300)"] -10: Change: verb=DELETE - key={labh.f.com CNAME} - old=[labd] - msg=["- DELETE labh.f.com CNAME labd ttl=300"] -11: Change: verb=CREATE - key={labh.f.com A} - new=[1.2.3.4] - msg=["+ CREATE labh.f.com A 1.2.3.4 ttl=300"] `, }, } for _, tt := range tests { + models.CanonicalizeTargets(tt.args.existing, tt.args.origin) + models.CanonicalizeTargets(tt.args.desired, tt.args.origin) // Each "analyze*()" should return the same msgs, but a different ChangeList. // Sadly the analyze*() functions are destructive to the CompareConfig struct. @@ -379,19 +470,19 @@ ChangeList: len=12 t.Run(tt.name, func(t *testing.T) { cl := analyzeByRecordSet(NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn)) - compareMsgs(t, "analyzeByRecordSet", tt.name, "RSet", cl, tt.wantMsgs) + compareMsgs(t, "analyzeByRecordSet", tt.name, "RSet", cl, tt.wantMsgsRSet, tt.wantMsgs) compareCL(t, "analyzeByRecordSet", tt.name, "RSet", cl, tt.wantChangeRSet) }) t.Run(tt.name, func(t *testing.T) { cl := analyzeByLabel(NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn)) - compareMsgs(t, "analyzeByLabel", tt.name, "Label", cl, tt.wantMsgs) + compareMsgs(t, "analyzeByLabel", tt.name, "Label", cl, tt.wantMsgsLabel, tt.wantMsgs) compareCL(t, "analyzeByLabel", tt.name, "Label", cl, tt.wantChangeLabel) }) t.Run(tt.name, func(t *testing.T) { cl := analyzeByRecord(NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn)) - compareMsgs(t, "analyzeByRecord", tt.name, "Rec", cl, tt.wantMsgs) + compareMsgs(t, "analyzeByRecord", tt.name, "Rec", cl, tt.wantMsgsRec, tt.wantMsgs) compareCL(t, "analyzeByRecord", tt.name, "Rec", cl, tt.wantChangeRec) }) @@ -400,8 +491,17 @@ ChangeList: len=12 } } +func coalesce(a string, b string) string { + if a != "" { + return a + } + return b +} + func mkTargetConfig(x ...*models.RecordConfig) []targetConfig { var tc []targetConfig + + models.CanonicalizeTargets(x, "f.com") for _, r := range x { ct, cf := mkCompareBlobs(r, nil) tc = append(tc, targetConfig{ @@ -469,8 +569,8 @@ func Test_diffTargets(t *testing.T) { want: ChangeList{ Change{Type: CREATE, Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"}, - New: models.Records{testDataAMX10a}, - Msgs: []string{"+ CREATE laba.f.com MX 10 laba ttl=300"}, + New: models.Records{makeRec("laba", "MX", "10 laba.f.com.")}, + Msgs: []string{"+ CREATE laba.f.com MX 10 laba.f.com. ttl=300"}, }, }, }, @@ -484,8 +584,8 @@ func Test_diffTargets(t *testing.T) { want: ChangeList{ Change{Type: DELETE, Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"}, - Old: models.Records{testDataAMX10a}, - Msgs: []string{"- DELETE laba.f.com MX 10 laba ttl=300"}, + Old: models.Records{makeRec("laba", "MX", "10 laba.f.com.")}, + Msgs: []string{"- DELETE laba.f.com MX 10 laba.f.com. ttl=300"}, }, }, }, @@ -501,7 +601,7 @@ func Test_diffTargets(t *testing.T) { Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"}, Old: models.Records{testDataAMX10a}, New: models.Records{testDataAMX20b}, - Msgs: []string{"± MODIFY laba.f.com MX (10 laba ttl=300) -> (20 labb ttl=300)"}, + Msgs: []string{"± MODIFY laba.f.com MX (10 laba.f.com. ttl=300) -> (20 labb.f.com. ttl=300)"}, }, }, }, diff --git a/pkg/diff2/compareconfig_test.go b/pkg/diff2/compareconfig_test.go index 9f576d00e..51a15df15 100644 --- a/pkg/diff2/compareconfig_test.go +++ b/pkg/diff2/compareconfig_test.go @@ -58,8 +58,8 @@ ldata: tdata[2]: "CNAME" e(0, 0) d(1, 1) labelMap: len=1 map[labh.f.com:true] keyMap: len=3 map[{labh.f.com A}:true {labh.f.com CNAME}:true {labh.f.com MX}:true] -existing: ["22 ttt" "1.2.3.4"] -desired: ["labd"] +existing: ["22 ttt.f.com." "1.2.3.4"] +desired: ["labd.f.com."] origin: f.com compFn: `, @@ -81,8 +81,8 @@ ldata: tdata[2]: "MX" e(0, 0) d(1, 1) labelMap: len=1 map[labh.f.com:true] keyMap: len=3 map[{labh.f.com A}:true {labh.f.com CNAME}:true {labh.f.com MX}:true] -existing: ["labd"] -desired: ["1.2.3.4" "22 ttt"] +existing: ["labd.f.com."] +desired: ["1.2.3.4" "22 ttt.f.com."] origin: f.com compFn: `, @@ -104,7 +104,7 @@ ldata: tdata[0]: "CNAME" e(1, 1) d(0, 0) labelMap: len=2 map[laba.f.com:true labc.f.com:true] keyMap: len=2 map[{laba.f.com A}:true {labc.f.com CNAME}:true] -existing: ["1.2.3.4" "laba"] +existing: ["1.2.3.4" "laba.f.com."] desired: ["1.2.3.4"] origin: f.com compFn: @@ -127,8 +127,8 @@ ldata: tdata[0]: "A" e(1, 1) d(1, 1) labelMap: len=2 map[f.com:true laba.f.com:true] keyMap: len=2 map[{f.com MX}:true {laba.f.com A}:true] -existing: ["1.2.3.4" "1 aaa"] -desired: ["1.2.3.4" "22 bbb"] +existing: ["1.2.3.4" "1 aaa.f.com."] +desired: ["1.2.3.4" "22 bbb.f.com."] origin: f.com compFn: `, @@ -153,8 +153,8 @@ ldata: tdata[0]: "A" e(1, 1) d(2, 2) labelMap: len=3 map[laba.f.com:true labc.f.com:true labe.f.com:true] keyMap: len=4 map[{laba.f.com A}:true {laba.f.com MX}:true {labc.f.com CNAME}:true {labe.f.com A}:true] -existing: ["1.2.3.4" "10 laba" "laba" "10.10.10.15"] -desired: ["1.2.3.4" "1.2.3.5" "20 labb" "10.10.10.95" "10.10.10.96"] +existing: ["1.2.3.4" "10 laba.f.com." "laba.f.com." "10.10.10.15"] +desired: ["1.2.3.4" "1.2.3.5" "20 labb.f.com." "10.10.10.95" "10.10.10.96"] origin: f.com compFn: `, @@ -186,8 +186,8 @@ ldata: tdata[1]: "A" e(0, 0) d(1, 1) labelMap: len=6 map[laba.f.com:true labc.f.com:true labe.f.com:true labf.f.com:true labg.f.com:true labh.f.com:true] keyMap: len=8 map[{laba.f.com A}:true {laba.f.com MX}:true {labc.f.com CNAME}:true {labe.f.com A}:true {labf.f.com TXT}:true {labg.f.com NS}:true {labh.f.com A}:true {labh.f.com CNAME}:true] -existing: ["1.2.3.4" "10 laba" "laba" "10.10.10.15" "10.10.10.16" "10.10.10.17" "10.10.10.18" "10.10.10.15" "10.10.10.16" "10.10.10.17" "10.10.10.18" "labd"] -desired: ["1.2.3.4" "1.2.3.5" "20 labb" "10.10.10.95" "10.10.10.96" "10.10.10.97" "10.10.10.98" "\"foo\"" "10.10.10.10" "10.10.10.15" "10.10.10.16" "10.10.10.97" "1.2.3.4"] +existing: ["1.2.3.4" "10 laba.f.com." "laba.f.com." "10.10.10.15" "10.10.10.16" "10.10.10.17" "10.10.10.18" "laba.f.com." "labb.f.com." "labc.f.com." "labe.f.com." "labd.f.com."] +desired: ["1.2.3.4" "1.2.3.5" "20 labb.f.com." "10.10.10.95" "10.10.10.96" "10.10.10.97" "10.10.10.98" "\"foo\"" "labf.f.com." "laba.f.com." "labe.f.com." "labb.f.com." "1.2.3.4"] origin: f.com compFn: `, @@ -196,6 +196,10 @@ compFn: for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + + models.CanonicalizeTargets(tt.args.desired, "f.com") + models.CanonicalizeTargets(tt.args.existing, "f.com") + cc := NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn) got := strings.TrimSpace(cc.String()) tt.want = strings.TrimSpace(tt.want) @@ -229,6 +233,7 @@ func Test_mkCompareBlobs(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + got, got1 := mkCompareBlobs(tt.args.rc, tt.args.f) if got != tt.want { t.Errorf("mkCompareBlobs() got = %q, want %q", got, tt.want) diff --git a/pkg/diff2/diff2.go b/pkg/diff2/diff2.go index d9ee3a195..f8e11404a 100644 --- a/pkg/diff2/diff2.go +++ b/pkg/diff2/diff2.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph" ) // Verb indicates the Change's type (create, delete, etc.) @@ -52,6 +53,31 @@ type Change struct { HintRecordSetLen1 bool } +func (c Change) GetType() dnsgraph.NodeType { + if c.Type == REPORT { + return dnsgraph.Report + } + + return dnsgraph.Change +} + +func (c Change) GetName() string { + return c.Key.NameFQDN +} + +func (c Change) GetDependencies() []dnsgraph.Dependency { + var dependencies []dnsgraph.Dependency + + if c.Type == CHANGE || c.Type == DELETE { + dependencies = append(dependencies, dnsgraph.CreateDependencies(c.Old.GetAllDependencies(), dnsgraph.BackwardDependency)...) + } + if c.Type == CHANGE || c.Type == CREATE { + dependencies = append(dependencies, dnsgraph.CreateDependencies(c.New.GetAllDependencies(), dnsgraph.ForwardDependency)...) + } + + return dependencies +} + /* General instructions: diff --git a/pkg/diff2/flag.go b/pkg/diff2/flag.go index 6576d9271..f46644e75 100644 --- a/pkg/diff2/flag.go +++ b/pkg/diff2/flag.go @@ -2,3 +2,6 @@ package diff2 // EnableDiff2 is true to activate the experimental diff2 algorithm. var EnableDiff2 bool + +// DisableOrdering can be set to true to disable the reordering of the changes +var DisableOrdering bool diff --git a/pkg/diff2/ordering.go b/pkg/diff2/ordering.go new file mode 100644 index 000000000..f5b82f10c --- /dev/null +++ b/pkg/diff2/ordering.go @@ -0,0 +1,28 @@ +package diff2 + +import ( + "log" + + "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph" + "github.com/StackExchange/dnscontrol/v4/pkg/dnssort" +) + +func orderByDependencies(changes ChangeList) ChangeList { + if DisableOrdering { + log.Println("[Info: ordering of the changes has been disabled.]") + return changes + } + + a := dnssort.SortUsingGraph(changes) + + if len(a.UnresolvedRecords) > 0 { + log.Printf("Warning: Found unresolved records %v.\n"+ + "This can indicate a circular dependency, please ensure all targets from given records exist and no circular dependencies exist in the changeset. "+ + "These unresolved records are still added as changes and pushed to the provider, but will cause issues if and when the provider checks the changes.\n"+ + "For more information and how to disable the reordering please consolidate our documentation at https://docs.dnscontrol.org/developer-info/ordering\n", + dnsgraph.GetRecordsNamesForGraphables(a.UnresolvedRecords), + ) + } + + return a.SortedRecords +} diff --git a/pkg/dnsgraph/dependencies.go b/pkg/dnsgraph/dependencies.go new file mode 100644 index 000000000..e2acfc8ea --- /dev/null +++ b/pkg/dnsgraph/dependencies.go @@ -0,0 +1,11 @@ +package dnsgraph + +func CreateDependencies(dependencyFQDNs []string, dependencyType DependencyType) []Dependency { + var dependencies []Dependency + + for _, dependency := range dependencyFQDNs { + dependencies = append(dependencies, Dependency{NameFQDN: dependency, Type: dependencyType}) + } + + return dependencies +} diff --git a/pkg/dnsgraph/dnsgraph.go b/pkg/dnsgraph/dnsgraph.go new file mode 100644 index 000000000..24df8f2a8 --- /dev/null +++ b/pkg/dnsgraph/dnsgraph.go @@ -0,0 +1,143 @@ +package dnsgraph + +import "github.com/StackExchange/dnscontrol/v4/pkg/dnstree" + +type edgeDirection uint8 + +const ( + IncomingEdge edgeDirection = iota + OutgoingEdge +) + +type DNSGraphEdge[T Graphable] struct { + Dependency Dependency + Node *DNSGraphNode[T] + Direction edgeDirection +} + +type DNSGraphEdges[T Graphable] []DNSGraphEdge[T] + +type DNSGraphNode[T Graphable] struct { + Data T + Edges DNSGraphEdges[T] +} + +type dnsGraphNodes[T Graphable] []*DNSGraphNode[T] + +type DNSGraph[T Graphable] struct { + All dnsGraphNodes[T] + Tree *dnstree.DomainTree[dnsGraphNodes[T]] +} + +func CreateGraph[T Graphable](entries []T) *DNSGraph[T] { + graph := &DNSGraph[T]{ + All: dnsGraphNodes[T]{}, + Tree: dnstree.Create[dnsGraphNodes[T]](), + } + + for _, data := range entries { + graph.AddNode(data) + } + + for _, sourceNode := range graph.All { + for _, dependency := range sourceNode.Data.GetDependencies() { + graph.AddEdge(sourceNode, dependency) + } + } + + return graph +} + +func (graph *DNSGraph[T]) RemoveNode(toRemove *DNSGraphNode[T]) { + for _, edge := range toRemove.Edges { + edge.Node.Edges = edge.Node.Edges.RemoveNode(toRemove) + } + + graph.All = graph.All.RemoveNode(toRemove) + + nodes := graph.Tree.Get(toRemove.Data.GetName()) + if nodes != nil { + nodes = nodes.RemoveNode(toRemove) + graph.Tree.Set(toRemove.Data.GetName(), nodes) + } +} + +func (graph *DNSGraph[T]) AddNode(data T) { + nodes := graph.Tree.Get(data.GetName()) + node := &DNSGraphNode[T]{ + Data: data, + Edges: DNSGraphEdges[T]{}, + } + if nodes == nil { + nodes = dnsGraphNodes[T]{} + } + nodes = append(nodes, node) + + graph.All = append(graph.All, node) + graph.Tree.Set(data.GetName(), nodes) +} + +func (graph *DNSGraph[T]) AddEdge(sourceNode *DNSGraphNode[T], dependency Dependency) { + destinationNodes := graph.Tree.Get(dependency.NameFQDN) + + if destinationNodes == nil { + return + } + + for _, destinationNode := range destinationNodes { + if sourceNode == destinationNode { + continue + } + + if sourceNode.Edges.Contains(destinationNode, OutgoingEdge) { + continue + } + + sourceNode.Edges = append(sourceNode.Edges, DNSGraphEdge[T]{ + Dependency: dependency, + Node: destinationNode, + Direction: OutgoingEdge, + }) + + destinationNode.Edges = append(destinationNode.Edges, DNSGraphEdge[T]{ + Dependency: dependency, + Node: sourceNode, + Direction: IncomingEdge, + }) + } +} + +func (nodes dnsGraphNodes[T]) RemoveNode(toRemove *DNSGraphNode[T]) dnsGraphNodes[T] { + var newNodes dnsGraphNodes[T] + + for _, node := range nodes { + if node != toRemove { + newNodes = append(newNodes, node) + } + } + + return newNodes +} + +func (edges DNSGraphEdges[T]) RemoveNode(toRemove *DNSGraphNode[T]) DNSGraphEdges[T] { + var newEdges DNSGraphEdges[T] + + for _, edge := range edges { + if edge.Node != toRemove { + newEdges = append(newEdges, edge) + } + } + + return newEdges +} + +func (edges DNSGraphEdges[T]) Contains(toFind *DNSGraphNode[T], direction edgeDirection) bool { + + for _, edge := range edges { + if edge.Node == toFind && edge.Direction == direction { + return true + } + } + + return false +} diff --git a/pkg/dnsgraph/dnsgraph_test.go b/pkg/dnsgraph/dnsgraph_test.go new file mode 100644 index 000000000..719f92a9e --- /dev/null +++ b/pkg/dnsgraph/dnsgraph_test.go @@ -0,0 +1,68 @@ +package dnsgraph_test + +import ( + "testing" + + "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph" + "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph/testutils" + "github.com/stretchr/testify/assert" +) + +func Test_CreateGraph(t *testing.T) { + changes := []testutils.StubRecord{ + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{}}, + {NameFQDN: "mail.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}, {Type: dnsgraph.ForwardDependency, NameFQDN: "someserver.example.com"}}}, + {NameFQDN: "*.hq.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}}}, + {NameFQDN: "someserver.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "a.hq.example.com"}, {Type: dnsgraph.ForwardDependency, NameFQDN: "b.hq.example.com"}}}, + } + + graph := dnsgraph.CreateGraph(testutils.StubRecordsAsGraphable(changes)) + + nodes := graph.Tree.Get("example.com") + assert.Len(t, nodes, 1) + assert.Len(t, nodes[0].Edges, 2) + assert.Equal(t, "mail.example.com", nodes[0].Edges[0].Node.Data.GetName()) + assert.Equal(t, dnsgraph.IncomingEdge, nodes[0].Edges[0].Direction) + assert.Equal(t, "*.hq.example.com", nodes[0].Edges[1].Node.Data.GetName()) + + nodes = graph.Tree.Get("someserver.example.com") + assert.Len(t, nodes, 1) + // *.hq.example.com is added once + assert.Len(t, nodes[0].Edges, 2) + assert.Equal(t, "mail.example.com", nodes[0].Edges[0].Node.Data.GetName()) + assert.Equal(t, dnsgraph.IncomingEdge, nodes[0].Edges[0].Direction) + assert.Equal(t, "*.hq.example.com", nodes[0].Edges[1].Node.Data.GetName()) + assert.Equal(t, dnsgraph.OutgoingEdge, nodes[0].Edges[1].Direction) + + nodes = graph.Tree.Get("a.hq.example.com") + assert.Len(t, nodes, 1) + // someserver.example.com is added once + assert.Len(t, nodes[0].Edges, 2) + assert.Equal(t, "example.com", nodes[0].Edges[0].Node.Data.GetName()) + assert.Equal(t, dnsgraph.OutgoingEdge, nodes[0].Edges[0].Direction) + assert.Equal(t, "someserver.example.com", nodes[0].Edges[1].Node.Data.GetName()) + assert.Equal(t, dnsgraph.IncomingEdge, nodes[0].Edges[1].Direction) +} + +func Test_RemoveNode(t *testing.T) { + changes := []testutils.StubRecord{ + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{}}, + {NameFQDN: "mail.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}, {Type: dnsgraph.ForwardDependency, NameFQDN: "someserver.example.com"}}}, + {NameFQDN: "*.hq.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}}}, + {NameFQDN: "someserver.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "a.hq.example.com"}, {Type: dnsgraph.ForwardDependency, NameFQDN: "b.hq.example.com"}}}, + } + + graph := dnsgraph.CreateGraph(testutils.StubRecordsAsGraphable(changes)) + + graph.RemoveNode(graph.Tree.Get("example.com")[0]) + + // example.com change has been removed + nodes := graph.Tree.Get("example.com") + assert.Len(t, nodes, 0) + + nodes = graph.Tree.Get("a.hq.example.com") + assert.Len(t, nodes, 1) + + assert.Len(t, nodes[0].Edges, 1) + assert.Equal(t, "someserver.example.com", nodes[0].Edges[0].Node.Data.GetName()) +} diff --git a/pkg/dnsgraph/graphable.go b/pkg/dnsgraph/graphable.go new file mode 100644 index 000000000..13dd2fb53 --- /dev/null +++ b/pkg/dnsgraph/graphable.go @@ -0,0 +1,36 @@ +package dnsgraph + +type NodeType uint8 + +const ( + Change NodeType = iota + Report +) + +type DependencyType uint8 + +const ( + ForwardDependency DependencyType = iota + BackwardDependency +) + +type Dependency struct { + NameFQDN string + Type DependencyType +} + +type Graphable interface { + GetType() NodeType + GetName() string + GetDependencies() []Dependency +} + +func GetRecordsNamesForGraphables[T Graphable](graphables []T) []string { + var names []string + + for _, graphable := range graphables { + names = append(names, graphable.GetName()) + } + + return names +} diff --git a/pkg/dnsgraph/testutils/stubrecords.go b/pkg/dnsgraph/testutils/stubrecords.go new file mode 100644 index 000000000..e4627ffec --- /dev/null +++ b/pkg/dnsgraph/testutils/stubrecords.go @@ -0,0 +1,31 @@ +package testutils + +import "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph" + +type StubRecord struct { + NameFQDN string + Dependencies []dnsgraph.Dependency + Type dnsgraph.NodeType +} + +func (record StubRecord) GetType() dnsgraph.NodeType { + return record.Type +} + +func (record StubRecord) GetName() string { + return record.NameFQDN +} + +func (record StubRecord) GetDependencies() []dnsgraph.Dependency { + return record.Dependencies +} + +func StubRecordsAsGraphable(records []StubRecord) []dnsgraph.Graphable { + sortableRecords := make([]dnsgraph.Graphable, len(records)) + + for iX := range records { + sortableRecords[iX] = records[iX] + } + + return sortableRecords +} diff --git a/pkg/dnssort/graphsort.go b/pkg/dnssort/graphsort.go new file mode 100644 index 000000000..b9476e44c --- /dev/null +++ b/pkg/dnssort/graphsort.go @@ -0,0 +1,121 @@ +package dnssort + +import "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph" + +// SortUsingGraph sorts changes based on their dependencies using a directed graph. +// Most changes have dependencies on other changes. +// Either they are depend on already (a backwards dependency) or their new state depend on another record (a forwards dependency) which can be in our change set or an existing record. +// A rough sketch of our sorting algorithm is as follows +// +// while graph has nodes: +// +// foreach node in graph: +// +// if node has no dependencies: +// add node to sortedNodes +// remove node from graph +// +// return sortedNodes +// +// The code below also accounts for the existence of cycles by tracking if any nodes were added to the sorted set in the last round. +func SortUsingGraph[T dnsgraph.Graphable](records []T) SortResult[T] { + sortState := createDirectedSortState(records) + + for sortState.hasWork() { + + for _, node := range sortState.graph.All { + sortState.hasResolvedLastRound = false + + if hasUnmetDependencies(node) { + continue + } + + sortState.hasResolvedLastRound = true + sortState.addSortedRecord(node.Data) + sortState.graph.RemoveNode(node) + } + + if sortState.hasStalled() { + break + } + } + + sortState.finalize() + + return SortResult[T]{ + SortedRecords: sortState.sortedRecords, + UnresolvedRecords: sortState.unresolvedRecords, + } +} + +type directedSortState[T dnsgraph.Graphable] struct { + graph *dnsgraph.DNSGraph[T] + sortedRecords []T + unresolvedRecords []T + hasResolvedLastRound bool +} + +func createDirectedSortState[T dnsgraph.Graphable](records []T) directedSortState[T] { + changes, reportChanges := splitRecordsByType(records) + + graph := dnsgraph.CreateGraph(changes) + + return directedSortState[T]{ + graph: graph, + unresolvedRecords: []T{}, + sortedRecords: reportChanges, + hasResolvedLastRound: false, + } +} + +func splitRecordsByType[T dnsgraph.Graphable](records []T) ([]T, []T) { + var changes []T + var reports []T + + for _, record := range records { + switch record.GetType() { + case dnsgraph.Report: + reports = append(reports, record) + case dnsgraph.Change: + changes = append(changes, record) + } + } + + return changes, reports +} + +func (sortState *directedSortState[T]) hasWork() bool { + return len(sortState.graph.All) > 0 +} + +func (sortState *directedSortState[T]) hasStalled() bool { + return !sortState.hasResolvedLastRound +} + +func (sortState *directedSortState[T]) addSortedRecord(node T) { + sortState.sortedRecords = append(sortState.sortedRecords, node) +} + +func (sortState *directedSortState[T]) finalize() { + // Add all of the changes remaining in the graph as unresolved and add them at the end of the sorted result to at least include everything + if len(sortState.graph.All) > 0 { + for _, unresolved := range sortState.graph.All { + sortState.addSortedRecord(unresolved.Data) + sortState.unresolvedRecords = append(sortState.unresolvedRecords, unresolved.Data) + } + } +} + +func hasUnmetDependencies[T dnsgraph.Graphable](node *dnsgraph.DNSGraphNode[T]) bool { + for _, edge := range node.Edges { + if edge.Dependency.Type == dnsgraph.BackwardDependency && edge.Direction == dnsgraph.IncomingEdge { + return true + } + + if edge.Dependency.Type == dnsgraph.ForwardDependency && edge.Direction == dnsgraph.OutgoingEdge { + return true + } + } + + return false +} diff --git a/pkg/dnssort/graphsort_test.go b/pkg/dnssort/graphsort_test.go new file mode 100644 index 000000000..2736a9fc5 --- /dev/null +++ b/pkg/dnssort/graphsort_test.go @@ -0,0 +1,191 @@ +package dnssort_test + +import ( + "testing" + + "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph" + "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph/testutils" + "github.com/StackExchange/dnscontrol/v4/pkg/dnssort" +) + +func Test_graphsort(t *testing.T) { + + t.Run("Direct dependency", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "www.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}}}, + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{}}, + }, + []string{ + "example.com", + "www.example.com", + }, + []string{}, + ), + ) + + t.Run("Already in correct order", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{}}, + {NameFQDN: "www.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}}}, + }, + []string{ + "example.com", + "www.example.com", + }, + []string{}, + ), + ) + + t.Run("Use wildcards", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "www.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "a.test.example.com"}}}, + {NameFQDN: "*.test.example.com", Dependencies: []dnsgraph.Dependency{}}, + }, + []string{ + "*.test.example.com", + "www.example.com", + }, + []string{}, + ), + ) + + t.Run("Cyclic dependency added on the end", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "a.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "b.example.com"}}}, + {NameFQDN: "b.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "a.example.com"}}}, + {NameFQDN: "www.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}}}, + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{}}, + }, + []string{ + "example.com", + "www.example.com", + "a.example.com", + "b.example.com", + }, + []string{ + "a.example.com", + "b.example.com", + }, + ), + ) + + t.Run("Dependency on the same named record resolves in correct order", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "a.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "a.example.com"}}}, + {NameFQDN: "www.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}}}, + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{{}}}, + {NameFQDN: "a.example.com", Dependencies: []dnsgraph.Dependency{}}, + }, + []string{ + "example.com", + "a.example.com", + "a.example.com", + "www.example.com", + }, + []string{}, + ), + ) + + t.Run("Ignores external dependency", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "mail.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "mail.external.tld"}}}, + }, + []string{ + "mail.example.com", + }, + []string{}, + ), + ) + + t.Run("Deletions in correct order", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "mail.example.com", Dependencies: []dnsgraph.Dependency{}}, + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{{NameFQDN: "mail.example.com", Type: dnsgraph.BackwardDependency}}}, + }, + []string{ + "example.com", + "mail.example.com", + }, + []string{}, + ), + ) + + t.Run("A Change with dependency on old and new state", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "bar2.example.com", Dependencies: []dnsgraph.Dependency{{}}}, + {NameFQDN: "foo.example.com", Dependencies: []dnsgraph.Dependency{{NameFQDN: "bar2.example.com", Type: dnsgraph.BackwardDependency}, {NameFQDN: "new2.example.com", Type: dnsgraph.ForwardDependency}}}, + {NameFQDN: "new2.example.com", Dependencies: []dnsgraph.Dependency{{}}}, + }, + []string{ + "new2.example.com", + "foo.example.com", + "bar2.example.com", + }, + []string{}, + ), + ) + + t.Run("Reports first and ignore dependencies", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "example.com", Dependencies: []dnsgraph.Dependency{}}, + {NameFQDN: "test.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "example.com"}}, Type: dnsgraph.Report}, + }, + []string{ + "test.example.com", + "example.com", + }, + []string{}, + ), + ) + + t.Run("Reports are not resolvable as dependencies", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "test2.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "test.example.com"}}}, + {NameFQDN: "test.example.com", Dependencies: []dnsgraph.Dependency{}, Type: dnsgraph.Report}, + }, + []string{ + "test.example.com", + "test2.example.com", + }, + []string{}, + ), + ) +} + +func executeGraphSort(inputOrder []testutils.StubRecord, expectedOutputOrder []string, expectedUnresolved []string) func(*testing.T) { + return func(t *testing.T) { + inputSortableRecords := testutils.StubRecordsAsGraphable(inputOrder) + t.Helper() + result := dnssort.SortUsingGraph(inputSortableRecords) + + if len(expectedOutputOrder) != len(result.SortedRecords) { + t.Errorf("Missing records after sort. Expected order: %v. Got order: %v\n", expectedOutputOrder, dnsgraph.GetRecordsNamesForGraphables(result.SortedRecords)) + } else { + for iX := range expectedOutputOrder { + if result.SortedRecords[iX].GetName() != expectedOutputOrder[iX] { + t.Errorf("Invalid order on index %d after sort. Expected order: %v. Got order: %v\n", iX, expectedOutputOrder, dnsgraph.GetRecordsNamesForGraphables(result.SortedRecords)) + } + } + } + + if len(expectedUnresolved) != len(result.UnresolvedRecords) { + t.Errorf("Missing unresolved records. Expected unresolved: %v. Got: %v\n", expectedUnresolved, dnsgraph.GetRecordsNamesForGraphables(result.UnresolvedRecords)) + } else { + for iX := range expectedUnresolved { + if result.UnresolvedRecords[iX].GetName() != expectedUnresolved[iX] { + t.Errorf("Invalid unresolved records after sort. Expected: %v. Got: %v\n", expectedOutputOrder, dnsgraph.GetRecordsNamesForGraphables(result.UnresolvedRecords)) + } + } + } + } +} diff --git a/pkg/dnssort/result.go b/pkg/dnssort/result.go new file mode 100644 index 000000000..5f90ecdb3 --- /dev/null +++ b/pkg/dnssort/result.go @@ -0,0 +1,8 @@ +package dnssort + +import "github.com/StackExchange/dnscontrol/v4/pkg/dnsgraph" + +type SortResult[T dnsgraph.Graphable] struct { + SortedRecords []T + UnresolvedRecords []T +} diff --git a/pkg/dnstree/dnstree.go b/pkg/dnstree/dnstree.go new file mode 100644 index 000000000..a2ec2a520 --- /dev/null +++ b/pkg/dnstree/dnstree.go @@ -0,0 +1,144 @@ +package dnstree + +import ( + "strings" +) + +// Create creates a tree like structure to add arbitrary data to DNS names. +// The DomainTree splits the domain name based on the dot (.), reverses the resulting list and add all strings the tree in order. +// It has support for wildcard domain names the tree nodes (`Set`), but not during retrieval (Get and Has). +// Get always returns the most specific node; it doesn't immediately return the node upon finding a wildcard node. +func Create[T any]() *DomainTree[T] { + return &DomainTree[T]{ + IsLeaf: false, + IsWildcard: false, + Name: "", + Children: map[string]*domainNode[T]{}, + } +} + +type DomainTree[T any] domainNode[T] + +type domainNode[T any] struct { + IsLeaf bool + IsWildcard bool + Name string + Children map[string]*domainNode[T] + data T +} + +func createNode[T any](name string) *domainNode[T] { + return &domainNode[T]{ + IsLeaf: false, + Name: name, + Children: map[string]*domainNode[T]{}, + } +} + +// Set adds given data to the given fqdn. +// The FQDN can contain a wildcard on the start. +// example fqdn: *.example.com +func (tree *DomainTree[T]) Set(fqdn string, data T) { + domainParts := splitFQDN(fqdn) + + isWildcard := domainParts[0] == "*" + if isWildcard { + domainParts = domainParts[1:] + } + + ptr := (*domainNode[T])(tree) + for iX := len(domainParts) - 1; iX > 0; iX -= 1 { + ptr = ptr.addIntermediate(domainParts[iX]) + } + + ptr.addLeaf(domainParts[0], isWildcard, data) +} + +// Retrieves the attached data from a given FQDN. +// The tree will return the data entry for the most specific FQDN entry. +// If no entry is found Get will return the default value for the specific type. +// +// tree.Set("*.example.com", 1) +// tree.Set("a.example.com", 2) +// tree.Get("a.example.com") // 2 +// tree.Get("a.a.example.com") // 1 +// tree.Get("other.com") // 0 +func (tree *DomainTree[T]) Get(fqdn string) T { + domainParts := splitFQDN(fqdn) + + var mostSpecificNode *domainNode[T] + ptr := (*domainNode[T])(tree) + + for iX := len(domainParts) - 1; iX >= 0; iX -= 1 { + node, ok := ptr.Children[domainParts[iX]] + if !ok { + if mostSpecificNode != nil { + return mostSpecificNode.data + } + return *new(T) + } + + if node.IsWildcard { + mostSpecificNode = node + } + + ptr = node + } + + if ptr.IsLeaf || ptr.IsWildcard { + return ptr.data + } + + if mostSpecificNode != nil { + return mostSpecificNode.data + } + + return *new(T) +} + +// Has returns if the tree contains data for given FQDN. +func (tree *DomainTree[T]) Has(fqdn string) bool { + domainParts := splitFQDN(fqdn) + + var mostSpecificNode *domainNode[T] + ptr := (*domainNode[T])(tree) + + for iX := len(domainParts) - 1; iX >= 0; iX -= 1 { + node, ok := ptr.Children[domainParts[iX]] + if !ok { + return mostSpecificNode != nil + } + + if node.IsWildcard { + mostSpecificNode = node + } + + ptr = node + } + + return ptr.IsLeaf || ptr.IsWildcard || mostSpecificNode != nil +} + +func splitFQDN(fqdn string) []string { + normalizedFQDN := strings.TrimSuffix(fqdn, ".") + + return strings.Split(normalizedFQDN, ".") +} + +func (tree *domainNode[T]) addIntermediate(name string) *domainNode[T] { + if _, ok := tree.Children[name]; !ok { + tree.Children[name] = createNode[T](name) + } + + return tree.Children[name] +} + +func (tree *domainNode[T]) addLeaf(name string, isWildcard bool, data T) *domainNode[T] { + node := tree.addIntermediate(name) + + node.data = data + node.IsLeaf = true + node.IsWildcard = node.IsWildcard || isWildcard + + return node +} diff --git a/pkg/dnstree/dnstree_test.go b/pkg/dnstree/dnstree_test.go new file mode 100644 index 000000000..5e1957491 --- /dev/null +++ b/pkg/dnstree/dnstree_test.go @@ -0,0 +1,64 @@ +package dnstree_test + +import ( + "testing" + + "github.com/StackExchange/dnscontrol/v4/pkg/dnstree" +) + +func Test_domaintree(t *testing.T) { + + t.Run("Single FQDN", + executeTreeTest( + []string{ + "other.example.com", + }, + []string{"other.example.com"}, + []string{"com", "x.example.com", "x.www.example.com", "example.com"}, + ), + ) + + t.Run("Wildcard", + executeTreeTest( + []string{ + "*.example.com", + }, + []string{"example.com", "other.example.com"}, + []string{"com", "example.nl", "*.com"}, + ), + ) + + t.Run("Combined domains", + executeTreeTest( + []string{ + "*.other.example.com", + "specific.example.com", + "specific.example.nl", + }, + []string{"any.other.example.com", "specific.example.com", "specific.example.nl"}, + []string{"com", "nl", "", "example.nl", "other.nl"}, + ), + ) +} + +func executeTreeTest(inputs []string, founds []string, missings []string) func(*testing.T) { + return func(t *testing.T) { + t.Helper() + tree := dnstree.Create[interface{}]() + for _, input := range inputs { + tree.Set(input, struct{}{}) + } + + for _, found := range founds { + if tree.Has(found) == false { + t.Errorf("Expected %s to be found in tree, but is missing", found) + } + } + + for _, missing := range missings { + if tree.Has(missing) == true { + t.Errorf("Expected %s to be missing in tree, but is found", missing) + } + } + } +} From 84f0bc15521775e6c4828593d701c5c5e695ad36 Mon Sep 17 00:00:00 2001 From: Major Hayden Date: Tue, 5 Sep 2023 15:26:03 +0000 Subject: [PATCH 37/79] docs: Fix small route53 typo (#2546) --- documentation/providers/route53.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/providers/route53.md b/documentation/providers/route53.md index 3c71b70f0..7f1402c1d 100644 --- a/documentation/providers/route53.md +++ b/documentation/providers/route53.md @@ -80,7 +80,7 @@ D("example.com", REG_NONE, DnsProvider(DSP_R53), ## Split horizon -This provider supports spilt horizons using the [`R53_ZONE()`](../functions/record/R53_ZONE.md) domain function. +This provider supports split horizons using the [`R53_ZONE()`](../functions/record/R53_ZONE.md) domain function. In this example the domain `testzone.net` appears in the same account twice, each with different zone IDs specified using [`R53_ZONE()`](../functions/record/R53_ZONE.md). From c9ce326ae1dc5294cbe2e42b224d4c54002ab1bc Mon Sep 17 00:00:00 2001 From: tomf Date: Tue, 5 Sep 2023 15:27:04 +0000 Subject: [PATCH 38/79] MYTHICBEASTS: Add SSHFP record support (#2545) Co-authored-by: Tom Limoncelli --- documentation/providers.md | 2 +- providers/mythicbeasts/mythicbeastsProvider.go | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/documentation/providers.md b/documentation/providers.md index 1e42c150b..3ea68f8fd 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -43,7 +43,7 @@ If a feature is definitively not supported for whatever reason, we would also li | [`LOOPIA`](providers/loopia.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | | [`LUADNS`](providers/luadns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | | [`MSDNS`](providers/msdns.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ✅ | -| [`MYTHICBEASTS`](providers/mythicbeasts.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ✅ | ❔ | ✅ | ❌ | ✅ | ✅ | +| [`MYTHICBEASTS`](providers/mythicbeasts.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ❌ | ✅ | ✅ | | [`NAMECHEAP`](providers/namecheap.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❌ | ❌ | ✅ | | [`NAMEDOTCOM`](providers/namedotcom.md) | ❌ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ✅ | ❌ | ✅ | ✅ | | [`NETCUP`](providers/netcup.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ❌ | diff --git a/providers/mythicbeasts/mythicbeastsProvider.go b/providers/mythicbeasts/mythicbeastsProvider.go index 69f300988..f5798c012 100644 --- a/providers/mythicbeasts/mythicbeastsProvider.go +++ b/providers/mythicbeasts/mythicbeastsProvider.go @@ -36,6 +36,7 @@ var features = providers.DocumentationNotes{ providers.CanUseCAA: providers.Can(), providers.CanUseLOC: providers.Cannot(), providers.CanUsePTR: providers.Can(), + providers.CanUseSSHFP: providers.Can(), providers.CanUseSRV: providers.Can(), providers.CanUseTLSA: providers.Can(), providers.DocCreateDomains: providers.Cannot("Requires domain registered through Web UI"), @@ -121,8 +122,15 @@ func (n *mythicBeastsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig Msg: strings.Join(msgs, "\n"), F: func() error { var b strings.Builder - for _, rr := range dc.Records { - fmt.Fprintf(&b, "%v\n", rr.ToRR().String()) + for _, record := range dc.Records { + switch rr := record.ToRR().(type) { + case *dns.SSHFP: + // "Hex strings [for SSHFP] must be in lower-case", per Mythic Beasts API docs. + // miekg's DNS outputs uppercase: https://github.com/miekg/dns/blob/48f38ebef989eedc6b57f1869ae849ccc8f5fe29/types.go#L988 + fmt.Fprintf(&b, "%s %d %d %s\n", rr.Header().String(), rr.Algorithm, rr.Type, strings.ToLower(rr.FingerPrint)) + default: + fmt.Fprintf(&b, "%v\n", rr.String()) + } } resp, err := n.httpRequest("PUT", "/zones/"+dc.Name+"/records", strings.NewReader(b.String())) From a1c7a26351c815749d86206d4107a534f162472d Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 7 Sep 2023 10:30:18 -0400 Subject: [PATCH 39/79] MSDNS: Improve PowerShell reliability (#2551) --- providers/msdns/powershell.go | 36 +++++++++++++++--------------- providers/msdns/powershell_test.go | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/providers/msdns/powershell.go b/providers/msdns/powershell.go index 2022367bc..367deb5a5 100644 --- a/providers/msdns/powershell.go +++ b/providers/msdns/powershell.go @@ -19,12 +19,12 @@ type psHandle struct { shell ps.Shell } -// func eLog(s string) { -// f, _ := os.OpenFile("powershell.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) -// f.WriteString(s) -// f.WriteString("\n") -// f.Close() -// } +func eLog(s string) { + f, _ := os.OpenFile("powershell.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + f.WriteString(s) + f.WriteString("\n") + f.Close() +} func newPowerShell(config map[string]string) (*psHandle, error) { @@ -70,7 +70,7 @@ func (psh *psHandle) Exit() { type dnsZone map[string]interface{} func (psh *psHandle) GetDNSServerZoneAll(dnsserver string) ([]string, error) { - stdout, stderr, err := psh.shell.Execute(generatePSZoneAll(dnsserver)) + stdout, stderr, err := psh.shell.Execute("\n\r" + generatePSZoneAll(dnsserver) + "\n\r") if err != nil { return nil, err } @@ -115,7 +115,8 @@ func (psh *psHandle) GetDNSZoneRecords(dnsserver, domain string) ([]nativeRecord filename := tmpfile.Name() tmpfile.Close() - stdout, stderr, err := psh.shell.Execute(generatePSZoneDump(dnsserver, domain, filename)) + stdout, stderr, err := psh.shell.Execute( + "\n\r" + generatePSZoneDump(dnsserver, domain, filename) + "\n\r") if err != nil { return nil, err } @@ -207,8 +208,8 @@ func (psh *psHandle) RecordDelete(dnsserver, domain string, rec *models.RecordCo c = generatePSDelete(dnsserver, domain, rec) } - //eLog(c) - _, stderr, err := psh.shell.Execute(c) + eLog(c) + _, stderr, err := psh.shell.Execute("\n\r" + c + "\n\r") if err != nil { printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) return err @@ -266,8 +267,8 @@ func (psh *psHandle) RecordCreate(dnsserver, domain string, rec *models.RecordCo //printer.Printf("DEBUG: PScreate\n") } - //eLog(c) - stdout, stderr, err := psh.shell.Execute(c) + eLog(c) + stdout, stderr, err := psh.shell.Execute("\n\r" + c + "\n\r") if err != nil { printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) return err @@ -350,8 +351,8 @@ func generatePSCreate(dnsserver, domain string, rec *models.RecordConfig) string func (psh *psHandle) RecordModify(dnsserver, domain string, old, rec *models.RecordConfig) error { c := generatePSModify(dnsserver, domain, old, rec) - //eLog(c) - _, stderr, err := psh.shell.Execute(c) + eLog(c) + _, stderr, err := psh.shell.Execute("\n\r" + c + "\n\r") if err != nil { printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) return err @@ -363,10 +364,9 @@ func (psh *psHandle) RecordModify(dnsserver, domain string, old, rec *models.Rec } return nil } - func generatePSModify(dnsserver, domain string, old, rec *models.RecordConfig) string { // The simple way is to just remove the old record and insert the new record. - return generatePSDelete(dnsserver, domain, old) + ` ; ` + generatePSCreate(dnsserver, domain, rec) + return "\n\r" + generatePSDelete(dnsserver, domain, old) + " ; " + generatePSCreate(dnsserver, domain, rec) + "\n\r" // NB: SOA records can't be deleted. When we implement them, we'll // need to special case them and generate an in-place modification // command. @@ -374,8 +374,8 @@ func generatePSModify(dnsserver, domain string, old, rec *models.RecordConfig) s func (psh *psHandle) RecordModifyTTL(dnsserver, domain string, old *models.RecordConfig, newTTL uint32) error { c := generatePSModifyTTL(dnsserver, domain, old, newTTL) - //eLog(c) - _, stderr, err := psh.shell.Execute(c) + eLog(c) + _, stderr, err := psh.shell.Execute("\n\r" + c + "\n\r") if err != nil { printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) return err diff --git a/providers/msdns/powershell_test.go b/providers/msdns/powershell_test.go index 31a92c9d1..5d36249c7 100644 --- a/providers/msdns/powershell_test.go +++ b/providers/msdns/powershell_test.go @@ -29,7 +29,7 @@ func Test_generatePSZoneAll(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := generatePSZoneAll(tt.args.dnsserver); got != tt.want { + if got := generatePSZoneAll(tt.args.dnsserver); got != strings.TrimSpace(tt.want) { t.Errorf("generatePSZoneAll() = got=(\n%s\n) want=(\n%s\n)", got, tt.want) } }) @@ -59,7 +59,7 @@ func Test_generatePSZoneDump(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := generatePSZoneDump(tt.args.dnsserver, tt.args.domainname, "foo"); got != tt.want { + if got := generatePSZoneDump(tt.args.dnsserver, tt.args.domainname, "foo"); got != strings.TrimSpace(tt.want) { t.Errorf("generatePSZoneDump() = got=(\n%s\n) want=(\n%s\n)", got, tt.want) } }) From c4d5d9bf20242ee02b838a1f6d48058014350104 Mon Sep 17 00:00:00 2001 From: imlonghao Date: Thu, 7 Sep 2023 23:03:27 +0800 Subject: [PATCH 40/79] NETLIFY: fix SRV priority and allow apex NS records (#2549) Co-authored-by: Tom Limoncelli --- providers/netlify/api.go | 2 +- providers/netlify/netlifyProvider.go | 36 ---------------------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/providers/netlify/api.go b/providers/netlify/api.go index 70eaae389..31b700f85 100644 --- a/providers/netlify/api.go +++ b/providers/netlify/api.go @@ -48,7 +48,7 @@ type dnsRecordCreate struct { Flag int64 `json:"flag"` Hostname string `json:"hostname,omitempty"` Port int64 `json:"port,omitempty"` - Priority int64 `json:"priority,omitempty"` + Priority int64 `json:"priority"` Tag string `json:"tag,omitempty"` TTL int64 `json:"ttl,omitempty"` Type string `json:"type,omitempty"` diff --git a/providers/netlify/netlifyProvider.go b/providers/netlify/netlifyProvider.go index 42f474d03..203e3d61a 100644 --- a/providers/netlify/netlifyProvider.go +++ b/providers/netlify/netlifyProvider.go @@ -8,7 +8,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" - "github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/miekg/dns" ) @@ -144,43 +143,8 @@ func (n *netlifyProvider) GetZoneRecords(domain string, meta map[string]string) return cleanRecords, nil } -// Return true if the string ends in one of Netlify's name server domains -// False if anything else -func isNetlifyNameServerDomain(name string) bool { - for _, i := range nameServerSuffixes { - if strings.HasSuffix(name, i) { - return true - } - } - return false -} - -// remove all non-netlify NS records from our desired state. -// if any are found, print a warning -func removeOtherApexNS(dc *models.DomainConfig) { - newList := make([]*models.RecordConfig, 0, len(dc.Records)) - for _, rec := range dc.Records { - if rec.Type == "NS" { - // apex NS inside netlify are expected. - // We ignore them, warning as needed. - // Child delegations are supported so, we allow non-apex NS records. - if rec.GetLabelFQDN() == dc.Name { - if !isNetlifyNameServerDomain(rec.GetTargetField()) { - printer.Printf("Warning: Netlify does not allow NS records to be modified. %s will not be added.\n", rec.GetTargetField()) - } - continue - } - } - newList = append(newList, rec) - } - dc.Records = newList -} - // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (n *netlifyProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, error) { - - removeOtherApexNS(dc) - var corrections []*models.Correction var differ diff.Differ if !diff2.EnableDiff2 { From 56acf4a6b29f9b2667440872205348a6a80d59ac Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 7 Sep 2023 14:10:00 -0400 Subject: [PATCH 41/79] CHORE: Update dependencies (#2552) --- go.mod | 66 ++++++++++++++-------------- go.sum | 136 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/go.mod b/go.mod index 6179816c0..87592f409 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/StackExchange/dnscontrol/v4 go 1.18 require ( - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 @@ -11,17 +11,17 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.20.1 - github.com/aws/aws-sdk-go-v2/config v1.18.33 - github.com/aws/aws-sdk-go-v2/credentials v1.13.32 - github.com/aws/aws-sdk-go-v2/service/route53 v1.29.2 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.16.2 + github.com/aws/aws-sdk-go-v2 v1.21.0 + github.com/aws/aws-sdk-go-v2/config v1.18.39 + github.com/aws/aws-sdk-go-v2/credentials v1.13.37 + github.com/aws/aws-sdk-go-v2/service/route53 v1.29.5 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.3 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 - github.com/cloudflare/cloudflare-go v0.75.0 - github.com/digitalocean/godo v1.100.0 + github.com/cloudflare/cloudflare-go v0.76.0 + github.com/digitalocean/godo v1.102.1 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 github.com/exoscale/egoscale v0.90.2 @@ -30,9 +30,9 @@ require ( github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe github.com/google/go-github/v35 v35.3.0 github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 - github.com/hashicorp/vault/api v1.9.2 + github.com/hashicorp/vault/api v1.10.0 github.com/jarcoal/httpmock v1.0.8 // indirect - github.com/jinzhu/copier v0.3.5 + github.com/jinzhu/copier v0.4.0 github.com/miekg/dns v1.1.55 github.com/mittwald/go-powerdns v0.6.2 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 @@ -49,9 +49,9 @@ require ( github.com/transip/gotransip/v6 v6.21.0 github.com/urfave/cli/v2 v2.25.7 github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 - golang.org/x/net v0.14.0 - golang.org/x/oauth2 v0.11.0 - google.golang.org/api v0.135.0 + golang.org/x/net v0.15.0 + golang.org/x/oauth2 v0.12.0 + google.golang.org/api v0.138.0 gopkg.in/ns1/ns1-go.v2 v2.7.8 ) @@ -63,28 +63,28 @@ require ( github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-isatty v0.0.19 github.com/vultr/govultr/v2 v2.17.2 - golang.org/x/exp v0.0.0-20230807204917-050eac23e9de - golang.org/x/text v0.12.0 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + golang.org/x/text v0.13.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/compute v1.20.1 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 // indirect - github.com/aws/smithy-go v1.14.1 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect + github.com/aws/smithy-go v1.14.2 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect @@ -96,11 +96,11 @@ require ( github.com/go-test/deep v1.0.3 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/uuid v4.0.0+incompatible // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/s2a-go v0.1.4 // indirect + github.com/google/s2a-go v0.1.5 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect @@ -133,14 +133,14 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.13.0 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect + golang.org/x/sys v0.12.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.11.0 // indirect + golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect google.golang.org/grpc v1.57.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect diff --git a/go.sum b/go.sum index ee48ee01a..2a16430c2 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 h1:8iR6OLffWWorFdzL2JFCab5xpD8VKEE2DUBBl+HNTDY= @@ -16,8 +16,8 @@ github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 h1:AJKJCKcb/psppPl/9CUiQQnTG+Bce0/cIweD5w5Q7aQ= github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= @@ -35,34 +35,34 @@ github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x0 github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.20.1 h1:rZBf5DWr7YGrnlTK4kgDQGn1ltqOg5orCYb/UhOFZkg= -github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= -github.com/aws/aws-sdk-go-v2/config v1.18.33 h1:JKcw5SFxFW/rpM4mOPjv0VQ11E2kxW13F3exWOy7VZU= -github.com/aws/aws-sdk-go-v2/config v1.18.33/go.mod h1:hXO/l9pgY3K5oZJldamP0pbZHdPqqk+4/maa7DSD3cA= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32 h1:lIH1eKPcCY1ylR4B6PkBGRWMHO3aVenOKJHWiS4/G2w= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32/go.mod h1:lL8U3v/Y79YRG69WlAho0OHIKUXCyFvSXaIvfo81sls= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 h1:DK/9C+UN/X+1+Wm8pqaDksQr2tSLzq+8X1/rI/ZxKEQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8/go.mod h1:ce7BgLQfYr5hQFdy67oX2svto3ufGtm6oBvmsHScI1Q= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 h1:c8ed/T9T2K5I+h/JzmF5tpI46+OODQ74dzmdo+QnaMg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 h1:hNeAAymUY5gu11WrrmFb3CVIp9Dar9hbo44yzzcQpzA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 h1:fc0ukRAiP1syoSGZYu+DaE+FulSYhTiJ8WpVu5jElU4= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39/go.mod h1:WLAW8PT7+JhjZfLSWe7WEJaJu0GNo0cKc2Zyo003RBs= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 h1:dGAseBFEYxth10V23b5e2mAS+tX7oVbfYHD6dnDdAsg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= -github.com/aws/aws-sdk-go-v2/service/route53 v1.29.2 h1:6rbDtLVUDUBMCciu5ipjwGpGq1roAFXCVhliS2S+SAE= -github.com/aws/aws-sdk-go-v2/service/route53 v1.29.2/go.mod h1:rsvxuoKwhm9C5yWTqQ2zYtlb/aSkM+StNs/jcy93QQw= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.16.2 h1:+QM69OrWCsp5A6g1oQyC4Rbl9U9F0/xBvugb1N0Ha/U= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.16.2/go.mod h1:sVEjwdvFyw2UY9cvFeeWgVq4y2QEILPcmRF2glyTshM= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 h1:A2RlEMo4SJSwbNoUUgkxTAEMduAy/8wG3eB2b2lP4gY= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.2/go.mod h1:ju+nNXUunfIFamXUIZQiICjnO/TPlOmWcYhZcSy7xaE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 h1:OJELEgyaT2kmaBGZ+myyZbTTLobfe3ox3FSh5eYK9Qs= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2/go.mod h1:ubDBBaDFs1GHijSOTi8ljppML15GLG0HxhILtbjNNYQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 h1:ympg1+Lnq33XLhcK/xTG4yZHPs1Oyxu+6DEWbl7qOzA= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.2/go.mod h1:FQ/DQcOfESELfJi5ED+IPPAjI5xC6nxtSolVVB773jM= -github.com/aws/smithy-go v1.14.1 h1:EFKMUmH/iHMqLiwoEDx2rRjRQpI1YCn5jTysoaDujFs= -github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc= +github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= +github.com/aws/aws-sdk-go-v2/config v1.18.39 h1:oPVyh6fuu/u4OiW4qcuQyEtk7U7uuNBmHmJSLg1AJsQ= +github.com/aws/aws-sdk-go-v2/config v1.18.39/go.mod h1:+NH/ZigdPckFpgB1TRcRuWCB/Kbbvkxc/iNAKTq5RhE= +github.com/aws/aws-sdk-go-v2/credentials v1.13.37 h1:BvEdm09+ZEh2XtN+PVHPcYwKY3wIeB6pw7vPRM4M9/U= +github.com/aws/aws-sdk-go-v2/credentials v1.13.37/go.mod h1:ACLrdkd4CLZyXOghZ8IYumQbcooAcp2jo/s2xsFH8IM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= +github.com/aws/aws-sdk-go-v2/service/route53 v1.29.5 h1:6wPin3WPyQpBl/QZsoNUnqvXy4Ib1Ygv7VagGvLKJAc= +github.com/aws/aws-sdk-go-v2/service/route53 v1.29.5/go.mod h1:6zl0jh5MUKuJ07eHn3MNeLOVutxwl8m9vQltZjoLakM= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.3 h1:aaHlZb06fyEQ3uqEVJiN3hLt8syCzX+tWZiz40S4c0Y= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.3/go.mod h1:SK+5R1cYgVgSfBGi9T/gPGNIuLInF3eIRYNruia62rg= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 h1:2PylFCfKCEDv6PeSN09pC/VUiRd10wi1VfHG5FrW0/g= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.6/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 h1:pSB560BbVj9ZlJZF4WYj5zsytWHWKxg+NgyGV4B2L58= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= +github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= +github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -84,8 +84,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.75.0 h1:03a4EkwwsDo0yAHjQ/l+D36K9wTkvr0afDiI/uHQ0Xw= -github.com/cloudflare/cloudflare-go v0.75.0/go.mod h1:5ocQT9qQ99QsT1Ii2751490Z5J+W/nv6jOj+lSAe4ug= +github.com/cloudflare/cloudflare-go v0.76.0 h1:0YsPw0KHWJK2fpivzx38X5onurfM0GkanZtS8HAqlj0= +github.com/cloudflare/cloudflare-go v0.76.0/go.mod h1:5ocQT9qQ99QsT1Ii2751490Z5J+W/nv6jOj+lSAe4ug= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= @@ -103,8 +103,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI= github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw= -github.com/digitalocean/godo v1.100.0 h1:3MuDCh9Hw0MCBwV8GbHBiGrKZXCZ+VJfAY8iNCW+Mks= -github.com/digitalocean/godo v1.100.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib1YhopUc8NA= +github.com/digitalocean/godo v1.102.1 h1:BrNePwIXjQWjOJXVTBqkURMjm70BRR0qXbRKfHNBF24= +github.com/digitalocean/godo v1.102.1/go.mod h1:SaUYccN7r+CO1QtsbXGypAsgobDrmSfVMJESEfXgoEg= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= @@ -155,8 +155,8 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -196,8 +196,8 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.5 h1:8IYp3w9nysqv3JH+NJgXJzGbDHzLOTj43BmSkp+O7qg= +github.com/google/s2a-go v0.1.5/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -240,12 +240,12 @@ github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0S github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= -github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= +github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= -github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= -github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -447,11 +447,11 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230807204917-050eac23e9de h1:l5Za6utMv/HsBWWqzt4S8X17j+kt1uVETUX5UFhn2rE= -golang.org/x/exp v0.0.0-20230807204917-050eac23e9de/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -479,12 +479,12 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -517,8 +517,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -530,8 +530,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -546,14 +546,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 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/api v0.135.0 h1:6Vgfj6uPMXcyy66waYWBwmkeNB+9GmUlJDOzkukPQYQ= -google.golang.org/api v0.135.0/go.mod h1:Bp77uRFgwsSKI0BWH573F5Q6wSlznwI2NFayLOp/7mQ= +google.golang.org/api v0.138.0 h1:K/tVp05MxNVbHShRw9m7e9VJGdagNeTdMzqPH7AUqr0= +google.golang.org/api v0.138.0/go.mod h1:4xyob8CxC+0GChNBvEUAk8VBKNvYOTWM9T3v3UfRxuY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -562,10 +562,10 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= -google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e h1:S83+ibolgyZ0bqz7KEsUOPErxcv4VzlszxY+31OfB/E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= +google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= From 0b5de1adf236030f9253c92d4d1bd98fc11ce941 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 14:10:49 -0400 Subject: [PATCH 42/79] Build(deps): Bump actions/checkout from 3 to 4 (#2544) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tom Limoncelli --- .github/workflows/build.yml | 8 ++++---- .github/workflows/codeql.yml | 2 +- .github/workflows/draft_release.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5f862cf5c..a1ea1e9f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: env: TEST_RESULTS: "/tmp/test-results" steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v4 - name: restore_cache uses: actions/cache@v3.3.1 with: @@ -175,7 +175,7 @@ jobs: matrix: provider: ${{ fromJson(needs.integration-test-providers.outputs.integration_test_providers )}} steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v4 - run: mkdir -p "$TEST_RESULTS" - name: restore_cache uses: actions/cache@v3.3.1 @@ -282,7 +282,7 @@ jobs: matrix: provider: ${{ fromJson(needs.integration-test-providers.outputs.integration_test_providers )}} steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v4 - run: mkdir -p "$TEST_RESULTS" - name: restore_cache uses: actions/cache@v3.3.1 @@ -314,7 +314,7 @@ jobs: # DOCKERHUB_ACCESS_TOKEN: # DOCKERHUB_USERNAME: # steps: -# - uses: actions/checkout@v3.5.0 +# - uses: actions/checkout@v4 ## # 'setup_remote_docker' was not transformed because there is no suitable equivalent in GitHub Actions # - uses: "./.github/actions/docker_check" # with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 985604ee8..e9429297d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml index fbe2623d0..82494ff90 100644 --- a/.github/workflows/draft_release.yml +++ b/.github/workflows/draft_release.yml @@ -19,7 +19,7 @@ jobs: uses: docker/setup-qemu-action@v2 - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 # Why "fetch-depth: 0"? To generate the release notes, we need the From af91e37043d49ce1d5f8ecc54c0196d972772bae Mon Sep 17 00:00:00 2001 From: asn-iac <134323752+asn-iac@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:31:34 -0700 Subject: [PATCH 43/79] CLOUDFLAREAPI: Add NAPTR record support (#2548) --- documentation/providers.md | 2 +- providers/cloudflare/cloudflareProvider.go | 10 ++++++++++ providers/cloudflare/rest.go | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/documentation/providers.md b/documentation/providers.md index 3ea68f8fd..d9a37484f 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -19,7 +19,7 @@ If a feature is definitively not supported for whatever reason, we would also li | [`AXFRDDNS`](providers/axfrddns.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | | [`AZURE_DNS`](providers/azure_dns.md) | ✅ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | | [`BIND`](providers/bind.md) | ✅ | ✅ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | -| [`CLOUDFLAREAPI`](providers/cloudflareapi.md) | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ✅ | +| [`CLOUDFLAREAPI`](providers/cloudflareapi.md) | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ✅ | | [`CLOUDNS`](providers/cloudns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | | [`CSCGLOBAL`](providers/cscglobal.md) | ✅ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ✅ | | [`DESEC`](providers/desec.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go index 9f303fae1..a310c4136 100644 --- a/providers/cloudflare/cloudflareProvider.go +++ b/providers/cloudflare/cloudflareProvider.go @@ -45,6 +45,7 @@ var features = providers.DocumentationNotes{ providers.CanUseCAA: providers.Can(), providers.CanUseDSForChildren: providers.Can(), providers.CanUseLOC: providers.Cannot(), + providers.CanUseNAPTR: providers.Can(), providers.CanUsePTR: providers.Can(), providers.CanUseSRV: providers.Can(), providers.CanUseSSHFP: providers.Can(), @@ -793,6 +794,15 @@ func (c cfTarget) FQDN() string { return strings.TrimRight(string(c), ".") + "." } +type cfNaptrRecData struct { + Flags string `json:"flags"` + Order uint16 `json:"order"` + Preference uint16 `json:"preference"` + Regex string `json:"regex"` + Replacement string `json:"replacement"` + Service string `json:"service"` +} + // uint16Zero converts value to uint16 or returns 0. func uint16Zero(value interface{}) uint16 { switch v := value.(type) { diff --git a/providers/cloudflare/rest.go b/providers/cloudflare/rest.go index ec2138b4b..b2072b11e 100644 --- a/providers/cloudflare/rest.go +++ b/providers/cloudflare/rest.go @@ -118,6 +118,17 @@ func cfSshfpData(rec *models.RecordConfig) *cfRecData { } } +func cfNaptrData(rec *models.RecordConfig) *cfNaptrRecData { + return &cfNaptrRecData{ + Flags: rec.NaptrFlags, + Order: rec.NaptrOrder, + Preference: rec.NaptrPreference, + Regex: rec.NaptrRegexp, + Replacement: rec.GetTargetField(), + Service: rec.NaptrService, + } +} + func (c *cloudflareProvider) createRec(rec *models.RecordConfig, domainID string) []*models.Correction { var id string content := rec.GetTargetField() @@ -159,6 +170,9 @@ func (c *cloudflareProvider) createRec(rec *models.RecordConfig, domainID string cf.Name = rec.GetLabelFQDN() } else if rec.Type == "DS" { cf.Data = cfDSData(rec) + } else if rec.Type == "NAPTR" { + cf.Data = cfNaptrData(rec) + cf.Name = rec.GetLabelFQDN() } resp, err := c.cfClient.CreateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(domainID), cf) if err != nil { @@ -225,6 +239,9 @@ func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID s cf.Name = rec.GetLabelFQDN() } else if rec.Type == "DS" { cf.Data = cfDSData(rec) + } else if rec.Type == "NAPTR" { + cf.Data = cfNaptrData(rec) + cf.Name = rec.GetLabelFQDN() } resp, err := c.cfClient.CreateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(domainID), cf) if err != nil { @@ -275,6 +292,9 @@ func (c *cloudflareProvider) modifyRecord(domainID, recID string, proxied bool, } else if rec.Type == "DS" { r.Data = cfDSData(rec) r.Content = "" + } else if rec.Type == "NAPTR" { + r.Data = cfNaptrData(rec) + r.Name = rec.GetLabelFQDN() } _, err := c.cfClient.UpdateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(domainID), r) return err From 1c5e038c67fca647daa3ea651b935ce90e777cc2 Mon Sep 17 00:00:00 2001 From: Florian Ritterhoff Date: Fri, 2 Jun 2023 06:10:35 +0200 Subject: [PATCH 44/79] add dhcid type --- build/generate/featureMatrix.go | 6 ++++++ models/dnsrr.go | 2 ++ models/record.go | 2 ++ pkg/js/helpers.js | 3 +++ pkg/js/parse_tests/046-DHCID.js | 3 +++ pkg/js/parse_tests/046-DHCID.json | 18 ++++++++++++++++++ pkg/normalize/validate.go | 4 +++- providers/axfrddns/axfrddnsProvider.go | 1 + providers/bind/bindProvider.go | 1 + providers/capabilities.go | 3 +++ providers/capability_string.go | 5 +++-- 11 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 pkg/js/parse_tests/046-DHCID.js create mode 100644 pkg/js/parse_tests/046-DHCID.json diff --git a/build/generate/featureMatrix.go b/build/generate/featureMatrix.go index 06c0178fe..c032d092f 100644 --- a/build/generate/featureMatrix.go +++ b/build/generate/featureMatrix.go @@ -87,6 +87,7 @@ func matrixData() *FeatureMatrix { DomainModifierSshfp = "[`SSHFP`](functions/domain/SSHFP.md)" DomainModifierTlsa = "[`TLSA`](functions/domain/TLSA.md)" DomainModifierDs = "[`DS`](functions/domain/DS.md)" + DomainModifierDhcid = "[`DHCID`](functions/domain/DHCID.md)" DualHost = "dual host" CreateDomains = "create-domains" NoPurge = "[`NO_PURGE`](functions/domain/NO_PURGE.md)" @@ -110,6 +111,7 @@ func matrixData() *FeatureMatrix { DomainModifierSshfp, DomainModifierTlsa, DomainModifierDs, + DomainModifierDhcid, DualHost, CreateDomains, NoPurge, @@ -212,6 +214,10 @@ func matrixData() *FeatureMatrix { DomainModifierTlsa, providers.CanUseTLSA, ) + setCapability( + DomainModifierDhcid, + providers.CanUseDHCID, + ) setCapability( GetZones, providers.CanGetZones, diff --git a/models/dnsrr.go b/models/dnsrr.go index 2361c7f38..b7b73e264 100644 --- a/models/dnsrr.go +++ b/models/dnsrr.go @@ -96,6 +96,8 @@ func RRtoRC(rr dns.RR, origin string) (RecordConfig, error) { err = rc.SetTargetTLSA(v.Usage, v.Selector, v.MatchingType, v.Certificate) case *dns.TXT: err = rc.SetTargetTXTs(v.Txt) + case *dns.DHCID: + err = rc.SetTarget(v.Digest) default: return *rc, fmt.Errorf("rrToRecord: Unimplemented zone record type=%s (%v)", rc.Type, rr) } diff --git a/models/record.go b/models/record.go index 9c958a808..fb2f7cccd 100644 --- a/models/record.go +++ b/models/record.go @@ -446,6 +446,8 @@ func (rc *RecordConfig) ToRR() dns.RR { rr.(*dns.TLSA).Certificate = rc.GetTargetField() case dns.TypeTXT: rr.(*dns.TXT).Txt = rc.TxtStrings + case dns.TypeDHCID: + rr.(*dns.DHCID).Digest = rc.GetTargetField() default: panic(fmt.Sprintf("ToRR: Unimplemented rtype %v", rc.Type)) // We panic so that we quickly find any switch statements diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index 6581cfaf2..10dfa1f69 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -407,6 +407,9 @@ var DS = recordBuilder('DS', { }, }); +// DHCID(name,target, recordModifiers...) +var DHCID = recordBuilder('DHCID'); + // PTR(name,target, recordModifiers...) var PTR = recordBuilder('PTR'); diff --git a/pkg/js/parse_tests/046-DHCID.js b/pkg/js/parse_tests/046-DHCID.js new file mode 100644 index 000000000..8847c54ff --- /dev/null +++ b/pkg/js/parse_tests/046-DHCID.js @@ -0,0 +1,3 @@ +D("foo.com","none", + DHCID("@", "Test") +); diff --git a/pkg/js/parse_tests/046-DHCID.json b/pkg/js/parse_tests/046-DHCID.json new file mode 100644 index 000000000..a64818280 --- /dev/null +++ b/pkg/js/parse_tests/046-DHCID.json @@ -0,0 +1,18 @@ +{ + "registrars": [], + "dns_providers": [], + "domains": [ + { + "name": "foo.com", + "registrar": "none", + "dnsProviders": {}, + "records": [ + { + "type": "DHCID", + "name": "@", + "target": "Test" + } + ] + } + ] +} diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 0a52cad1a..23694c98c 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -73,6 +73,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin "SSHFP": true, "TLSA": true, "TXT": true, + "DHCID": true, } _, ok := validTypes[rec.Type] if !ok { @@ -221,7 +222,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) { } case "SRV": check(checkTarget(target)) - case "TXT", "IMPORT_TRANSFORM", "CAA", "SSHFP", "TLSA", "DS": + case "TXT", "IMPORT_TRANSFORM", "CAA", "SSHFP", "TLSA", "DS", "DHCID": default: if rec.Metadata["orig_custom_type"] != "" { // it is a valid custom type. We perform no validation on target @@ -696,6 +697,7 @@ var providerCapabilityChecks = []pairTypeCapability{ capabilityCheck("SRV", providers.CanUseSRV), capabilityCheck("SSHFP", providers.CanUseSSHFP), capabilityCheck("TLSA", providers.CanUseTLSA), + capabilityCheck("DHCID", providers.CanUseDHCID), // DS needs special record-level checks { diff --git a/providers/axfrddns/axfrddnsProvider.go b/providers/axfrddns/axfrddnsProvider.go index d455fc205..d670b775b 100644 --- a/providers/axfrddns/axfrddnsProvider.go +++ b/providers/axfrddns/axfrddnsProvider.go @@ -49,6 +49,7 @@ var features = providers.DocumentationNotes{ providers.CanUseSRV: providers.Can(), providers.CanUseSSHFP: providers.Can(), providers.CanUseTLSA: providers.Can(), + providers.CanUseDHCID: providers.Can(), providers.CantUseNOPURGE: providers.Cannot(), providers.DocCreateDomains: providers.Cannot(), providers.DocDualHost: providers.Cannot(), diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index fdb746625..21c98da64 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -44,6 +44,7 @@ var features = providers.DocumentationNotes{ providers.CanUseSRV: providers.Can(), providers.CanUseSSHFP: providers.Can(), providers.CanUseTLSA: providers.Can(), + providers.CanUseDHCID: providers.Can(), providers.CantUseNOPURGE: providers.Cannot(), providers.DocCreateDomains: providers.Can("Driver just maintains list of zone files. It should automatically add missing ones."), providers.DocDualHost: providers.Can(), diff --git a/providers/capabilities.go b/providers/capabilities.go index 3335c8f5a..972163391 100644 --- a/providers/capabilities.go +++ b/providers/capabilities.go @@ -78,6 +78,9 @@ const ( // DocOfficiallySupported means it is actively used and maintained by stack exchange DocOfficiallySupported + + // CanUseDHCID indicates the provider can handle DHCID records + CanUseDHCID ) var providerCapabilities = map[string]map[Capability]bool{} diff --git a/providers/capability_string.go b/providers/capability_string.go index fb35841af..fd5753163 100644 --- a/providers/capability_string.go +++ b/providers/capability_string.go @@ -28,11 +28,12 @@ func _() { _ = x[DocCreateDomains-17] _ = x[DocDualHost-18] _ = x[DocOfficiallySupported-19] + _ = x[CanUseDHCID-20] } -const _Capability_name = "CanAutoDNSSECCanGetZonesCanUseAKAMAICDNCanUseAliasCanUseAzureAliasCanUseCAACanUseDSCanUseDSForChildrenCanUseLOCCanUseNAPTRCanUsePTRCanUseRoute53AliasCanUseSOACanUseSRVCanUseSSHFPCanUseTLSACantUseNOPURGEDocCreateDomainsDocDualHostDocOfficiallySupported" +const _Capability_name = "CanAutoDNSSECCanGetZonesCanUseAKAMAICDNCanUseAliasCanUseAzureAliasCanUseCAACanUseDSCanUseDSForChildrenCanUseLOCCanUseNAPTRCanUsePTRCanUseRoute53AliasCanUseSOACanUseSRVCanUseSSHFPCanUseTLSACantUseNOPURGEDocCreateDomainsDocDualHostDocOfficiallySupportedCanUseDHCID" -var _Capability_index = [...]uint8{0, 13, 24, 39, 50, 66, 75, 83, 102, 111, 122, 131, 149, 158, 167, 178, 188, 202, 218, 229, 251} +var _Capability_index = [...]uint16{0, 13, 24, 39, 50, 66, 75, 83, 102, 111, 122, 131, 149, 158, 167, 178, 188, 202, 218, 229, 251, 262} func (i Capability) String() string { if i >= Capability(len(_Capability_index)-1) { From 3e1e7aeb8ee45cd987f1e78da76f5d447709f1a3 Mon Sep 17 00:00:00 2001 From: Florian Ritterhoff Date: Tue, 22 Aug 2023 11:09:50 +0200 Subject: [PATCH 45/79] fix: correct order for dhcid --- build/generate/featureMatrix.go | 8 ++++---- models/dnsrr.go | 4 ++-- models/record.go | 4 ++-- pkg/normalize/validate.go | 4 ++-- providers/bind/bindProvider.go | 2 +- providers/capabilities.go | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/build/generate/featureMatrix.go b/build/generate/featureMatrix.go index c032d092f..e204728e0 100644 --- a/build/generate/featureMatrix.go +++ b/build/generate/featureMatrix.go @@ -182,6 +182,10 @@ func matrixData() *FeatureMatrix { DomainModifierCaa, providers.CanUseCAA, ) + setCapability( + DomainModifierDhcid, + providers.CanUseDHCID, + ) setCapability( DomainModifierDs, providers.CanUseDS, @@ -214,10 +218,6 @@ func matrixData() *FeatureMatrix { DomainModifierTlsa, providers.CanUseTLSA, ) - setCapability( - DomainModifierDhcid, - providers.CanUseDHCID, - ) setCapability( GetZones, providers.CanGetZones, diff --git a/models/dnsrr.go b/models/dnsrr.go index b7b73e264..1ef0f8212 100644 --- a/models/dnsrr.go +++ b/models/dnsrr.go @@ -74,6 +74,8 @@ func RRtoRC(rr dns.RR, origin string) (RecordConfig, error) { err = rc.SetTargetCAA(v.Flag, v.Tag, v.Value) case *dns.CNAME: err = rc.SetTarget(v.Target) + case *dns.DHCID: + err = rc.SetTarget(v.Digest) case *dns.DS: err = rc.SetTargetDS(v.KeyTag, v.Algorithm, v.DigestType, v.Digest) case *dns.LOC: @@ -96,8 +98,6 @@ func RRtoRC(rr dns.RR, origin string) (RecordConfig, error) { err = rc.SetTargetTLSA(v.Usage, v.Selector, v.MatchingType, v.Certificate) case *dns.TXT: err = rc.SetTargetTXTs(v.Txt) - case *dns.DHCID: - err = rc.SetTarget(v.Digest) default: return *rc, fmt.Errorf("rrToRecord: Unimplemented zone record type=%s (%v)", rc.Type, rr) } diff --git a/models/record.go b/models/record.go index fb2f7cccd..a8ebd9436 100644 --- a/models/record.go +++ b/models/record.go @@ -390,6 +390,8 @@ func (rc *RecordConfig) ToRR() dns.RR { rr.(*dns.CAA).Value = rc.GetTargetField() case dns.TypeCNAME: rr.(*dns.CNAME).Target = rc.GetTargetField() + case dns.TypeDHCID: + rr.(*dns.DHCID).Digest = rc.GetTargetField() case dns.TypeDS: rr.(*dns.DS).Algorithm = rc.DsAlgorithm rr.(*dns.DS).DigestType = rc.DsDigestType @@ -446,8 +448,6 @@ func (rc *RecordConfig) ToRR() dns.RR { rr.(*dns.TLSA).Certificate = rc.GetTargetField() case dns.TypeTXT: rr.(*dns.TXT).Txt = rc.TxtStrings - case dns.TypeDHCID: - rr.(*dns.DHCID).Digest = rc.GetTargetField() default: panic(fmt.Sprintf("ToRR: Unimplemented rtype %v", rc.Type)) // We panic so that we quickly find any switch statements diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 23694c98c..998baeaf0 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -222,7 +222,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) { } case "SRV": check(checkTarget(target)) - case "TXT", "IMPORT_TRANSFORM", "CAA", "SSHFP", "TLSA", "DS", "DHCID": + case "CAA", "DHCID", "DS", "IMPORT_TRANSFORM", "SSHFP", "TLSA", "TXT": default: if rec.Metadata["orig_custom_type"] != "" { // it is a valid custom type. We perform no validation on target @@ -689,6 +689,7 @@ var providerCapabilityChecks = []pairTypeCapability{ capabilityCheck("AUTODNSSEC", providers.CanAutoDNSSEC), capabilityCheck("AZURE_ALIAS", providers.CanUseAzureAlias), capabilityCheck("CAA", providers.CanUseCAA), + capabilityCheck("DHCID", providers.CanUseDHCID), capabilityCheck("LOC", providers.CanUseLOC), capabilityCheck("NAPTR", providers.CanUseNAPTR), capabilityCheck("PTR", providers.CanUsePTR), @@ -697,7 +698,6 @@ var providerCapabilityChecks = []pairTypeCapability{ capabilityCheck("SRV", providers.CanUseSRV), capabilityCheck("SSHFP", providers.CanUseSSHFP), capabilityCheck("TLSA", providers.CanUseTLSA), - capabilityCheck("DHCID", providers.CanUseDHCID), // DS needs special record-level checks { diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index 21c98da64..444ce6d72 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -36,6 +36,7 @@ var features = providers.DocumentationNotes{ providers.CanAutoDNSSEC: providers.Can("Just writes out a comment indicating DNSSEC was requested"), providers.CanGetZones: providers.Can(), providers.CanUseCAA: providers.Can(), + providers.CanUseDHCID: providers.Can(), providers.CanUseDS: providers.Can(), providers.CanUseLOC: providers.Can(), providers.CanUseNAPTR: providers.Can(), @@ -44,7 +45,6 @@ var features = providers.DocumentationNotes{ providers.CanUseSRV: providers.Can(), providers.CanUseSSHFP: providers.Can(), providers.CanUseTLSA: providers.Can(), - providers.CanUseDHCID: providers.Can(), providers.CantUseNOPURGE: providers.Cannot(), providers.DocCreateDomains: providers.Can("Driver just maintains list of zone files. It should automatically add missing ones."), providers.DocDualHost: providers.Can(), diff --git a/providers/capabilities.go b/providers/capabilities.go index 972163391..5af2817ca 100644 --- a/providers/capabilities.go +++ b/providers/capabilities.go @@ -32,6 +32,9 @@ const ( // CanUseCAA indicates the provider can handle CAA records CanUseCAA + // CanUseDHCID indicates the provider can handle DHCID records + CanUseDHCID + // CanUseDS indicates that the provider can handle DS record types. This // implies CanUseDSForChildren without specifying the latter explicitly. CanUseDS @@ -78,9 +81,6 @@ const ( // DocOfficiallySupported means it is actively used and maintained by stack exchange DocOfficiallySupported - - // CanUseDHCID indicates the provider can handle DHCID records - CanUseDHCID ) var providerCapabilities = map[string]map[Capability]bool{} From b6e183d4b53bad1af133ab977b3d70f54dfc20a9 Mon Sep 17 00:00:00 2001 From: Florian Ritterhoff Date: Sun, 10 Sep 2023 08:05:26 +0200 Subject: [PATCH 46/79] add missing handling of dhcid --- integrationTest/integration_test.go | 9 ++++++++ models/domain.go | 2 +- models/record.go | 4 ++-- models/t_parse.go | 2 ++ pkg/normalize/validate.go | 2 +- pkg/prettyzone/prettyzone_test.go | 2 ++ providers/capability_string.go | 34 ++++++++++++++--------------- 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 66dadb8fe..366898880 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -536,6 +536,10 @@ func cname(name, target string) *models.RecordConfig { return makeRec(name, target, "CNAME") } +func dhcid(name, target string) *models.RecordConfig { + return makeRec(name, target, "DHCID") +} + func ds(name string, keyTag uint16, algorithm, digestType uint8, digest string) *models.RecordConfig { r := makeRec(name, "", "DS") r.SetTargetDS(keyTag, algorithm, digestType, digest) @@ -1554,6 +1558,11 @@ func makeTests(t *testing.T) []*TestGroup { // ns("another-child", "ns101.cloudns.net."), //), ), + testgroup("PTR", + requires(providers.CanUsePTR), + tc("Create DHCPID record", dhcid("test", "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=")), + tc("Modify DHCPID record", dhcid("test", "Test/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=")), + ), //// Vendor-specific record types diff --git a/models/domain.go b/models/domain.go index 63c8a8a27..b7640745d 100644 --- a/models/domain.go +++ b/models/domain.go @@ -135,7 +135,7 @@ func (dc *DomainConfig) Punycode() error { rec.SetTarget(t) case "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE": rec.SetTarget(rec.GetTargetField()) - case "A", "AAAA", "CAA", "DS", "LOC", "NAPTR", "SOA", "SSHFP", "TXT", "TLSA", "AZURE_ALIAS": + case "A", "AAAA", "CAA", "DHCPID", "DS", "LOC", "NAPTR", "SOA", "SSHFP", "TXT", "TLSA", "AZURE_ALIAS": // Nothing to do. default: return fmt.Errorf("Punycode rtype %v unimplemented", rec.Type) diff --git a/models/record.go b/models/record.go index a8ebd9436..894c49dac 100644 --- a/models/record.go +++ b/models/record.go @@ -595,7 +595,7 @@ func Downcase(recs []*RecordConfig) { // Target is case insensitive. Downcase it. r.target = strings.ToLower(r.target) // BUGFIX(tlim): isn't ALIAS in the wrong case statement? - case "A", "ALIAS", "CAA", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TXT": + case "A", "ALIAS", "CAA", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "DHCID", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TXT": // Do nothing. (IP address or case sensitive target) case "SOA": if r.target != "DEFAULT_NOT_SET." { @@ -619,7 +619,7 @@ func CanonicalizeTargets(recs []*RecordConfig, origin string) { case "AKAMAICDN", "ANAME", "CNAME", "DS", "MX", "NS", "NAPTR", "PTR", "SRV": // Target is a hostname that might be a shortname. Turn it into a FQDN. r.target = dnsutil.AddOrigin(r.target, originFQDN) - case "A", "ALIAS", "CAA", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TLSA", "TXT": + case "A", "ALIAS", "CAA", "DHCID", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TLSA", "TXT": // Do nothing. case "SOA": if r.target != "DEFAULT_NOT_SET." { diff --git a/models/t_parse.go b/models/t_parse.go index 374526e91..1cbfeea63 100644 --- a/models/t_parse.go +++ b/models/t_parse.go @@ -59,6 +59,8 @@ func (rc *RecordConfig) PopulateFromString(rtype, contents, origin string) error return rc.SetTargetCAAString(contents) case "DS": return rc.SetTargetDSString(contents) + case "DHCID": + return rc.SetTarget(contents) case "LOC": return rc.SetTargetLOCString(origin, contents) case "MX": diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 998baeaf0..3b30cc34b 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -61,6 +61,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin "ALIAS": false, "CAA": true, "CNAME": true, + "DHCID": true, "DS": true, "IMPORT_TRANSFORM": false, "LOC": true, @@ -73,7 +74,6 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin "SSHFP": true, "TLSA": true, "TXT": true, - "DHCID": true, } _, ok := validTypes[rec.Type] if !ok { diff --git a/pkg/prettyzone/prettyzone_test.go b/pkg/prettyzone/prettyzone_test.go index 85e2f3c93..88f93454d 100644 --- a/pkg/prettyzone/prettyzone_test.go +++ b/pkg/prettyzone/prettyzone_test.go @@ -272,6 +272,7 @@ func TestWriteZoneFileEach(t *testing.T) { d = append(d, mustNewRR(`_443._tcp.bosun.org. 300 IN TLSA 3 1 1 abcdef0`)) // Label must be _port._proto d = append(d, mustNewRR(`sub.bosun.org. 300 IN NS bosun.org.`)) // Must be a label with no other records. d = append(d, mustNewRR(`x.bosun.org. 300 IN CNAME bosun.org.`)) // Must be a label with no other records. + d = append(d, mustNewRR(`bosun.org. 300 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=`)) buf := &bytes.Buffer{} WriteZoneFileRR(buf, d, "bosun.org") if buf.String() != testdataZFEach { @@ -289,6 +290,7 @@ var testdataZFEach = `$TTL 300 IN SRV 10 10 9999 foo.com. IN TXT "my text" IN CAA 0 issue "letsencrypt.org" + IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= 4.5 IN PTR y.bosun.org. _443._tcp IN TLSA 3 1 1 abcdef0 sub IN NS bosun.org. diff --git a/providers/capability_string.go b/providers/capability_string.go index fd5753163..1363be8dd 100644 --- a/providers/capability_string.go +++ b/providers/capability_string.go @@ -14,26 +14,26 @@ func _() { _ = x[CanUseAlias-3] _ = x[CanUseAzureAlias-4] _ = x[CanUseCAA-5] - _ = x[CanUseDS-6] - _ = x[CanUseDSForChildren-7] - _ = x[CanUseLOC-8] - _ = x[CanUseNAPTR-9] - _ = x[CanUsePTR-10] - _ = x[CanUseRoute53Alias-11] - _ = x[CanUseSOA-12] - _ = x[CanUseSRV-13] - _ = x[CanUseSSHFP-14] - _ = x[CanUseTLSA-15] - _ = x[CantUseNOPURGE-16] - _ = x[DocCreateDomains-17] - _ = x[DocDualHost-18] - _ = x[DocOfficiallySupported-19] - _ = x[CanUseDHCID-20] + _ = x[CanUseDHCID-6] + _ = x[CanUseDS-7] + _ = x[CanUseDSForChildren-8] + _ = x[CanUseLOC-9] + _ = x[CanUseNAPTR-10] + _ = x[CanUsePTR-11] + _ = x[CanUseRoute53Alias-12] + _ = x[CanUseSOA-13] + _ = x[CanUseSRV-14] + _ = x[CanUseSSHFP-15] + _ = x[CanUseTLSA-16] + _ = x[CantUseNOPURGE-17] + _ = x[DocCreateDomains-18] + _ = x[DocDualHost-19] + _ = x[DocOfficiallySupported-20] } -const _Capability_name = "CanAutoDNSSECCanGetZonesCanUseAKAMAICDNCanUseAliasCanUseAzureAliasCanUseCAACanUseDSCanUseDSForChildrenCanUseLOCCanUseNAPTRCanUsePTRCanUseRoute53AliasCanUseSOACanUseSRVCanUseSSHFPCanUseTLSACantUseNOPURGEDocCreateDomainsDocDualHostDocOfficiallySupportedCanUseDHCID" +const _Capability_name = "CanAutoDNSSECCanGetZonesCanUseAKAMAICDNCanUseAliasCanUseAzureAliasCanUseCAACanUseDHCIDCanUseDSCanUseDSForChildrenCanUseLOCCanUseNAPTRCanUsePTRCanUseRoute53AliasCanUseSOACanUseSRVCanUseSSHFPCanUseTLSACantUseNOPURGEDocCreateDomainsDocDualHostDocOfficiallySupported" -var _Capability_index = [...]uint16{0, 13, 24, 39, 50, 66, 75, 83, 102, 111, 122, 131, 149, 158, 167, 178, 188, 202, 218, 229, 251, 262} +var _Capability_index = [...]uint16{0, 13, 24, 39, 50, 66, 75, 86, 94, 113, 122, 133, 142, 160, 169, 178, 189, 199, 213, 229, 240, 262} func (i Capability) String() string { if i >= Capability(len(_Capability_index)-1) { From 5b95f29082d5ebf175aec394227de4ffcaafea39 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 14 Sep 2023 10:25:45 -0400 Subject: [PATCH 47/79] Improve require() docs (#2553) --- documentation/functions/global/require.md | 46 +++++++++++++------ .../functions/global/require_glob.md | 14 +++--- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/documentation/functions/global/require.md b/documentation/functions/global/require.md index 07e93fba6..7e7482e24 100644 --- a/documentation/functions/global/require.md +++ b/documentation/functions/global/require.md @@ -8,17 +8,38 @@ ts_ignore: true `require(...)` loads the specified JavaScript or JSON file, allowing to split your configuration across multiple files. +A better name for this function might be "include". + If the supplied `path` string ends with `.js`, the file is interpreted as JavaScript code, almost as though its contents had been included in the currently-executing file. If the path string ends with `.json`, `require()` returns the `JSON.parse()` of the file's contents. -If the path string begins with a `.`, it is interpreted relative to +If the path string begins with a `./`, it is interpreted relative to the currently-loading file (which may not be the file where the -`require()` statement is, if called within a function), otherwise it +`require()` statement is, if called within a function). Otherwise it is interpreted relative to the program's working directory at the time of the call. +### Example 1: Simple + +In this example, we separate our macros in one file, and put groups of domains +in 3 other files. The result is a cleaner separation of code vs. domains. + +{% code title="dnsconfig.js" %} +```javascript +require("lib/macros.json"); + +require("domains/main.json"); +require("domains/parked.json"); +require("domains/otherstuff.json"); +``` +{% endcode %} + +### Example 2: Complex + +Here's a more complex example: + {% code title="dnsconfig.js" %} ```javascript require("kubernetes/clusters.js"); @@ -60,7 +81,9 @@ function includeK8Sdev() { ``` {% endcode %} -You can also use it to require JSON files and initialize variables with it: +### Example 3: JSON + +Requiring JSON files initializes variables: {% code title="dnsconfig.js" %} ```javascript @@ -83,16 +106,13 @@ for (var domain in domains) { ``` {% endcode %} -# Future +# Notes -It might be better to rename the function to something like -`include()` instead, (leaving `require` as a deprecated alias) because -by analogy it is *much* closer to PHP's `include()` function than it -is to node's `require()`. After all, the reason node.js calls it -"require" is because it's a declarative statement saying the file is -needed, and so should be loaded if it hasn't already been loaded. +`require()` is *much* closer to PHP's `include()` function than it +is to node's `require()`. +Node's `require()` only includes a file once. In contrast, DNSControl's `require()` is actually an imperative command to -load the file and execute the code or parse the data from it. (So if -two files both `require("./tools.js")`, for example, then it will be -loaded twice, whereas in node.js it would only be loaded once.) +load the file and execute the code or parse the data from it. For example if +two files both `require("./tools.js")`, then it will be +loaded twice, whereas in node.js it would only be loaded once. diff --git a/documentation/functions/global/require_glob.md b/documentation/functions/global/require_glob.md index da7b4cd77..d56cad985 100644 --- a/documentation/functions/global/require_glob.md +++ b/documentation/functions/global/require_glob.md @@ -8,7 +8,7 @@ parameter_types: recursive: boolean --- -`require_glob()` can recursively load `.js` files, optionally non-recursive as well. +`require_glob()` recursively loads `.js` files that match a glob (wildcard). The recursion can be disabled. Possible parameters are: @@ -31,8 +31,13 @@ require_glob("./domains/", false); ``` {% endcode %} -One more important thing to note: `require_glob()` is as smart as `require()` is. It loads files always relative to the JavaScript -file where it's being executed in. Let's go with an example, as it describes it better: +# Comparison to require() + +`require_glob()` and `require()` both use the same rules for determining which directory path is +relative to. + +This will load files being present underneath `./domains/user1/` and **NOT** at below `./domains/`, as `require_glob()` +is called in the subfolder `domains/`. {% code title="dnsconfig.js" %} ```javascript @@ -45,6 +50,3 @@ require("domains/index.js"); require_glob("./user1/"); ``` {% endcode %} - -This will now load files being present underneath `./domains/user1/` and **NOT** at below `./domains/`, as `require_glob()` -is called in the subfolder `domains/`. From d75b72f08a3a333519bc8f06b81e49e195540966 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:26:22 -0400 Subject: [PATCH 48/79] Build(deps): Bump actions/upload-artifact from 3.1.2 to 3.1.3 (#2555) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tom Limoncelli --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a1ea1e9f4..ca60ee815 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- $PACKAGE_NAMES - name: Enforce Go Formatted Code run: "[ `go fmt ./... | wc -l` -eq 0 ]" - - uses: actions/upload-artifact@v3.1.2 + - uses: actions/upload-artifact@v3.1.3 with: path: "/tmp/test-results" @@ -192,7 +192,7 @@ jobs: gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- -timeout 30m -v -verbose -provider ${{ matrix.provider }} -cfworkers=false fi working-directory: integrationTest - - uses: actions/upload-artifact@v3.1.2 + - uses: actions/upload-artifact@v3.1.3 with: path: "/tmp/test-results" integrtests-diff2: @@ -299,7 +299,7 @@ jobs: echo "Skip test for ${{ matrix.provider }} provider" fi working-directory: integrationTest - - uses: actions/upload-artifact@v3.1.2 + - uses: actions/upload-artifact@v3.1.3 with: path: "/tmp/test-results" # release: @@ -328,10 +328,10 @@ jobs: # - name: Install goreleaser # run: go install github.com/goreleaser/goreleaser@latest # - run: goreleaser release -# - uses: actions/upload-artifact@v3.1.2 +# - uses: actions/upload-artifact@v3.1.3 # with: # path: dist -# - uses: actions/upload-artifact@v3.1.2 +# - uses: actions/upload-artifact@v3.1.3 # with: # path: |- # dist/*.rpm From f1fd723c809e153f806c6f1573426b9c0109d430 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:26:51 -0400 Subject: [PATCH 49/79] Build(deps): Bump actions/cache from 3.3.1 to 3.3.2 (#2554) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tom Limoncelli --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca60ee815..d13048b13 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: restore_cache - uses: actions/cache@v3.3.1 + uses: actions/cache@v3.3.2 with: key: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} restore-keys: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} @@ -178,7 +178,7 @@ jobs: - uses: actions/checkout@v4 - run: mkdir -p "$TEST_RESULTS" - name: restore_cache - uses: actions/cache@v3.3.1 + uses: actions/cache@v3.3.2 with: key: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} restore-keys: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} @@ -285,7 +285,7 @@ jobs: - uses: actions/checkout@v4 - run: mkdir -p "$TEST_RESULTS" - name: restore_cache - uses: actions/cache@v3.3.1 + uses: actions/cache@v3.3.2 with: key: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} restore-keys: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} @@ -321,7 +321,7 @@ jobs: # docker-password: "${{ secrets.DOCKER_PASSWORD }}" # docker-username: "${{ env.DOCKER_LOGIN }}" # - name: restore_cache -# uses: actions/cache@v3.3.1 +# uses: actions/cache@v3.3.2 # with: # key: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} # restore-keys: linux-go-${{ hashFiles('go.sum') }}-${{ env.cache-key }} From 1d825be67a26e5a83405469a1d901daf181f144f Mon Sep 17 00:00:00 2001 From: Florian Ritterhoff <32478819+fritterhoff@users.noreply.github.com> Date: Thu, 14 Sep 2023 19:15:54 +0200 Subject: [PATCH 50/79] NEW FEATURE: Added "push --report" flag which generates JSON report of changes made (#2543) Co-authored-by: Tom Limoncelli --- commands/previewPush.go | 46 ++++++++++++++++++++++++++++++++--- documentation/SUMMARY.md | 1 + documentation/json-reports.md | 34 ++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 documentation/json-reports.md diff --git a/commands/previewPush.go b/commands/previewPush.go index c1915deac..70b1d4370 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -1,6 +1,7 @@ package commands import ( + "encoding/json" "fmt" "os" "strings" @@ -45,6 +46,13 @@ type PreviewArgs struct { Full bool } +type ReportItem struct { + Domain string `json:"domain"` + Corrections int `json:"corrections"` + Provider string `json:"provider,omitempty"` + Registrar string `json:"registrar,omitempty"` +} + func (args *PreviewArgs) flags() []cli.Flag { flags := args.GetDNSConfigArgs.flags() flags = append(flags, args.GetCredentialsArgs.flags()...) @@ -93,6 +101,7 @@ var _ = cmd(catMain, func() *cli.Command { type PushArgs struct { PreviewArgs Interactive bool + Report string } func (args *PushArgs) flags() []cli.Flag { @@ -102,21 +111,26 @@ func (args *PushArgs) flags() []cli.Flag { Destination: &args.Interactive, Usage: "Interactive. Confirm or Exclude each correction before they run", }) + flags = append(flags, &cli.StringFlag{ + Name: "report", + Destination: &args.Report, + Usage: `Generate a machine-parseable report of performed corrections.`, + }) return flags } // Preview implements the preview subcommand. func Preview(args PreviewArgs) error { - return run(args, false, false, printer.DefaultPrinter) + return run(args, false, false, printer.DefaultPrinter, nil) } // Push implements the push subcommand. func Push(args PushArgs) error { - return run(args.PreviewArgs, true, args.Interactive, printer.DefaultPrinter) + return run(args.PreviewArgs, true, args.Interactive, printer.DefaultPrinter, &args.Report) } // run is the main routine common to preview/push -func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { +func run(args PreviewArgs, push bool, interactive bool, out printer.CLI, report *string) error { // TODO: make truly CLI independent. Perhaps return results on a channel as they occur // This is a hack until we have the new printer replacement. @@ -151,7 +165,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { // create a WaitGroup with the length of domains for the anonymous functions (later goroutines) to wait for var wg sync.WaitGroup wg.Add(len(cfg.Domains)) - + var reportItems []ReportItem // For each domain in dnsconfig.js... for _, domain := range cfg.Domains { // Run preview or push operations per domain as anonymous function, in preparation for the later use of goroutines. @@ -232,6 +246,11 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { totalCorrections += len(corrections) // When diff1 goes away, the call to printReports() should be moved to HERE. //printReports(domain.Name, provider.Name, reports, out, push, notifier) + reportItems = append(reportItems, ReportItem{ + Domain: domain.Name, + Corrections: len(corrections), + Provider: provider.Name, + }) anyErrors = printOrRunCorrections(domain.Name, provider.Name, corrections, out, push, interactive, notifier) || anyErrors } @@ -253,6 +272,11 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { return } totalCorrections += len(corrections) + reportItems = append(reportItems, ReportItem{ + Domain: domain.Name, + Corrections: len(corrections), + Registrar: domain.RegistrarName, + }) anyErrors = printOrRunCorrections(domain.Name, domain.RegistrarName, corrections, out, push, interactive, notifier) || anyErrors }(domain) } @@ -269,6 +293,20 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { if totalCorrections != 0 && args.WarnChanges { return fmt.Errorf("there are pending changes") } + if report != nil { + f, err := os.OpenFile(*report, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer f.Close() + b, err := json.MarshalIndent(reportItems, "", " ") + if err != nil { + return err + } + if _, err := f.Write(b); err != nil { + return err + } + } return nil } diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index 050ec85c3..3ff6172a7 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -154,6 +154,7 @@ * [Nameservers and Delegations](nameservers.md) * [Notifications](notifications.md) * [Useful code tricks](code-tricks.md) +* [JSON Reports](json-reports.md) ## Developer info diff --git a/documentation/json-reports.md b/documentation/json-reports.md new file mode 100644 index 000000000..e6efa7928 --- /dev/null +++ b/documentation/json-reports.md @@ -0,0 +1,34 @@ +# JSON Reports + +DNSControl has build in functionality to generate a machine-parseable report after pushing changes. This report is JSON formated and contains the zonename, the provider or registrar name and the amount of performed changes. + +## Usage + +To enable the report option you must use the `push` operation in combination with the `--report ` option. This generates the json file. + +{% code title="report.json" %} +```json +[ + { + "domain": "private.example.com", + "corrections": 10, + "provider": "bind" + }, + { + "domain": "private.example.com", + "corrections": 0, + "registrar": "none" + }, + { + "domain": "admin.example.com", + "corrections": 5, + "provider": "bind" + }, + { + "domain": "admin.example.com", + "corrections": 0, + "registrar": "none" + } +] +``` +{% endcode %} From 255e08cff2c64b6e1a871c456fdeccc64799780c Mon Sep 17 00:00:00 2001 From: str4d Date: Thu, 14 Sep 2023 18:17:02 +0100 Subject: [PATCH 51/79] PORKBUN: Add registrar support (#2542) Co-authored-by: Tom Limoncelli --- documentation/providers.md | 2 +- providers/porkbun/api.go | 39 ++++++++++++++++++++---- providers/porkbun/porkbunProvider.go | 44 ++++++++++++++++++++++++++-- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/documentation/providers.md b/documentation/providers.md index d9a37484f..daa8edce8 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -53,7 +53,7 @@ If a feature is definitively not supported for whatever reason, we would also li | [`ORACLE`](providers/oracle.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | | [`OVH`](providers/ovh.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❔ | ❔ | ❌ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ❌ | ✅ | ✅ | | [`PACKETFRAME`](providers/packetframe.md) | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ❔ | -| [`PORKBUN`](providers/porkbun.md) | ❌ | ✅ | ❌ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | +| [`PORKBUN`](providers/porkbun.md) | ❌ | ✅ | ✅ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | | [`POWERDNS`](providers/powerdns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | [`ROUTE53`](providers/route53.md) | ✅ | ✅ | ✅ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | | [`RWTH`](providers/rwth.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ✅ | ❌ | ❔ | ❌ | ❌ | ✅ | ✅ | diff --git a/providers/porkbun/api.go b/providers/porkbun/api.go index 9c083f926..3145319af 100644 --- a/providers/porkbun/api.go +++ b/providers/porkbun/api.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "sort" "time" ) @@ -18,7 +19,7 @@ type porkbunProvider struct { secretKey string } -type requestParams map[string]string +type requestParams map[string]any type errorResponse struct { Status string `json:"status"` @@ -40,6 +41,11 @@ type recordResponse struct { Records []domainRecord `json:"records"` } +type nsResponse struct { + Status string `json:"status"` + Nameservers []string `json:"ns"` +} + func (c *porkbunProvider) post(endpoint string, params requestParams) ([]byte, error) { params["apikey"] = c.apiKey params["secretapikey"] = c.secretKey @@ -82,7 +88,7 @@ func (c *porkbunProvider) ping() error { func (c *porkbunProvider) createRecord(domain string, rec requestParams) error { if _, err := c.post("/dns/create/"+domain, rec); err != nil { - return fmt.Errorf("failed create record (porkbun): %s", err) + return fmt.Errorf("failed create record (porkbun): %w", err) } return nil } @@ -90,14 +96,14 @@ func (c *porkbunProvider) createRecord(domain string, rec requestParams) error { func (c *porkbunProvider) deleteRecord(domain string, recordID string) error { params := requestParams{} if _, err := c.post(fmt.Sprintf("/dns/delete/%s/%s", domain, recordID), params); err != nil { - return fmt.Errorf("failed delete record (porkbun): %s", err) + return fmt.Errorf("failed delete record (porkbun): %w", err) } return nil } func (c *porkbunProvider) modifyRecord(domain string, recordID string, rec requestParams) error { if _, err := c.post(fmt.Sprintf("/dns/edit/%s/%s", domain, recordID), rec); err != nil { - return fmt.Errorf("failed update (porkbun): %s", err) + return fmt.Errorf("failed update (porkbun): %w", err) } return nil } @@ -106,7 +112,7 @@ func (c *porkbunProvider) getRecords(domain string) ([]domainRecord, error) { params := requestParams{} var bodyString, err = c.post("/dns/retrieve/"+domain, params) if err != nil { - return nil, fmt.Errorf("failed fetching record list from porkbun: %s", err) + return nil, fmt.Errorf("failed fetching record list from porkbun: %w", err) } var dr recordResponse @@ -121,3 +127,26 @@ func (c *porkbunProvider) getRecords(domain string) ([]domainRecord, error) { } return records, nil } + +func (c *porkbunProvider) getNameservers(domain string) ([]string, error) { + params := requestParams{} + var bodyString, err = c.post(fmt.Sprintf("/domain/getNs/%s", domain), params) + if err != nil { + return nil, fmt.Errorf("failed fetching nameserver list from porkbun: %w", err) + } + + var ns nsResponse + json.Unmarshal(bodyString, &ns) + + sort.Strings(ns.Nameservers) + return ns.Nameservers, nil +} + +func (c *porkbunProvider) updateNameservers(ns []string, domain string) error { + params := requestParams{} + params["ns"] = ns + if _, err := c.post(fmt.Sprintf("/domain/updateNs/%s", domain), params); err != nil { + return fmt.Errorf("failed NS update (porkbun): %w", err) + } + return nil +} diff --git a/providers/porkbun/porkbunProvider.go b/providers/porkbun/porkbunProvider.go index 1825a7550..0eddd1c9f 100644 --- a/providers/porkbun/porkbunProvider.go +++ b/providers/porkbun/porkbunProvider.go @@ -3,6 +3,7 @@ package porkbun import ( "encoding/json" "fmt" + "sort" "strconv" "strings" @@ -25,8 +26,16 @@ var defaultNS = []string{ "salvador.ns.porkbun.com", } -// NewPorkbun creates the provider. -func NewPorkbun(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { +func newReg(conf map[string]string) (providers.Registrar, error) { + return newPorkbun(conf, nil) +} + +func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { + return newPorkbun(conf, metadata) +} + +// newPorkbun creates the provider. +func newPorkbun(m map[string]string, metadata json.RawMessage) (*porkbunProvider, error) { c := &porkbunProvider{} c.apiKey, c.secretKey = m["api_key"], m["secret_key"] @@ -63,8 +72,9 @@ var features = providers.DocumentationNotes{ } func init() { + providers.RegisterRegistrarType("PORKBUN", newReg) fns := providers.DspFuncs{ - Initializer: NewPorkbun, + Initializer: newDsp, RecordAuditor: AuditRecords, } providers.RegisterDomainServiceProviderType("PORKBUN", fns, features) @@ -317,3 +327,31 @@ func fixTTL(ttl uint32) uint32 { } return minimumTTL } + +func (c *porkbunProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + nss, err := c.getNameservers(dc.Name) + if err != nil { + return nil, err + } + foundNameservers := strings.Join(nss, ",") + + expected := []string{} + for _, ns := range dc.Nameservers { + expected = append(expected, ns.Name) + } + sort.Strings(expected) + expectedNameservers := strings.Join(expected, ",") + + if foundNameservers == expectedNameservers { + return nil, nil + } + + return []*models.Correction{ + { + Msg: fmt.Sprintf("Update nameservers %s -> %s", foundNameservers, expectedNameservers), + F: func() error { + return c.updateNameservers(expected, dc.Name) + }, + }, + }, nil +} From 6ad7f348f7b634a1b70993d78ff083f7edfe2a81 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Fri, 15 Sep 2023 09:11:30 -0400 Subject: [PATCH 52/79] NEW RECORD TYPE: DHCID (#2557) Co-authored-by: Tom Limoncelli --- commands/types/dnscontrol.d.ts | 14 +++-- documentation/providers.md | 96 ++++++++++++++--------------- integrationTest/integration_test.go | 4 +- models/target.go | 2 +- 4 files changed, 59 insertions(+), 57 deletions(-) diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index e19bce20c..aa1aeada6 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -3054,7 +3054,7 @@ declare function URL301(name: string, ...modifiers: RecordModifier[]): DomainMod declare function getConfiguredDomains(): string[]; /** - * `require_glob()` can recursively load `.js` files, optionally non-recursive as well. + * `require_glob()` recursively loads `.js` files that match a glob (wildcard). The recursion can be disabled. * * Possible parameters are: * @@ -3073,8 +3073,13 @@ declare function getConfiguredDomains(): string[]; * require_glob("./domains/", false); * ``` * - * One more important thing to note: `require_glob()` is as smart as `require()` is. It loads files always relative to the JavaScript - * file where it's being executed in. Let's go with an example, as it describes it better: + * # Comparison to require() + * + * `require_glob()` and `require()` both use the same rules for determining which directory path is + * relative to. + * + * This will load files being present underneath `./domains/user1/` and **NOT** at below `./domains/`, as `require_glob()` + * is called in the subfolder `domains/`. * * ```javascript * require("domains/index.js"); @@ -3084,9 +3089,6 @@ declare function getConfiguredDomains(): string[]; * require_glob("./user1/"); * ``` * - * This will now load files being present underneath `./domains/user1/` and **NOT** at below `./domains/`, as `require_glob()` - * is called in the subfolder `domains/`. - * * @see https://docs.dnscontrol.org/language-reference/top-level-functions/require_glob */ declare function require_glob(path: string, recursive: boolean): void; diff --git a/documentation/providers.md b/documentation/providers.md index daa8edce8..4f2c37a2a 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -12,54 +12,54 @@ a provider that supports it, we'd love your contribution to ensure it works corr If a feature is definitively not supported for whatever reason, we would also like a PR to clarify why it is not supported, and fill in this entire matrix. -| Provider name | Official Support | DNS Provider | Registrar | [`ALIAS`](functions/domain/ALIAS.md) | [`CAA`](functions/domain/CAA.md) | [`AUTODNSSEC`](functions/domain/AUTODNSSEC_ON.md) | [`LOC`](functions/domain/LOC.md) | [`NAPTR`](functions/domain/NAPTR.md) | [`PTR`](functions/domain/PTR.md) | [`SOA`](functions/domain/SOA.md) | [`SRV`](functions/domain/SRV.md) | [`SSHFP`](functions/domain/SSHFP.md) | [`TLSA`](functions/domain/TLSA.md) | [`DS`](functions/domain/DS.md) | dual host | create-domains | [`NO_PURGE`](functions/domain/NO_PURGE.md) | get-zones | -| ------------- | ---------------- | ------------ | --------- | ------------------------------------ | -------------------------------- | ------------------------------------------------- | -------------------------------- | ------------------------------------ | -------------------------------- | -------------------------------- | -------------------------------- | ------------------------------------ | ---------------------------------- | ------------------------------ | --------- | -------------- | ------------------------------------------ | --------- | -| [`AKAMAIEDGEDNS`](providers/akamaiedgedns.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | -| [`AUTODNS`](providers/autodns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❔ | ❔ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | -| [`AXFRDDNS`](providers/axfrddns.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | -| [`AZURE_DNS`](providers/azure_dns.md) | ✅ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | -| [`BIND`](providers/bind.md) | ✅ | ✅ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | -| [`CLOUDFLAREAPI`](providers/cloudflareapi.md) | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ✅ | -| [`CLOUDNS`](providers/cloudns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | -| [`CSCGLOBAL`](providers/cscglobal.md) | ✅ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ✅ | -| [`DESEC`](providers/desec.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | -| [`DIGITALOCEAN`](providers/digitalocean.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | -| [`DNSIMPLE`](providers/dnsimple.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | -| [`DNSMADEEASY`](providers/dnsmadeeasy.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | -| [`DNSOVERHTTPS`](providers/dnsoverhttps.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | -| [`DOMAINNAMESHOP`](providers/domainnameshop.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | -| [`EASYNAME`](providers/easyname.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | -| [`EXOSCALE`](providers/exoscale.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❌ | ❔ | ❌ | ❌ | ✅ | ❔ | -| [`GANDI_V5`](providers/gandi_v5.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❌ | ❔ | ❌ | ❌ | ✅ | -| [`GCLOUD`](providers/gcloud.md) | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | -| [`GCORE`](providers/gcore.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | -| [`HEDNS`](providers/hedns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | -| [`HETZNER`](providers/hetzner.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| [`HEXONET`](providers/hexonet.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❔ | ❔ | ✅ | ❔ | ✅ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | -| [`HOSTINGDE`](providers/hostingde.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| [`INTERNETBS`](providers/internetbs.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | -| [`INWX`](providers/inwx.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | -| [`LINODE`](providers/linode.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ✅ | -| [`LOOPIA`](providers/loopia.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | -| [`LUADNS`](providers/luadns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | -| [`MSDNS`](providers/msdns.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ✅ | -| [`MYTHICBEASTS`](providers/mythicbeasts.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ❌ | ✅ | ✅ | -| [`NAMECHEAP`](providers/namecheap.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❌ | ❌ | ✅ | -| [`NAMEDOTCOM`](providers/namedotcom.md) | ❌ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ✅ | ❌ | ✅ | ✅ | -| [`NETCUP`](providers/netcup.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ❌ | -| [`NETLIFY`](providers/netlify.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | -| [`NS1`](providers/ns1.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | -| [`OPENSRS`](providers/opensrs.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | -| [`ORACLE`](providers/oracle.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | -| [`OVH`](providers/ovh.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❔ | ❔ | ❌ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ❌ | ✅ | ✅ | -| [`PACKETFRAME`](providers/packetframe.md) | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ❔ | -| [`PORKBUN`](providers/porkbun.md) | ❌ | ✅ | ✅ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | -| [`POWERDNS`](providers/powerdns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| [`ROUTE53`](providers/route53.md) | ✅ | ✅ | ✅ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | -| [`RWTH`](providers/rwth.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ✅ | ❌ | ❔ | ❌ | ❌ | ✅ | ✅ | -| [`SOFTLAYER`](providers/softlayer.md) | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❌ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | -| [`TRANSIP`](providers/transip.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ❌ | ❔ | ❌ | ✅ | ✅ | -| [`VULTR`](providers/vultr.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ✅ | ❌ | ❔ | ❔ | ✅ | ✅ | ✅ | +| Provider name | Official Support | DNS Provider | Registrar | [`ALIAS`](functions/domain/ALIAS.md) | [`CAA`](functions/domain/CAA.md) | [`AUTODNSSEC`](functions/domain/AUTODNSSEC_ON.md) | [`LOC`](functions/domain/LOC.md) | [`NAPTR`](functions/domain/NAPTR.md) | [`PTR`](functions/domain/PTR.md) | [`SOA`](functions/domain/SOA.md) | [`SRV`](functions/domain/SRV.md) | [`SSHFP`](functions/domain/SSHFP.md) | [`TLSA`](functions/domain/TLSA.md) | [`DS`](functions/domain/DS.md) | [`DHCID`](functions/domain/DHCID.md) | dual host | create-domains | [`NO_PURGE`](functions/domain/NO_PURGE.md) | get-zones | +| ------------- | ---------------- | ------------ | --------- | ------------------------------------ | -------------------------------- | ------------------------------------------------- | -------------------------------- | ------------------------------------ | -------------------------------- | -------------------------------- | -------------------------------- | ------------------------------------ | ---------------------------------- | ------------------------------ | ------------------------------------ | --------- | -------------- | ------------------------------------------ | --------- | +| [`AKAMAIEDGEDNS`](providers/akamaiedgedns.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❔ | ✅ | ✅ | ❌ | ✅ | +| [`AUTODNS`](providers/autodns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❔ | ❔ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ | ✅ | +| [`AXFRDDNS`](providers/axfrddns.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ❌ | ❌ | ❌ | ❌ | +| [`AZURE_DNS`](providers/azure_dns.md) | ✅ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`BIND`](providers/bind.md) | ✅ | ✅ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | +| [`CLOUDFLAREAPI`](providers/cloudflareapi.md) | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ✅ | ✅ | ✅ | +| [`CLOUDNS`](providers/cloudns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | +| [`CSCGLOBAL`](providers/cscglobal.md) | ✅ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ✅ | +| [`DESEC`](providers/desec.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | +| [`DIGITALOCEAN`](providers/digitalocean.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | +| [`DNSIMPLE`](providers/dnsimple.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ | ✅ | +| [`DNSMADEEASY`](providers/dnsmadeeasy.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❌ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`DNSOVERHTTPS`](providers/dnsoverhttps.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | +| [`DOMAINNAMESHOP`](providers/domainnameshop.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | +| [`EASYNAME`](providers/easyname.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | +| [`EXOSCALE`](providers/exoscale.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❌ | ❔ | ❔ | ❌ | ❌ | ✅ | ❔ | +| [`GANDI_V5`](providers/gandi_v5.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❌ | ❔ | ❔ | ❌ | ❌ | ✅ | +| [`GCLOUD`](providers/gcloud.md) | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`GCORE`](providers/gcore.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`HEDNS`](providers/hedns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`HETZNER`](providers/hetzner.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`HEXONET`](providers/hexonet.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❔ | ❔ | ✅ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ❔ | +| [`HOSTINGDE`](providers/hostingde.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`INTERNETBS`](providers/internetbs.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | +| [`INWX`](providers/inwx.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`LINODE`](providers/linode.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ✅ | +| [`LOOPIA`](providers/loopia.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❔ | ✅ | ❌ | ✅ | ✅ | +| [`LUADNS`](providers/luadns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`MSDNS`](providers/msdns.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ✅ | +| [`MYTHICBEASTS`](providers/mythicbeasts.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ❌ | ✅ | ✅ | +| [`NAMECHEAP`](providers/namecheap.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❔ | ❌ | ❌ | ❌ | ✅ | +| [`NAMEDOTCOM`](providers/namedotcom.md) | ❌ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ❌ | ✅ | ✅ | +| [`NETCUP`](providers/netcup.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ❌ | +| [`NETLIFY`](providers/netlify.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ | ✅ | +| [`NS1`](providers/ns1.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`OPENSRS`](providers/opensrs.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | +| [`ORACLE`](providers/oracle.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`OVH`](providers/ovh.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❔ | ❔ | ❌ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ❌ | ✅ | ✅ | +| [`PACKETFRAME`](providers/packetframe.md) | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ❔ | +| [`PORKBUN`](providers/porkbun.md) | ❌ | ✅ | ✅ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❔ | ❌ | ❌ | ✅ | ✅ | +| [`POWERDNS`](providers/powerdns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`ROUTE53`](providers/route53.md) | ✅ | ✅ | ✅ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`RWTH`](providers/rwth.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ✅ | ❌ | ❔ | ❔ | ❌ | ❌ | ✅ | ✅ | +| [`SOFTLAYER`](providers/softlayer.md) | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❌ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ | ❔ | +| [`TRANSIP`](providers/transip.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ❌ | ❔ | ❔ | ❌ | ✅ | ✅ | +| [`VULTR`](providers/vultr.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ✅ | ❌ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | ### Providers with "official support" diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 366898880..22d66a777 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -1558,8 +1558,8 @@ func makeTests(t *testing.T) []*TestGroup { // ns("another-child", "ns101.cloudns.net."), //), ), - testgroup("PTR", - requires(providers.CanUsePTR), + testgroup("DHCPID", + requires(providers.CanUseDHCID), tc("Create DHCPID record", dhcid("test", "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=")), tc("Modify DHCPID record", dhcid("test", "Test/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=")), ), diff --git a/models/target.go b/models/target.go index 6d3c38620..9a189d8ff 100644 --- a/models/target.go +++ b/models/target.go @@ -101,7 +101,7 @@ func (rc *RecordConfig) GetTargetSortable() string { func (rc *RecordConfig) GetTargetDebug() string { content := fmt.Sprintf("%s %s %s %d", rc.Type, rc.NameFQDN, rc.target, rc.TTL) switch rc.Type { // #rtype_variations - case "A", "AAAA", "CNAME", "NS", "PTR", "TXT", "AKAMAICDN": + case "A", "AAAA", "AKAMAICDN", "CNAME", "DHCID", "NS", "PTR", "TXT": // Nothing special. case "AZURE_ALIAS": content += fmt.Sprintf(" type=%s", rc.AzureAlias["type"]) From c01fb2d40b50df90db17729b8165b232ff534a11 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Fri, 15 Sep 2023 15:30:55 -0400 Subject: [PATCH 53/79] Update Deps, fix staticcheck and golint warnings (#2558) --- go.mod | 14 +++--- go.sum | 52 ++++++-------------- integrationTest/integration_test.go | 56 +++++++++++----------- pkg/dnstree/dnstree.go | 9 ++-- pkg/notifications/telegram.go | 20 ++++---- providers/cloudflare/cloudflareProvider.go | 4 +- providers/cloudflare/rest.go | 4 +- providers/netlify/netlifyProvider.go | 4 -- providers/ns1/ns1Provider.go | 18 +++---- 9 files changed, 77 insertions(+), 104 deletions(-) diff --git a/go.mod b/go.mod index 87592f409..a666a2b22 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 - github.com/cloudflare/cloudflare-go v0.76.0 + github.com/cloudflare/cloudflare-go v0.77.0 github.com/digitalocean/godo v1.102.1 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 @@ -33,10 +33,10 @@ require ( github.com/hashicorp/vault/api v1.10.0 github.com/jarcoal/httpmock v1.0.8 // indirect github.com/jinzhu/copier v0.4.0 - github.com/miekg/dns v1.1.55 + github.com/miekg/dns v1.1.56 github.com/mittwald/go-powerdns v0.6.2 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 - github.com/nrdcg/goinwx v0.8.2 + github.com/nrdcg/goinwx v0.8.3 github.com/oracle/oci-go-sdk/v32 v32.0.0 github.com/ovh/go-ovh v1.1.0 github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d @@ -51,7 +51,7 @@ require ( github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 golang.org/x/net v0.15.0 golang.org/x/oauth2 v0.12.0 - google.golang.org/api v0.138.0 + google.golang.org/api v0.141.0 gopkg.in/ns1/ns1-go.v2 v2.7.8 ) @@ -100,8 +100,8 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/s2a-go v0.1.5 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect @@ -140,7 +140,7 @@ require ( golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 // indirect google.golang.org/grpc v1.57.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect diff --git a/go.sum b/go.sum index 2a16430c2..acb8bb383 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= @@ -33,7 +32,6 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc= github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= @@ -80,18 +78,12 @@ github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 h1:awE2kiwdJa409MC5i3OH9fJHCr2yE75yHuWWoA5zx8Q= github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5/go.mod h1:1usm1EQvugrIio3ODIAMrDG9NzA86AHIqhZCxJgNdxY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.76.0 h1:0YsPw0KHWJK2fpivzx38X5onurfM0GkanZtS8HAqlj0= -github.com/cloudflare/cloudflare-go v0.76.0/go.mod h1:5ocQT9qQ99QsT1Ii2751490Z5J+W/nv6jOj+lSAe4ug= +github.com/cloudflare/cloudflare-go v0.77.0 h1:bVUGkSKdXEz8+u2Yj3ASqZsqlcsPkeB+PDqVs9OE7TY= +github.com/cloudflare/cloudflare-go v0.77.0/go.mod h1:R+Q/Im0G0MzKJxj3eXOBBE8xpnchVA9tSiQwOEvfW4Y= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -113,8 +105,6 @@ github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6G github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/exoscale/egoscale v0.90.2 h1:oGSJy5Dxbcn5m5F0/DcnU4WXJg+2j3g+UgEu4yyKG9M= github.com/exoscale/egoscale v0.90.2/go.mod h1:NDhQbdGNKwnLVC2YGTB6ds9WIPw+V5ckvEEV8ho7pFE= @@ -172,7 +162,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -196,14 +185,14 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/s2a-go v0.1.5 h1:8IYp3w9nysqv3JH+NJgXJzGbDHzLOTj43BmSkp+O7qg= -github.com/google/s2a-go v0.1.5/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -214,7 +203,6 @@ github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfre github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 h1:/gx6joY4PjXUu6mKM4yx7yj9Ti6yP8ljOxY/Qt0J25g= github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038/go.mod h1:xKR3tvLne+vYYPH9d4DM8X9MKlNV2yXDEomxulcK218= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -326,8 +314,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -345,8 +333,8 @@ github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAA github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nrdcg/goinwx v0.8.2 h1:RmjiHlEA+lzi3toXyPSaE6hWnBQ0+G+1u7w8C6Fpp4g= -github.com/nrdcg/goinwx v0.8.2/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4= +github.com/nrdcg/goinwx v0.8.3 h1:ARgoqQ+HhKhOhsey1qwHfxBJ6tDfb42iHt3tqED6chU= +github.com/nrdcg/goinwx v0.8.3/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oracle/oci-go-sdk/v32 v32.0.0 h1:SSbzrQO3WRcPJEZ8+b3SFPYsPtkFM96clqrp03lrwbU= github.com/oracle/oci-go-sdk/v32 v32.0.0/go.mod h1:aZc4jC59IuNP3cr5y1nj555QvwojMX2nMJaBiozuuEs= @@ -374,7 +362,6 @@ github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08 github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0= github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= @@ -435,7 +422,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -446,7 +432,6 @@ golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -463,7 +448,6 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -476,18 +460,15 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -552,28 +533,24 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/api v0.138.0 h1:K/tVp05MxNVbHShRw9m7e9VJGdagNeTdMzqPH7AUqr0= -google.golang.org/api v0.138.0/go.mod h1:4xyob8CxC+0GChNBvEUAk8VBKNvYOTWM9T3v3UfRxuY= +google.golang.org/api v0.141.0 h1:Df6vfMgDoIM6ss0m7H4MPwFwY87WNXHfBIda/Bmfl4E= +google.golang.org/api v0.141.0/go.mod h1:iZqLkdPlXKyG0b90eu6KxVSE4D/ccRF2e/doKD2CnQQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 h1:o4LtQxebKIJ4vkzyhtD2rfUNZ20Zf0ik5YVP5E7G7VE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -619,7 +596,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 22d66a777..a40288104 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -37,13 +37,13 @@ func init() { // Helper constants/funcs for the CLOUDFLARE proxy testing: -func CF_PROXY_OFF() *TestCase { return tc("proxyoff", cfProxyA("prxy", "174.136.107.111", "off")) } -func CF_PROXY_ON() *TestCase { return tc("proxyon", cfProxyA("prxy", "174.136.107.111", "on")) } -func CF_PROXY_FULL1() *TestCase { return tc("proxyf1", cfProxyA("prxy", "174.136.107.111", "full")) } -func CF_PROXY_FULL2() *TestCase { return tc("proxyf2", cfProxyA("prxy", "174.136.107.222", "full")) } -func CF_CPROXY_OFF() *TestCase { return tc("cproxyoff", cfProxyCNAME("cproxy", "example.com.", "off")) } -func CF_CPROXY_ON() *TestCase { return tc("cproxyon", cfProxyCNAME("cproxy", "example.com.", "on")) } -func CF_CPROXY_FULL() *TestCase { return tc("cproxyf", cfProxyCNAME("cproxy", "example.com.", "full")) } +func CfProxyOff() *TestCase { return tc("proxyoff", cfProxyA("prxy", "174.136.107.111", "off")) } +func CfProxyOn() *TestCase { return tc("proxyon", cfProxyA("prxy", "174.136.107.111", "on")) } +func CfProxyFull1() *TestCase { return tc("proxyf1", cfProxyA("prxy", "174.136.107.111", "full")) } +func CfProxyFull2() *TestCase { return tc("proxyf2", cfProxyA("prxy", "174.136.107.222", "full")) } +func CfCProxyOff() *TestCase { return tc("cproxyoff", cfProxyCNAME("cproxy", "example.com.", "off")) } +func CfCProxyOn() *TestCase { return tc("cproxyon", cfProxyCNAME("cproxy", "example.com.", "on")) } +func CfCProxyFull() *TestCase { return tc("cproxyf", cfProxyCNAME("cproxy", "example.com.", "full")) } // --- @@ -1778,10 +1778,10 @@ func makeTests(t *testing.T) []*TestGroup { testgroup("CF_PROXY A create", only("CLOUDFLAREAPI"), - CF_PROXY_OFF(), clear(), - CF_PROXY_ON(), clear(), - CF_PROXY_FULL1(), clear(), - CF_PROXY_FULL2(), clear(), + CfProxyOff(), clear(), + CfProxyOn(), clear(), + CfProxyFull1(), clear(), + CfProxyFull2(), clear(), ), // These next testgroups attempt every possible transition between off, on, full1 and full2. @@ -1791,59 +1791,59 @@ func makeTests(t *testing.T) []*TestGroup { testgroup("CF_PROXY A off to X", only("CLOUDFLAREAPI"), //CF_PROXY_OFF(), CF_PROXY_OFF(), clear(), // redundant - CF_PROXY_OFF(), CF_PROXY_ON(), clear(), - CF_PROXY_OFF(), CF_PROXY_FULL1(), clear(), - CF_PROXY_OFF(), CF_PROXY_FULL2(), clear(), + CfProxyOff(), CfProxyOn(), clear(), + CfProxyOff(), CfProxyFull1(), clear(), + CfProxyOff(), CfProxyFull2(), clear(), ), testgroup("CF_PROXY A on to X", only("CLOUDFLAREAPI"), - CF_PROXY_ON(), CF_PROXY_OFF(), clear(), + CfProxyOn(), CfProxyOff(), clear(), //CF_PROXY_ON(), CF_PROXY_ON(), clear(), // redundant //CF_PROXY_ON(), CF_PROXY_FULL1().ExpectNoChanges(), clear(), // Removed for speed - CF_PROXY_ON(), CF_PROXY_FULL2(), clear(), + CfProxyOn(), CfProxyFull2(), clear(), ), testgroup("CF_PROXY A full1 to X", only("CLOUDFLAREAPI"), - CF_PROXY_FULL1(), CF_PROXY_OFF(), clear(), + CfProxyFull1(), CfProxyOff(), clear(), //CF_PROXY_FULL1(), CF_PROXY_ON().ExpectNoChanges(), clear(), // Removed for speed //CF_PROXY_FULL1(), CF_PROXY_FULL1(), clear(), // redundant - CF_PROXY_FULL1(), CF_PROXY_FULL2(), clear(), + CfProxyFull1(), CfProxyFull2(), clear(), ), testgroup("CF_PROXY A full2 to X", only("CLOUDFLAREAPI"), - CF_PROXY_FULL2(), CF_PROXY_OFF(), clear(), - CF_PROXY_FULL2(), CF_PROXY_ON(), clear(), - CF_PROXY_FULL2(), CF_PROXY_FULL1(), clear(), + CfProxyFull2(), CfProxyOff(), clear(), + CfProxyFull2(), CfProxyOn(), clear(), + CfProxyFull2(), CfProxyFull1(), clear(), //CF_PROXY_FULL2(), CF_PROXY_FULL2(), clear(), // redundant ), testgroup("CF_PROXY CNAME create", only("CLOUDFLAREAPI"), - CF_CPROXY_OFF(), clear(), - CF_CPROXY_ON(), clear(), - CF_CPROXY_FULL(), clear(), + CfCProxyOff(), clear(), + CfCProxyOn(), clear(), + CfCProxyFull(), clear(), ), testgroup("CF_PROXY CNAME off to X", only("CLOUDFLAREAPI"), //CF_CPROXY_OFF(), CF_CPROXY_OFF(), clear(), // redundant - CF_CPROXY_OFF(), CF_CPROXY_ON(), clear(), - CF_CPROXY_OFF(), CF_CPROXY_FULL(), clear(), + CfCProxyOff(), CfCProxyOn(), clear(), + CfCProxyOff(), CfCProxyFull(), clear(), ), testgroup("CF_PROXY CNAME on to X", only("CLOUDFLAREAPI"), - CF_CPROXY_ON(), CF_CPROXY_OFF(), clear(), + CfCProxyOn(), CfCProxyOff(), clear(), //CF_CPROXY_ON(), CF_CPROXY_ON(), clear(), // redundant //CF_CPROXY_ON(), CF_CPROXY_FULL().ExpectNoChanges(), clear(), // Removed for speed ), testgroup("CF_PROXY CNAME full to X", only("CLOUDFLAREAPI"), - CF_CPROXY_FULL(), CF_CPROXY_OFF(), clear(), + CfCProxyFull(), CfCProxyOff(), clear(), //CF_CPROXY_FULL(), CF_CPROXY_ON().ExpectNoChanges(), clear(), // Removed for speed //CF_CPROXY_FULL(), CF_CPROXY_FULL(), clear(), // redundant ), diff --git a/pkg/dnstree/dnstree.go b/pkg/dnstree/dnstree.go index a2ec2a520..d07a4bb59 100644 --- a/pkg/dnstree/dnstree.go +++ b/pkg/dnstree/dnstree.go @@ -17,6 +17,7 @@ func Create[T any]() *DomainTree[T] { } } +// DomainTree is a domain tree. type DomainTree[T any] domainNode[T] type domainNode[T any] struct { @@ -47,14 +48,14 @@ func (tree *DomainTree[T]) Set(fqdn string, data T) { } ptr := (*domainNode[T])(tree) - for iX := len(domainParts) - 1; iX > 0; iX -= 1 { + for iX := len(domainParts) - 1; iX > 0; iX-- { ptr = ptr.addIntermediate(domainParts[iX]) } ptr.addLeaf(domainParts[0], isWildcard, data) } -// Retrieves the attached data from a given FQDN. +// Get retrieves the attached data from a given FQDN. // The tree will return the data entry for the most specific FQDN entry. // If no entry is found Get will return the default value for the specific type. // @@ -69,7 +70,7 @@ func (tree *DomainTree[T]) Get(fqdn string) T { var mostSpecificNode *domainNode[T] ptr := (*domainNode[T])(tree) - for iX := len(domainParts) - 1; iX >= 0; iX -= 1 { + for iX := len(domainParts) - 1; iX >= 0; iX-- { node, ok := ptr.Children[domainParts[iX]] if !ok { if mostSpecificNode != nil { @@ -103,7 +104,7 @@ func (tree *DomainTree[T]) Has(fqdn string) bool { var mostSpecificNode *domainNode[T] ptr := (*domainNode[T])(tree) - for iX := len(domainParts) - 1; iX >= 0; iX -= 1 { + for iX := len(domainParts) - 1; iX >= 0; iX-- { node, ok := ptr.Children[domainParts[iX]] if !ok { return mostSpecificNode != nil diff --git a/pkg/notifications/telegram.go b/pkg/notifications/telegram.go index 5d081eacf..bdadda38a 100644 --- a/pkg/notifications/telegram.go +++ b/pkg/notifications/telegram.go @@ -10,11 +10,11 @@ import ( func init() { initers = append(initers, func(cfg map[string]string) Notifier { - if bot_token, ok := cfg["telegram_bot_token"]; ok { - if chat_id, ok := cfg["telegram_chat_id"]; ok { + if botToken, ok := cfg["telegram_bot_token"]; ok { + if chatID, ok := cfg["telegram_chat_id"]; ok { notifier := &telegramNotifier{ - BOT_TOKEN: bot_token, - CHAT_ID: chat_id, + BotToken: botToken, + ChatID: chatID, } return notifier } @@ -25,8 +25,8 @@ func init() { // telegramNotifier sends notifications to Telegram type telegramNotifier struct { - BOT_TOKEN string - CHAT_ID string + BotToken string + ChatID string } func (s *telegramNotifier) Notify(domain, provider, msg string, err error, preview bool) { @@ -35,9 +35,9 @@ func (s *telegramNotifier) Notify(domain, provider, msg string, err error, previ Text string `json:"text"` } - var url = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", s.BOT_TOKEN) + var url = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", s.BotToken) - payload.ChatID, _ = strconv.ParseInt(s.CHAT_ID, 10, 64) + payload.ChatID, _ = strconv.ParseInt(s.ChatID, 10, 64) if preview { payload.Text = fmt.Sprintf(`DNSControl preview: %s[%s] -** %s`, domain, provider, msg) @@ -47,9 +47,9 @@ func (s *telegramNotifier) Notify(domain, provider, msg string, err error, previ payload.Text = fmt.Sprintf(`DNSControl successfully ran correction for **%s[%s]** - %s`, domain, provider, msg) } - marshaled_payload, _ := json.Marshal(payload) + marshaledPayload, _ := json.Marshal(payload) - _, _ = http.Post(url, "application/json", bytes.NewBuffer(marshaled_payload)) + _, _ = http.Post(url, "application/json", bytes.NewBuffer(marshaledPayload)) } diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go index a310c4136..883725851 100644 --- a/providers/cloudflare/cloudflareProvider.go +++ b/providers/cloudflare/cloudflareProvider.go @@ -74,7 +74,7 @@ type cloudflareProvider struct { ignoredLabels []string manageRedirects bool manageWorkers bool - accountId string + accountID string cfClient *cloudflare.API } @@ -690,7 +690,7 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS // Check account data if set if m["accountid"] != "" { - api.accountId = m["accountid"] + api.accountID = m["accountid"] } debug, err := strconv.ParseBool(os.Getenv("CLOUDFLAREAPI_DEBUG")) diff --git a/providers/cloudflare/rest.go b/providers/cloudflare/rest.go index b2072b11e..0f6bebfec 100644 --- a/providers/cloudflare/rest.go +++ b/providers/cloudflare/rest.go @@ -66,7 +66,7 @@ func (c *cloudflareProvider) deleteRec(rec cloudflare.DNSRecord, domainID string } func (c *cloudflareProvider) createZone(domainName string) (string, error) { - zone, err := c.cfClient.CreateZone(context.Background(), domainName, false, cloudflare.Account{ID: c.accountId}, "full") + zone, err := c.cfClient.CreateZone(context.Background(), domainName, false, cloudflare.Account{ID: c.accountID}, "full") return zone.ID, err } @@ -443,7 +443,7 @@ func (c *cloudflareProvider) createTestWorker(workerName string) error { });`, } - _, err := c.cfClient.UploadWorker(context.Background(), cloudflare.AccountIdentifier(c.accountId), wp) + _, err := c.cfClient.UploadWorker(context.Background(), cloudflare.AccountIdentifier(c.accountID), wp) return err } diff --git a/providers/netlify/netlifyProvider.go b/providers/netlify/netlifyProvider.go index 203e3d61a..6b8b050fb 100644 --- a/providers/netlify/netlifyProvider.go +++ b/providers/netlify/netlifyProvider.go @@ -12,10 +12,6 @@ import ( "github.com/miekg/dns" ) -var nameServerSuffixes = []string{ - ".nsone.net.", -} - var features = providers.DocumentationNotes{ providers.CanAutoDNSSEC: providers.Cannot(), providers.CanGetZones: providers.Can(), diff --git a/providers/ns1/ns1Provider.go b/providers/ns1/ns1Provider.go index 28f1ec478..b642e0c7e 100644 --- a/providers/ns1/ns1Provider.go +++ b/providers/ns1/ns1Provider.go @@ -31,8 +31,8 @@ var docNotes = providers.DocumentationNotes{ providers.DocOfficiallySupported: providers.Cannot(), } -// Number of retries for API backend requests in case of StatusTooManyRequests responses -const CLIENT_RETRIES = 10 +// clientRetries is the number of retries for API backend requests in case of StatusTooManyRequests responses +const clientRetries = 10 func init() { fns := providers.DspFuncs{ @@ -69,7 +69,7 @@ func newProvider(creds map[string]string, meta json.RawMessage) (providers.DNSSe func (n *nsone) GetZone(domain string) (*dns.Zone, error) { for rtr := 0; ; rtr++ { z, httpResp, err := n.Zones.Get(domain, true) - if httpResp.StatusCode == http.StatusTooManyRequests && rtr < CLIENT_RETRIES { + if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { continue } return z, err @@ -87,7 +87,7 @@ func (n *nsone) EnsureZoneExists(domain string) error { return nil } // too many requests - retry w/out waiting. We specified rate limit strategy creating the client - if httpResp.StatusCode == http.StatusTooManyRequests && rtr < CLIENT_RETRIES { + if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { continue } return err @@ -147,7 +147,7 @@ func (n *nsone) GetZoneDNSSEC(domain string) (bool, error) { if err != nil && err == rest.ErrDNSECNotEnabled { return false, nil } - if httpResp.StatusCode == http.StatusTooManyRequests && rtr < CLIENT_RETRIES { + if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { continue } // any other errors not expected, let's surface them @@ -278,7 +278,7 @@ func (n *nsone) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecor func (n *nsone) add(recs models.Records, domain string) error { for rtr := 0; ; rtr++ { httpResp, err := n.Records.Create(buildRecord(recs, domain, "")) - if httpResp.StatusCode == http.StatusTooManyRequests && rtr < CLIENT_RETRIES { + if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { continue } return err @@ -292,7 +292,7 @@ func (n *nsone) remove(key models.RecordKey, domain string) error { for rtr := 0; ; rtr++ { httpResp, err := n.Records.Delete(domain, key.NameFQDN, key.Type) - if httpResp.StatusCode == http.StatusTooManyRequests && rtr < CLIENT_RETRIES { + if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { continue } return err @@ -302,7 +302,7 @@ func (n *nsone) remove(key models.RecordKey, domain string) error { func (n *nsone) modify(recs models.Records, domain string) error { for rtr := 0; ; rtr++ { httpResp, err := n.Records.Update(buildRecord(recs, domain, "")) - if httpResp.StatusCode == http.StatusTooManyRequests && rtr < CLIENT_RETRIES { + if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { continue } return err @@ -325,7 +325,7 @@ func (n *nsone) configureDNSSEC(domain string, enabled bool) error { z.DNSSEC = &enabled for rtr := 0; ; rtr++ { httpResp, err := n.Zones.Update(z) - if httpResp.StatusCode == http.StatusTooManyRequests && rtr < CLIENT_RETRIES { + if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { continue } return err From fa890063a18fb97470b1b4b47318e016bc2b5b85 Mon Sep 17 00:00:00 2001 From: imlonghao Date: Sun, 17 Sep 2023 03:52:59 +0800 Subject: [PATCH 54/79] BUG: Ensure report location is not empty (#2560) --- commands/previewPush.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/previewPush.go b/commands/previewPush.go index 70b1d4370..38b6a3543 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -293,7 +293,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI, report if totalCorrections != 0 && args.WarnChanges { return fmt.Errorf("there are pending changes") } - if report != nil { + if report != nil && *report != "" { f, err := os.OpenFile(*report, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { return err From 39445b1cadccfa4729428bc7e71f6613159b4d51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 10:57:44 -0400 Subject: [PATCH 55/79] Build(deps): Bump docker/setup-qemu-action from 2 to 3 (#2561) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/draft_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml index 82494ff90..a41517a85 100644 --- a/.github/workflows/draft_release.yml +++ b/.github/workflows/draft_release.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Checkout repo uses: actions/checkout@v4 From 08338b322306ce2db513348f0ad46c4de255c3ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 11:32:58 -0400 Subject: [PATCH 56/79] Build(deps): Bump docker/login-action from 2 to 3 (#2563) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tom Limoncelli --- .github/workflows/draft_release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml index a41517a85..4f9e9312f 100644 --- a/.github/workflows/draft_release.yml +++ b/.github/workflows/draft_release.yml @@ -27,13 +27,13 @@ jobs: # back one commit. - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} From bf94f193459e1df879e00cf221cd288169613dc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 11:34:59 -0400 Subject: [PATCH 57/79] Build(deps): Bump goreleaser/goreleaser-action from 4 to 5 (#2562) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tom Limoncelli --- .github/workflows/build.yml | 4 ++-- .github/workflows/draft_release.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d13048b13..f7363f33b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: id: build_binaries_tagged name: Build binaries (if tagged) if: github.ref_type == 'tag' - uses: goreleaser/goreleaser-action@v4 + uses: goreleaser/goreleaser-action@v5 with: distribution: goreleaser version: latest @@ -57,7 +57,7 @@ jobs: id: build_binaries_not_tagged name: Build binaries (not tagged) if: github.ref_type != 'tag' - uses: goreleaser/goreleaser-action@v4 + uses: goreleaser/goreleaser-action@v5 with: distribution: goreleaser version: latest diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml index 4f9e9312f..cd443ce40 100644 --- a/.github/workflows/draft_release.yml +++ b/.github/workflows/draft_release.yml @@ -59,7 +59,7 @@ jobs: - id: release name: Goreleaser release - uses: goreleaser/goreleaser-action@v4 + uses: goreleaser/goreleaser-action@v5 with: distribution: goreleaser version: latest From 08afef7f7c2c34674525f729f1b41edb06aa1667 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 20 Sep 2023 13:03:46 -0400 Subject: [PATCH 58/79] CHORE: Clean up checkRecordSetHasMultipleTTLs (#2565) --- pkg/normalize/validate.go | 6 ++---- pkg/normalize/validate_test.go | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 3b30cc34b..88c9b8578 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -12,7 +12,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/providers" "github.com/miekg/dns" "github.com/miekg/dns/dnsutil" - "golang.org/x/exp/slices" ) // Returns false if target does not validate. @@ -620,13 +619,12 @@ func checkRecordSetHasMultipleTTLs(records []*models.RecordConfig) (errs []error labels[i] = k i++ } - sort.Strings(labels) - slices.Compact(labels) + // NB(tlim): No need to de-dup labels. They come from map keys. - // Invert for a more clear error message: for _, label := range labels { if len(m[label]) > 1 { + // Invert for a more clear error message: r := make(map[string]map[uint32]bool) for ttl, rtypes := range m[label] { for rtype := range rtypes { diff --git a/pkg/normalize/validate_test.go b/pkg/normalize/validate_test.go index 528827f6c..0bd842014 100644 --- a/pkg/normalize/validate_test.go +++ b/pkg/normalize/validate_test.go @@ -411,7 +411,7 @@ func TestCheckRecordSetHasMultipleTTLs_err_3type_2ttl(t *testing.T) { } errs := checkRecordSetHasMultipleTTLs(records) if len(errs) != 0 { - t.Errorf("Expected 0 errors (differnt types, no errors), but got %d: %v", len(errs), errs) + t.Errorf("Expected 0 errors (different types, no errors), but got %d: %v", len(errs), errs) } } @@ -424,7 +424,7 @@ func TestCheckRecordSetHasMultipleTTLs_err_3type_3ttl(t *testing.T) { } errs := checkRecordSetHasMultipleTTLs(records) if len(errs) != 1 { - t.Errorf("Expected 0 errors (differnt types, 1 error), but got %d: %v", len(errs), errs) + t.Errorf("Expected 0 errors (different types, 1 error), but got %d: %v", len(errs), errs) } } From 69bf714852e6e757887376676410a561313ab2d0 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 26 Sep 2023 11:25:57 -0400 Subject: [PATCH 59/79] TESTING: handoff() tests should disable NO_PURGE (#2568) --- pkg/diff2/handsoff_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/diff2/handsoff_test.go b/pkg/diff2/handsoff_test.go index 94e315292..7f89fb82a 100644 --- a/pkg/diff2/handsoff_test.go +++ b/pkg/diff2/handsoff_test.go @@ -164,7 +164,7 @@ D("f.com", "none", A("foo3", "3.3.3.3", ENSURE_ABSENT_REC()), {}) ` - handsoffHelper(t, existingZone, desiredJs, true, ` + handsoffHelper(t, existingZone, desiredJs, false, ` IGNORED: FOREIGN: `) @@ -184,7 +184,7 @@ D("f.com", "none", IGNORE_NAME("foo3"), {}) ` - handsoffHelper(t, existingZone, desiredJs, true, ` + handsoffHelper(t, existingZone, desiredJs, false, ` IGNORED: foo3 A 3.3.3.3 foo3 MX 10 mymx.example.com. @@ -207,7 +207,7 @@ D("f.com", "none", IGNORE_NAME("foo3", "MX"), {}) ` - handsoffHelper(t, existingZone, desiredJs, true, ` + handsoffHelper(t, existingZone, desiredJs, false, ` IGNORED: foo3 MX 10 mymx.example.com. FOREIGN: @@ -228,7 +228,7 @@ D("f.com", "none", IGNORE_TARGET('**.acm-validations.aws.', 'CNAME'), {}) ` - handsoffHelper(t, existingZone, desiredJs, true, ` + handsoffHelper(t, existingZone, desiredJs, false, ` IGNORED: _2222222222222222.cr CNAME _333333.nnn.acm-validations.aws. FOREIGN: From 4e3f5f31c74af8ca6aa034a864c3a99d94a1856e Mon Sep 17 00:00:00 2001 From: Patrik Kernstock Date: Wed, 27 Sep 2023 14:13:07 +0100 Subject: [PATCH 60/79] INWX: Support up to 2,147,483,647 domains (old limit was 20) (#2566) Co-authored-by: Tom Limoncelli --- providers/inwx/inwxProvider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index 3c50f7c27..6768dd24f 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -402,6 +402,7 @@ func (api *inwxAPI) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models. // fetchNameserverDomains returns the domains configured in INWX nameservers func (api *inwxAPI) fetchNameserverDomains() error { request := &goinwx.DomainListRequest{} + request.PageLimit = 2147483647 // int32 max value, highest number API accepts info, err := api.client.Domains.List(request) if err != nil { return err From 2d6d536ade4b516f51d618f5ed2a97130fd74da3 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 28 Sep 2023 09:32:18 -0400 Subject: [PATCH 61/79] CHORE: Update deps (#2569) --- go.mod | 20 ++++++++++---------- go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index a666a2b22..d10617c9a 100644 --- a/go.mod +++ b/go.mod @@ -12,15 +12,15 @@ require ( github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 github.com/aws/aws-sdk-go-v2 v1.21.0 - github.com/aws/aws-sdk-go-v2/config v1.18.39 - github.com/aws/aws-sdk-go-v2/credentials v1.13.37 + github.com/aws/aws-sdk-go-v2/config v1.18.42 + github.com/aws/aws-sdk-go-v2/credentials v1.13.40 github.com/aws/aws-sdk-go-v2/service/route53 v1.29.5 github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.3 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 - github.com/cloudflare/cloudflare-go v0.77.0 + github.com/cloudflare/cloudflare-go v0.78.0 github.com/digitalocean/godo v1.102.1 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 @@ -51,7 +51,7 @@ require ( github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 golang.org/x/net v0.15.0 golang.org/x/oauth2 v0.12.0 - google.golang.org/api v0.141.0 + google.golang.org/api v0.143.0 gopkg.in/ns1/ns1-go.v2 v2.7.8 ) @@ -79,11 +79,11 @@ require ( github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.22.0 // indirect github.com/aws/smithy-go v1.14.2 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -102,7 +102,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.3.1 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -140,7 +140,7 @@ require ( golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect google.golang.org/grpc v1.57.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect diff --git a/go.sum b/go.sum index acb8bb383..f17552aca 100644 --- a/go.sum +++ b/go.sum @@ -35,30 +35,30 @@ github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEq github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc= github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= -github.com/aws/aws-sdk-go-v2/config v1.18.39 h1:oPVyh6fuu/u4OiW4qcuQyEtk7U7uuNBmHmJSLg1AJsQ= -github.com/aws/aws-sdk-go-v2/config v1.18.39/go.mod h1:+NH/ZigdPckFpgB1TRcRuWCB/Kbbvkxc/iNAKTq5RhE= -github.com/aws/aws-sdk-go-v2/credentials v1.13.37 h1:BvEdm09+ZEh2XtN+PVHPcYwKY3wIeB6pw7vPRM4M9/U= -github.com/aws/aws-sdk-go-v2/credentials v1.13.37/go.mod h1:ACLrdkd4CLZyXOghZ8IYumQbcooAcp2jo/s2xsFH8IM= +github.com/aws/aws-sdk-go-v2/config v1.18.42 h1:28jHROB27xZwU0CB88giDSjz7M1Sba3olb5JBGwina8= +github.com/aws/aws-sdk-go-v2/config v1.18.42/go.mod h1:4AZM3nMMxwlG+eZlxvBKqwVbkDLlnN2a4UGTL6HjaZI= +github.com/aws/aws-sdk-go-v2/credentials v1.13.40 h1:s8yOkDh+5b1jUDhMBtngF6zKWLDs84chUk2Vk0c38Og= +github.com/aws/aws-sdk-go-v2/credentials v1.13.40/go.mod h1:VtEHVAAqDWASwdOqj/1huyT6uHbs5s8FUHfDQdky/Rs= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 h1:g+qlObJH4Kn4n21g69DjspU0hKTjWtq7naZ9OLCv0ew= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= github.com/aws/aws-sdk-go-v2/service/route53 v1.29.5 h1:6wPin3WPyQpBl/QZsoNUnqvXy4Ib1Ygv7VagGvLKJAc= github.com/aws/aws-sdk-go-v2/service/route53 v1.29.5/go.mod h1:6zl0jh5MUKuJ07eHn3MNeLOVutxwl8m9vQltZjoLakM= github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.3 h1:aaHlZb06fyEQ3uqEVJiN3hLt8syCzX+tWZiz40S4c0Y= github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.3/go.mod h1:SK+5R1cYgVgSfBGi9T/gPGNIuLInF3eIRYNruia62rg= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 h1:2PylFCfKCEDv6PeSN09pC/VUiRd10wi1VfHG5FrW0/g= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.6/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 h1:pSB560BbVj9ZlJZF4WYj5zsytWHWKxg+NgyGV4B2L58= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= +github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 h1:YkNzx1RLS0F5qdf9v1Q8Cuv9NXCL2TkosOxhzlUPV64= +github.com/aws/aws-sdk-go-v2/service/sso v1.14.1/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 h1:8lKOidPkmSmfUtiTgtdXWgaKItCZ/g75/jEk6Ql6GsA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= +github.com/aws/aws-sdk-go-v2/service/sts v1.22.0 h1:s4bioTgjSFRwOoyEFzAVCmFmoowBgjTR8gkrF/sQ4wk= +github.com/aws/aws-sdk-go-v2/service/sts v1.22.0/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= @@ -81,8 +81,8 @@ github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5/go.mod github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.77.0 h1:bVUGkSKdXEz8+u2Yj3ASqZsqlcsPkeB+PDqVs9OE7TY= -github.com/cloudflare/cloudflare-go v0.77.0/go.mod h1:R+Q/Im0G0MzKJxj3eXOBBE8xpnchVA9tSiQwOEvfW4Y= +github.com/cloudflare/cloudflare-go v0.78.0 h1:xMPdjJ+e2tGNUkw5LyduPlsMCaILEoN1Kqq/uEMx78w= +github.com/cloudflare/cloudflare-go v0.78.0/go.mod h1:R+Q/Im0G0MzKJxj3eXOBBE8xpnchVA9tSiQwOEvfW4Y= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -193,8 +193,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -533,8 +533,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/api v0.141.0 h1:Df6vfMgDoIM6ss0m7H4MPwFwY87WNXHfBIda/Bmfl4E= -google.golang.org/api v0.141.0/go.mod h1:iZqLkdPlXKyG0b90eu6KxVSE4D/ccRF2e/doKD2CnQQ= +google.golang.org/api v0.143.0 h1:o8cekTkqhywkbZT6p1UHJPZ9+9uuCAJs/KYomxZB8fA= +google.golang.org/api v0.143.0/go.mod h1:FoX9DO9hT7DLNn97OuoZAGSDuNAXdJRuGK98rSUgurk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -542,10 +542,10 @@ google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= -google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 h1:o4LtQxebKIJ4vkzyhtD2rfUNZ20Zf0ik5YVP5E7G7VE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= +google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= From dd23e88f9fe622cb4df32b67d88e246d22d9df41 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Fri, 29 Sep 2023 19:48:40 +0200 Subject: [PATCH 62/79] DOCS: Align Docker command (#2571) --- documentation/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/getting-started.md b/documentation/getting-started.md index bc7dc51ba..80f2169b5 100644 --- a/documentation/getting-started.md +++ b/documentation/getting-started.md @@ -26,7 +26,7 @@ sudo port install dnscontrol You can use DNSControl locally using the Docker image from [Docker hub](https://hub.docker.com/r/stackexchange/dnscontrol/) or [Github Container Registry](https://github.com/stackexchange/dnscontrol/pkgs/container/dnscontrol) and the command below. ```shell - docker run --rm -it -v "$(pwd):/dns" ghcr.io/stackexchange/dnscontrol preview +docker run --rm -it -v "$(pwd):/dns" ghcr.io/stackexchange/dnscontrol preview ``` ### Binaries From e29642fb527eaebef43faf4619d891e655f91c6e Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Fri, 29 Sep 2023 19:50:42 +0200 Subject: [PATCH 63/79] DOCS: Typo GitHub (#2570) Co-authored-by: Tom Limoncelli --- documentation/getting-started.md | 2 +- documentation/providers/loopia.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/getting-started.md b/documentation/getting-started.md index 80f2169b5..9235b3c53 100644 --- a/documentation/getting-started.md +++ b/documentation/getting-started.md @@ -23,7 +23,7 @@ sudo port install dnscontrol ### Docker -You can use DNSControl locally using the Docker image from [Docker hub](https://hub.docker.com/r/stackexchange/dnscontrol/) or [Github Container Registry](https://github.com/stackexchange/dnscontrol/pkgs/container/dnscontrol) and the command below. +You can use DNSControl locally using the Docker image from [Docker hub](https://hub.docker.com/r/stackexchange/dnscontrol/) or [GitHub Container Registry](https://github.com/stackexchange/dnscontrol/pkgs/container/dnscontrol) and the command below. ```shell docker run --rm -it -v "$(pwd):/dns" ghcr.io/stackexchange/dnscontrol preview diff --git a/documentation/providers/loopia.md b/documentation/providers/loopia.md index a608cf1f1..034cc49e4 100644 --- a/documentation/providers/loopia.md +++ b/documentation/providers/loopia.md @@ -6,7 +6,7 @@ They provide support in English and other regional variants (Norwegian, Serbian, This plugin is based on API documents found at [https://www.loopia.com/api/](https://www.loopia.com/api/) -and by observing API responses. Hat tip to Github @hazzeh whose code for the +and by observing API responses. Hat tip to GitHub @hazzeh whose code for the LEGO Loopia implementation was helpful. Sadly the Loopia API has some problems: @@ -70,7 +70,7 @@ There is no test endpoint. Fly free, grasshopper. Turning on debug will show the XML requests and responses, and include the username and password from your `creds.json` file. If you want to share these, -like for a Github issue, be sure to redact those from the XML. +like for a GitHub issue, be sure to redact those from the XML. ### Fetch Apex NS Entries From 60949c3ca666c5e925dfe586c367defa481354db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:07:10 -0400 Subject: [PATCH 64/79] Build(deps): Bump alpine from 3.18.3 to 3.18.4 (#2574) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c2405e582..f392fc6ff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax = docker/dockerfile:1.4 -FROM alpine:3.18.3@sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a as RUN +FROM alpine:3.18.4@sha256:eece025e432126ce23f223450a0326fbebde39cdf496a85d8c016293fc851978 as RUN # Add runtime dependencies # - tzdata: Go time required external dependency eg: TRANSIP and possibly others From a87cf1787d64dd1ec6fcadf2ffbb7edc7878af88 Mon Sep 17 00:00:00 2001 From: Patrik Kernstock Date: Tue, 3 Oct 2023 18:31:59 +0100 Subject: [PATCH 65/79] INWX: Updated docs for limit up to 2,147,483,647 domains (#2579) --- documentation/providers/inwx.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/documentation/providers/inwx.md b/documentation/providers/inwx.md index b17f381ec..6df8d8fd7 100644 --- a/documentation/providers/inwx.md +++ b/documentation/providers/inwx.md @@ -5,7 +5,7 @@ INWX.de is a Berlin-based domain registrar. To use this provider, add an entry to `creds.json` with `TYPE` set to `INWX` along with your INWX username and password. -Example: +**Example:** {% code title="creds.json" %} ```json @@ -19,18 +19,19 @@ Example: ``` {% endcode %} -### Two factor authentication +### Two-factor authentication + +INWX supports two-factor authentication via TOTP and does not allow TOTP codes to be reused. This means that you will only be able to log into your INWX account once every 30 seconds. -INWX supports two factor authentication via TOTP and does not allow TOTP codes to be reused. This means that you will only be able to log into your INWX account once every 30 seconds. You will hit this limitation in the following two scenarios: * You run DNSControl twice very quickly (to e.g. first use preview and then push). Waiting for 30 seconds to pass between these two invocations will work fine though. -* You use INWX as both the registrar and the DNS provider. In this case, DNSControl will try to login twice too quickly and the second login will fail because a TOTP code will be reused. The only way to support this configuration is to use a INWX account without two factor authentication. +* You use INWX as both the registrar and the DNS provider. In this case, DNSControl will try to login twice too quickly and the second login will fail because a TOTP code will be reused. The only way to support this configuration is to use a INWX account without two-factor authentication. -If you cannot work around these two limitation it is possible to contact the INWX support to request a sub-account for API access only without two factor authentication. -See issue [issue 848](https://github.com/StackExchange/dnscontrol/issues/848#issuecomment-692288859) for details. +If you cannot work around these two limitation it is possible to create and manage sub-account - with specific permission sets - dedicated for API access with two-factor +authentication disabled. This is possible at [inwx.de/en/account](https://www.inwx.de/en/account). -If two factor authentication has been enabled you will also need to provide a valid TOTP number. +If two-factor authentication has been enabled you will also need to provide a valid TOTP number. This can also be done via an environment variable: {% code title="creds.json" %} @@ -53,11 +54,11 @@ INWX_TOTP=12345 dnscontrol preview ``` It is also possible to directly provide the shared TOTP secret using the key "totp-key" in `creds.json`. -This secret is only shown once when two factor authentication is enabled and you'll have to make sure to write it down then. +This secret is only shown once when two-factor authentication is enabled and you'll have to make sure to write it down then. **Important Notes**: * Anyone with access to this `creds.json` file will have *full* access to your INWX account and will be able to transfer and/or delete your domains -* Storing the shared secret together with the password weakens two factor authentication because both factors are stored in a single place. +* Storing the shared secret together with the password weakens two-factor authentication because both factors are stored in a single place. {% code title="creds.json" %} ```json @@ -73,8 +74,7 @@ This secret is only shown once when two factor authentication is enabled and you {% endcode %} ### Sandbox -You can optionally also specify sandbox with a value of 1 to -redirect all requests to the sandbox API instead: +You can optionally also specify sandbox with a value of 1 to redirect all requests to the sandbox API instead: {% code title="creds.json" %} ```json @@ -89,13 +89,10 @@ redirect all requests to the sandbox API instead: ``` {% endcode %} -If sandbox is omitted or set to any other value the production -API will be used. - +If sandbox is omitted or set to any other value the production API will be used. ## Metadata -This provider does not recognize any special metadata fields unique to -INWX. +This provider does not recognize any special metadata fields unique to INWX. ## Usage An example `dnsconfig.js` configuration file @@ -112,3 +109,7 @@ D("example.com", REG_INWX, DnsProvider(DSP_CF), ); ``` {% endcode %} + +**Note**: The INWX provider implementation currently only supports up to 2,147,483,647 domains. If you exceed +this limit, it is expected that dnscontrol will fail to recognize some domains. Should you exceed this +limit, please open an issue on GitHub. From 60f9e4f87f122fa121c4947164b879ffc853a905 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Tue, 3 Oct 2023 19:35:48 +0200 Subject: [PATCH 66/79] TESTING: un-skip TestDualProviders (#2576) Signed-off-by: Jakob Ackermann Co-authored-by: Tom Limoncelli --- integrationTest/integration_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index a40288104..69bed066d 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -348,7 +348,6 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string, } func TestDualProviders(t *testing.T) { - t.Skip() p, domain, _, _ := getProvider(t) if p == nil { return From 46f15114ddd26f4eae28dbffacd91ae0f8542192 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sun, 8 Oct 2023 11:33:19 -0400 Subject: [PATCH 67/79] IMPORT_TRANSFORM: Be more forgiving about non-standard rtypes (#2587) --- pkg/normalize/validate.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 88c9b8578..ad00650d6 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -263,7 +263,7 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra } return rec2 } - switch rec.Type { // #rtype_variations + switch rec.Type { case "A": trs, err := transform.IPToList(net.ParseIP(rec.GetTargetField()), transforms) if err != nil { @@ -278,14 +278,9 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra r := newRec() r.SetTarget(transformCNAME(r.GetTargetField(), srcDomain.Name, dstDomain.Name)) dstDomain.Records = append(dstDomain.Records, r) - case "AKAMAICDN", "MX", "NAPTR", "NS", "SOA", "SRV", "TXT", "CAA", "TLSA": - // Not imported. - continue - case "LOC": - continue default: - return fmt.Errorf("import_transform: Unimplemented record type %v (%v)", - rec.Type, rec.GetLabel()) + // Anything else is ignored. + continue } } return nil From e7f1872fd5f90f019268a153265f079446b73e65 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sun, 8 Oct 2023 11:33:42 -0400 Subject: [PATCH 68/79] CSCGLOBAL: Be silent about backoffs less than 10s (#2588) --- providers/cscglobal/api.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/providers/cscglobal/api.go b/providers/cscglobal/api.go index df141d753..dd8224013 100644 --- a/providers/cscglobal/api.go +++ b/providers/cscglobal/api.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io" - "log" "net/http" "os" "sort" @@ -665,7 +664,11 @@ retry: if string(bodyString) == "Requests exceeded API Rate limit." { // a simple exponential back-off with a 3-minute max. - log.Printf("Delaying %v due to ratelimit\n", backoff) + if backoff > 10 { + // With this provider backups seem to be pretty common. Only + // announce it when the problem gets really bad. + printer.Printf("Delaying %v due to ratelimit (CSCGLOBAL)\n", backoff) + } time.Sleep(backoff) backoff = backoff + (backoff / 2) if backoff > maxBackoff { From f661cd47779a433d7f26138a0b93c6e8246a0453 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Sun, 8 Oct 2023 17:35:53 +0200 Subject: [PATCH 69/79] DOCS: TypeScript improvements (#2586) Co-authored-by: Tom Limoncelli --- documentation/typescript.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/documentation/typescript.md b/documentation/typescript.md index 16db1f036..e1d3a92ab 100644 --- a/documentation/typescript.md +++ b/documentation/typescript.md @@ -25,9 +25,11 @@ dnscontrol write-types This file has all the information your editor or IDE needs. It must be in the same directory as the `dnsconfig.js` file you are editing. -NOTE: Re-run the `dnscontrol write-types` command any time you upgrade +{% hint style="info" %} +**NOTE**: Re-run the `dnscontrol write-types` command any time you upgrade DNSControl. Because it is generated from the command, it will always be correct for the version of DNSControl you are using. +{% endhint %} 2. Tell your editor @@ -50,15 +52,19 @@ If your editor requires extra steps, please [file a bug](https://github.com/Stac ### Bugs? -**Bugs?** Not all features of DNSControl work perfectly at the moment. Please report bugs and feature requests on https://github.com/StackExchange/dnscontrol/issues +{% hint style="warning" %} +**BUGS**: Not all features of DNSControl work perfectly at the moment. Please report bugs and feature requests on https://github.com/StackExchange/dnscontrol/issues +{% endhint %} -**This is experimental.** This feature is currently experimental. We might change the installation instructions as we find better ways to enable this. +{% hint style="info" %} +**NOTE**: This feature is currently experimental. We might change the installation instructions as we find better ways to enable this. +{% endhint %} -## Known bugs +## Known bugs/issue -## Bug: `CLI_DEFAULTS` not implemented +### Bug: `CLI_DEFAULTS` not implemented -Bug: Values passed to `CLI_DEFAULTS` (and the corresponding `-v` command-line option) don’t show up as global variables +Values passed to `CLI_DEFAULTS` (and the corresponding `-v` command-line option) don’t show up as global variables Workaround: create a new `.d.ts` file in the same folder as your `dnsconfig.js` file. In that file, add the following line for each variable you want to use (replacing `VARIABLE_NAME` with the name of the variable). @@ -71,7 +77,6 @@ declare const VARIABLE_NAME: string; This will tell TypeScript that the variable exists, and that it’s a string. -## Known issue: `FETCH` not always accurate - -Bug: `FETCH` is always shown as available, even if you don’t run DNSControl with the `--allow-fetch` flag. +### Known issue: `FETCH` not always accurate +`FETCH` is always shown as available, even if you don’t run DNSControl with the `--allow-fetch` flag. From 7e79713603410c301121ea8f7f40eaa6d2a91e67 Mon Sep 17 00:00:00 2001 From: Purrrpley <63091454+Purrrpley@users.noreply.github.com> Date: Mon, 9 Oct 2023 02:39:18 +1100 Subject: [PATCH 70/79] Fix the return types of `*_BUILDER` functions (#2583) Co-authored-by: Tom Limoncelli --- commands/types/dnscontrol.d.ts | 28 +++++++++---------- .../{record => domain}/CAA_BUILDER.md | 0 .../{record => domain}/DMARC_BUILDER.md | 0 .../{record => domain}/LOC_BUILDER_DD.md | 0 .../{record => domain}/LOC_BUILDER_DMM_STR.md | 0 .../{record => domain}/LOC_BUILDER_DMS_STR.md | 0 .../{record => domain}/LOC_BUILDER_STR.md | 0 .../{record => domain}/M365_BUILDER.md | 0 8 files changed, 14 insertions(+), 14 deletions(-) rename documentation/functions/{record => domain}/CAA_BUILDER.md (100%) rename documentation/functions/{record => domain}/DMARC_BUILDER.md (100%) rename documentation/functions/{record => domain}/LOC_BUILDER_DD.md (100%) rename documentation/functions/{record => domain}/LOC_BUILDER_DMM_STR.md (100%) rename documentation/functions/{record => domain}/LOC_BUILDER_DMS_STR.md (100%) rename documentation/functions/{record => domain}/LOC_BUILDER_STR.md (100%) rename documentation/functions/{record => domain}/M365_BUILDER.md (100%) diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index aa1aeada6..f91aedc10 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -409,9 +409,9 @@ declare function CAA(name: string, tag: "issue" | "issuewild" | "iodef", value: * CAA("@", "issuewild", ";") * ``` * - * @see https://docs.dnscontrol.org/language-reference/record-modifiers/caa_builder + * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/caa_builder */ -declare function CAA_BUILDER(opts: { label?: string; iodef: string; iodef_critical?: boolean; issue: string[]; issuewild: string }): RecordModifier; +declare function CAA_BUILDER(opts: { label?: string; iodef: string; iodef_critical?: boolean; issue: string[]; issuewild: string }): DomainModifier; /** * `CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to @@ -753,9 +753,9 @@ declare const DISABLE_IGNORE_SAFETY_CHECK: DomainModifier; * * TXT records are automatically split using `AUTOSPLIT`. * * URIs in the `rua` and `ruf` arrays are passed raw. You must percent-encode all commas and exclamation points in the URI itself. * - * @see https://docs.dnscontrol.org/language-reference/record-modifiers/dmarc_builder + * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/dmarc_builder */ -declare function DMARC_BUILDER(opts: { label?: string; version?: string; policy: 'none' | 'quarantine' | 'reject'; subdomainPolicy?: 'none' | 'quarantine' | 'reject'; alignmentSPF?: 'strict' | 's' | 'relaxed' | 'r'; alignmentDKIM?: 'strict' | 's' | 'relaxed' | 'r'; percent?: number; rua?: string[]; ruf?: string[]; failureOptions?: { SPF: boolean, DKIM: boolean } | string; failureFormat?: string; reportInterval?: Duration; ttl?: Duration }): RecordModifier; +declare function DMARC_BUILDER(opts: { label?: string; version?: string; policy: 'none' | 'quarantine' | 'reject'; subdomainPolicy?: 'none' | 'quarantine' | 'reject'; alignmentSPF?: 'strict' | 's' | 'relaxed' | 'r'; alignmentDKIM?: 'strict' | 's' | 'relaxed' | 'r'; percent?: number; rua?: string[]; ruf?: string[]; failureOptions?: { SPF: boolean, DKIM: boolean } | string; failureFormat?: string; reportInterval?: Duration; ttl?: Duration }): DomainModifier; /** * `DOMAIN_ELSEWHERE()` is a helper macro that lets you easily indicate that @@ -1561,9 +1561,9 @@ declare function LOC(deg1: number, min1: number, sec1: number, deg2: number, min * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works * - * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_dd + * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_dd */ -declare function LOC_BUILDER_DD(opts: { label?: string; x: number; y: number; alt?: number; ttl?: Duration }): RecordModifier; +declare function LOC_BUILDER_DD(opts: { label?: string; x: number; y: number; alt?: number; ttl?: Duration }): DomainModifier; /** * `LOC_BUILDER_DMM({})` actually takes an object with the following properties: @@ -1603,9 +1603,9 @@ declare function LOC_BUILDER_DD(opts: { label?: string; x: number; y: number; al * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works * - * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_dmm_str + * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_dmm_str */ -declare function LOC_BUILDER_DMM_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): RecordModifier; +declare function LOC_BUILDER_DMM_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): DomainModifier; /** * `LOC_BUILDER_DMS_STR({})` actually takes an object with the following properties: @@ -1646,9 +1646,9 @@ declare function LOC_BUILDER_DMM_STR(opts: { label?: string; str: string; alt?: * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works * - * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_dms_str + * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_dms_str */ -declare function LOC_BUILDER_DMS_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): RecordModifier; +declare function LOC_BUILDER_DMS_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): DomainModifier; /** * `LOC_BUILDER_STR({})` actually takes an object with the following: properties. @@ -1694,9 +1694,9 @@ declare function LOC_BUILDER_DMS_STR(opts: { label?: string; str: string; alt?: * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works * - * @see https://docs.dnscontrol.org/language-reference/record-modifiers/loc_builder_str + * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_str */ -declare function LOC_BUILDER_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): RecordModifier; +declare function LOC_BUILDER_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): DomainModifier; /** * DNSControl offers a `M365_BUILDER` which can be used to simply set up Microsoft 365 for a domain in an opinionated way. @@ -1743,9 +1743,9 @@ declare function LOC_BUILDER_STR(opts: { label?: string; str: string; alt?: numb * * `domainGUID` The GUID of _this_ Microsoft 365 domain (default: `
  • Step-by-Step Guide: Adding new DNS rtypes: How to add a new DNS record type