diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7961281e..50501a0f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: actions: write # to allow uploading artifacts and cache steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit @@ -73,7 +73,7 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Install Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ matrix.GO_SEMVER }} check-latest: true @@ -162,7 +162,7 @@ jobs: continue-on-error: true # August 2020: s390x VM is down due to weather and power issues steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit allowed-endpoints: ci-s390x.caddyserver.com:22 @@ -221,7 +221,7 @@ jobs: if: github.event.pull_request.head.repo.full_name == 'caddyserver/caddy' && github.actor != 'dependabot[bot]' steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit @@ -233,7 +233,7 @@ jobs: version: latest args: check - name: Install Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: "~1.25" check-latest: true diff --git a/.github/workflows/cross-build.yml b/.github/workflows/cross-build.yml index b2e172833..8aa9eaf59 100644 --- a/.github/workflows/cross-build.yml +++ b/.github/workflows/cross-build.yml @@ -51,7 +51,7 @@ jobs: continue-on-error: true steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit @@ -59,7 +59,7 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Install Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ matrix.GO_SEMVER }} check-latest: true diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3d54bc546..849188c64 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -45,12 +45,12 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: '~1.25' check-latest: true @@ -73,7 +73,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit @@ -90,14 +90,14 @@ jobs: pull-requests: write steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit - name: 'Checkout Repository' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@595b5aeba73380359d98a5e087f648dbb0edce1b # v4.7.3 + uses: actions/dependency-review-action@56339e523c0409420f6c2c9a2f4292bbb3c07dd3 # v4.8.0 with: comment-summary-in-pr: on-failure # https://github.com/actions/dependency-review-action/issues/430#issuecomment-1468975566 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b72987e87..397df5ea2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit @@ -49,7 +49,7 @@ jobs: fetch-depth: 0 - name: Install Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ matrix.GO_SEMVER }} check-latest: true @@ -109,11 +109,11 @@ jobs: git verify-tag "${{ steps.vars.outputs.version_tag }}" || exit 1 - name: Install Cosign - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # main + uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # main - name: Cosign version run: cosign version - name: Install Syft - uses: anchore/sbom-action/download-syft@da167eac915b4e86f08b264dbdbc867b61be6f0c # main + uses: anchore/sbom-action/download-syft@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # main - name: Syft version run: syft version - name: Install xcaddy diff --git a/.github/workflows/release_published.yml b/.github/workflows/release_published.yml index 2ff313223..8afc5c35e 100644 --- a/.github/workflows/release_published.yml +++ b/.github/workflows/release_published.yml @@ -24,12 +24,12 @@ jobs: # See https://github.com/peter-evans/repository-dispatch - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit - name: Trigger event on caddyserver/dist - uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0 + uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0 with: token: ${{ secrets.REPO_DISPATCH_TOKEN }} repository: caddyserver/dist @@ -37,7 +37,7 @@ jobs: client-payload: '{"tag": "${{ github.event.release.tag_name }}"}' - name: Trigger event on caddyserver/caddy-docker - uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0 + uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0 with: token: ${{ secrets.REPO_DISPATCH_TOKEN }} repository: caddyserver/caddy-docker diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 43311829e..bb49f935d 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: egress-policy: audit @@ -47,7 +47,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif @@ -81,6 +81,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5 + uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.29.5 with: sarif_file: results.sarif diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 71aa0c2b8..228a64d38 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -481,7 +481,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) { // Validate DNS challenge config: any DNS challenge option except "dns" requires a DNS provider if acmeIssuer != nil && acmeIssuer.Challenges != nil && acmeIssuer.Challenges.DNS != nil { dnsCfg := acmeIssuer.Challenges.DNS - providerSet := dnsCfg.ProviderRaw != nil || h.Option("dns") != nil + providerSet := dnsCfg.ProviderRaw != nil || h.Option("dns") != nil || h.Option("acme_dns") != nil if len(dnsOptionsSet) > 0 && !providerSet { return nil, h.Errf( "setting DNS challenge options [%s] requires a DNS provider (set with the 'dns' subdirective or 'acme_dns' global option)", diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index eaeae66fa..30948f84f 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -565,23 +565,22 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e if globalACMECARoot != nil && !slices.Contains(acmeIssuer.TrustedRootsPEMFiles, globalACMECARoot.(string)) { acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, globalACMECARoot.(string)) } - if globalACMEDNSok { + if globalACMEDNSok && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.DNS == nil || acmeIssuer.Challenges.DNS.ProviderRaw == nil) { globalDNS := options["dns"] - if globalDNS != nil { - // If global `dns` is set, do NOT set provider in issuer, just set empty dns config - acmeIssuer.Challenges = &caddytls.ChallengesConfig{ - DNS: &caddytls.DNSChallengeConfig{}, - } - } else if globalACMEDNS != nil { - // Set a global DNS provider if `acme_dns` is set and `dns` is NOT set - acmeIssuer.Challenges = &caddytls.ChallengesConfig{ - DNS: &caddytls.DNSChallengeConfig{ - ProviderRaw: caddyconfig.JSONModuleObject(globalACMEDNS, "name", globalACMEDNS.(caddy.Module).CaddyModule().ID.Name(), nil), - }, - } - } else { + if globalDNS == nil && globalACMEDNS == nil { return fmt.Errorf("acme_dns specified without DNS provider config, but no provider specified with 'dns' global option") } + if acmeIssuer.Challenges == nil { + acmeIssuer.Challenges = new(caddytls.ChallengesConfig) + } + if acmeIssuer.Challenges.DNS == nil { + acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig) + } + // If global `dns` is set, do NOT set provider in issuer, just set empty dns config + if globalDNS == nil && acmeIssuer.Challenges.DNS.ProviderRaw == nil { + // Set a global DNS provider if `acme_dns` is set and `dns` is NOT set + acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(globalACMEDNS, "name", globalACMEDNS.(caddy.Module).CaddyModule().ID.Name(), nil) + } } if globalACMEEAB != nil && acmeIssuer.ExternalAccount == nil { acmeIssuer.ExternalAccount = globalACMEEAB.(*acme.EAB) diff --git a/caddytest/integration/caddyfile_adapt/acme_dns_configured.caddyfiletest b/caddytest/integration/caddyfile_adapt/acme_dns_configured.caddyfiletest index eaf8d0623..3f43a082a 100644 --- a/caddytest/integration/caddyfile_adapt/acme_dns_configured.caddyfiletest +++ b/caddytest/integration/caddyfile_adapt/acme_dns_configured.caddyfiletest @@ -53,6 +53,7 @@ example.com { "challenges": { "dns": { "provider": { + "argument": "foo", "name": "mock" } } diff --git a/caddytest/integration/caddyfile_adapt/tls_dns_override_acme_dns.caddyfiletest b/caddytest/integration/caddyfile_adapt/tls_dns_override_acme_dns.caddyfiletest new file mode 100644 index 000000000..2f7c6096a --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/tls_dns_override_acme_dns.caddyfiletest @@ -0,0 +1,79 @@ +{ + acme_dns mock foo +} + +localhost { + tls { + dns mock bar + resolvers 8.8.8.8 8.8.4.4 + } +} +---------- +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "terminal": true + } + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "subjects": [ + "localhost" + ], + "issuers": [ + { + "challenges": { + "dns": { + "provider": { + "argument": "bar", + "name": "mock" + }, + "resolvers": [ + "8.8.8.8", + "8.8.4.4" + ] + } + }, + "module": "acme" + } + ] + }, + { + "issuers": [ + { + "challenges": { + "dns": { + "provider": { + "argument": "foo", + "name": "mock" + } + } + }, + "module": "acme" + } + ] + } + ] + } + } + } +} diff --git a/caddytest/integration/caddyfile_adapt/tls_dns_override_global_dns.caddyfiletest b/caddytest/integration/caddyfile_adapt/tls_dns_override_global_dns.caddyfiletest new file mode 100644 index 000000000..fba67b566 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/tls_dns_override_global_dns.caddyfiletest @@ -0,0 +1,68 @@ +{ + dns mock foo +} + +localhost { + tls { + dns mock bar + resolvers 8.8.8.8 8.8.4.4 + } +} +---------- +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "terminal": true + } + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "subjects": [ + "localhost" + ], + "issuers": [ + { + "challenges": { + "dns": { + "provider": { + "argument": "bar", + "name": "mock" + }, + "resolvers": [ + "8.8.8.8", + "8.8.4.4" + ] + } + }, + "module": "acme" + } + ] + } + ] + }, + "dns": { + "argument": "foo", + "name": "mock" + } + } + } +} diff --git a/caddytest/integration/caddyfile_adapt/tls_dns_resolvers_with_global_provider.caddyfiletest b/caddytest/integration/caddyfile_adapt/tls_dns_resolvers_with_global_provider.caddyfiletest new file mode 100644 index 000000000..0292e8d07 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/tls_dns_resolvers_with_global_provider.caddyfiletest @@ -0,0 +1,76 @@ +{ + acme_dns mock +} + +localhost { + tls { + resolvers 8.8.8.8 8.8.4.4 + } +} +---------- +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "terminal": true + } + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "subjects": [ + "localhost" + ], + "issuers": [ + { + "challenges": { + "dns": { + "provider": { + "name": "mock" + }, + "resolvers": [ + "8.8.8.8", + "8.8.4.4" + ] + } + }, + "module": "acme" + } + ] + }, + { + "issuers": [ + { + "challenges": { + "dns": { + "provider": { + "name": "mock" + } + } + }, + "module": "acme" + } + ] + } + ] + } + } + } +} diff --git a/caddytest/integration/mockdns_test.go b/caddytest/integration/mockdns_test.go index 31dc4be7b..e55a6df58 100644 --- a/caddytest/integration/mockdns_test.go +++ b/caddytest/integration/mockdns_test.go @@ -15,7 +15,9 @@ func init() { } // MockDNSProvider is a mock DNS provider, for testing config with DNS modules. -type MockDNSProvider struct{} +type MockDNSProvider struct { + Argument string `json:"argument,omitempty"` // optional argument useful for testing +} // CaddyModule returns the Caddy module information. func (MockDNSProvider) CaddyModule() caddy.ModuleInfo { @@ -31,7 +33,15 @@ func (MockDNSProvider) Provision(ctx caddy.Context) error { } // UnmarshalCaddyfile sets up the module from Caddyfile tokens. -func (MockDNSProvider) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { +func (p *MockDNSProvider) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + d.Next() // consume directive name + + if d.NextArg() { + p.Argument = d.Val() + } + if d.NextArg() { + return d.Errf("unexpected argument '%s'", d.Val()) + } return nil }