Skip to content

Commit

Permalink
Merge branch 'master' into hurl-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mohammed90 authored Oct 29, 2024
2 parents 9ba7ea7 + eaaa2e5 commit 05c2380
Show file tree
Hide file tree
Showing 108 changed files with 3,576 additions and 1,341 deletions.
43 changes: 40 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,35 @@ jobs:
# short sha is enough?
short_sha=$(git rev-parse --short HEAD)
# To shorten the following lines
ssh_opts="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
ssh_host="[email protected]"
# The environment is fresh, so there's no point in keeping accepting and adding the key.
rsync -arz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --progress --delete --exclude '.git' . "$CI_USER"@ci-s390x.caddyserver.com:/var/tmp/"$short_sha"
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t "$CI_USER"@ci-s390x.caddyserver.com "cd /var/tmp/$short_sha; go version; go env; printf "\n\n";CGO_ENABLED=0 go test -p 1 -tags nobadger -v ./..."
rsync -arz -e "ssh $ssh_opts" --progress --delete --exclude '.git' . "$ssh_host":/var/tmp/"$short_sha"
ssh $ssh_opts -t "$ssh_host" bash <<EOF
cd /var/tmp/$short_sha
go version
go env
printf "\n\n"
retries=3
exit_code=0
while ((retries > 0)); do
CGO_ENABLED=0 go test -p 1 -tags nobadger -v ./...
exit_code=$?
if ((exit_code == 0)); then
break
fi
echo "\n\nTest failed: \$exit_code, retrying..."
((retries--))
done
echo "Remote exit code: \$exit_code"
exit \$exit_code
EOF
test_result=$?
# There's no need leaving the files around
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$CI_USER"@ci-s390x.caddyserver.com "rm -rf /var/tmp/'$short_sha'"
ssh $ssh_opts "$ssh_host" "rm -rf /var/tmp/'$short_sha'"
echo "Test exit code: $test_result"
exit $test_result
Expand All @@ -271,3 +293,18 @@ jobs:
with:
version: latest
args: check
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: "~1.23"
check-latest: true
- name: Install xcaddy
run: |
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
xcaddy version
- uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: build --single-target --snapshot
env:
TAG: "master"
2 changes: 1 addition & 1 deletion .github/workflows/cross-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ jobs:
continue-on-error: true
working-directory: ./cmd/caddy
run: |
GOOS=$GOOS GOARCH=$GOARCH go build -tags nobadger -trimpath -o caddy-"$GOOS"-$GOARCH 2> /dev/null
GOOS=$GOOS GOARCH=$GOARCH go build -tags=nobadger,nomysql,nopgx -trimpath -o caddy-"$GOOS"-$GOARCH 2> /dev/null
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.60
version: latest

# Windows times out frequently after about 5m50s if we don't set a longer timeout.
args: --timeout 10m
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ jobs:
uses: anchore/sbom-action/download-syft@main
- name: Syft version
run: syft version
- name: Install xcaddy
run: |
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
xcaddy version
# GoReleaser will take care of publishing those artifacts into the release
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
Expand Down
10 changes: 9 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ linters:
- errcheck
- errname
- exhaustive
- exportloopref
- gci
- gofmt
- goimports
Expand Down Expand Up @@ -145,6 +144,9 @@ output:

issues:
exclude-rules:
- text: 'G115' # TODO: Either we should fix the issues or nuke the linter if it's bad
linters:
- gosec
# we aren't calling unknown URL
- text: 'G107' # G107: Url provided to HTTP request as taint input
linters:
Expand All @@ -169,6 +171,12 @@ issues:
- path: modules/logging/filters.go
linters:
- dupl
- path: modules/caddyhttp/matchers.go
linters:
- dupl
- path: modules/caddyhttp/vars.go
linters:
- dupl
- path: _test\.go
linters:
- errcheck
5 changes: 3 additions & 2 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ before:
- cp cmd/caddy/main.go caddy-build/main.go
- /bin/sh -c 'cd ./caddy-build && go mod init caddy'
# prepare syso files for windows embedding
- go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
- /bin/sh -c 'for a in amd64 arm arm64; do XCADDY_SKIP_BUILD=1 GOOS=windows GOARCH=$a $GOPATH/bin/xcaddy build {{.Env.TAG}}; done'
- /bin/sh -c 'for a in amd64 arm arm64; do XCADDY_SKIP_BUILD=1 GOOS=windows GOARCH=$a xcaddy build {{.Env.TAG}}; done'
- /bin/sh -c 'mv /tmp/buildenv_*/*.syso caddy-build'
# GoReleaser doesn't seem to offer {{.Tag}} at this stage, so we have to embed it into the env
# so we run: TAG=$(git describe --abbrev=0) goreleaser release --rm-dist --skip-publish --skip-validate
Expand Down Expand Up @@ -84,6 +83,8 @@ builds:
- -s -w
tags:
- nobadger
- nomysql
- nopgx

signs:
- cmd: cosign
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ $ xcaddy build
4. Initialize a Go module: `go mod init caddy`
5. (Optional) Pin Caddy version: `go get github.com/caddyserver/caddy/v2@version` replacing `version` with a git tag, commit, or branch name.
6. (Optional) Add plugins by adding their import: `_ "import/path/here"`
7. Compile: `go build`
7. Compile: `go build -tags=nobadger,nomysql,nopgx`



Expand Down
34 changes: 13 additions & 21 deletions admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"os"
"path"
"regexp"
"slices"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -213,7 +214,7 @@ type AdminPermissions struct {

// newAdminHandler reads admin's config and returns an http.Handler suitable
// for use in an admin endpoint server, which will be listening on listenAddr.
func (admin *AdminConfig) newAdminHandler(addr NetworkAddress, remote bool) adminHandler {
func (admin *AdminConfig) newAdminHandler(addr NetworkAddress, remote bool, ctx Context) adminHandler {
muxWrap := adminHandler{mux: http.NewServeMux()}

// secure the local or remote endpoint respectively
Expand Down Expand Up @@ -269,7 +270,6 @@ func (admin *AdminConfig) newAdminHandler(addr NetworkAddress, remote bool) admi
// register third-party module endpoints
for _, m := range GetModules("admin.api") {
router := m.New().(AdminRouter)
handlerLabel := m.ID.Name()
for _, route := range router.Routes() {
addRoute(route.Pattern, handlerLabel, route.Handler)
}
Expand Down Expand Up @@ -312,7 +312,7 @@ func (admin AdminConfig) allowedOrigins(addr NetworkAddress) []*url.URL {
}
if admin.Origins == nil {
if addr.isLoopback() {
if addr.IsUnixNetwork() {
if addr.IsUnixNetwork() || addr.IsFdNetwork() {
// RFC 2616, Section 14.26:
// "A client MUST include a Host header field in all HTTP/1.1 request
// messages. If the requested URI does not include an Internet host
Expand Down Expand Up @@ -350,7 +350,7 @@ func (admin AdminConfig) allowedOrigins(addr NetworkAddress) []*url.URL {
uniqueOrigins[net.JoinHostPort("127.0.0.1", addr.port())] = struct{}{}
}
}
if !addr.IsUnixNetwork() {
if !addr.IsUnixNetwork() && !addr.IsFdNetwork() {
uniqueOrigins[addr.JoinHostPort(0)] = struct{}{}
}
}
Expand Down Expand Up @@ -381,7 +381,9 @@ func (admin AdminConfig) allowedOrigins(addr NetworkAddress) []*url.URL {
// for the admin endpoint exists in cfg, a default one is used, so
// that there is always an admin server (unless it is explicitly
// configured to be disabled).
func replaceLocalAdminServer(cfg *Config) error {
// Critically note that some elements and functionality of the context
// may not be ready, e.g. storage. Tread carefully.
func replaceLocalAdminServer(cfg *Config, ctx Context) error {
// always* be sure to close down the old admin endpoint
// as gracefully as possible, even if the new one is
// disabled -- careful to use reference to the current
Expand Down Expand Up @@ -423,7 +425,7 @@ func replaceLocalAdminServer(cfg *Config) error {
return err
}

handler := cfg.Admin.newAdminHandler(addr, false)
handler := cfg.Admin.newAdminHandler(addr, false, ctx)

ln, err := addr.Listen(context.TODO(), 0, net.ListenConfig{})
if err != nil {
Expand Down Expand Up @@ -544,7 +546,7 @@ func replaceRemoteAdminServer(ctx Context, cfg *Config) error {

// make the HTTP handler but disable Host/Origin enforcement
// because we are using TLS authentication instead
handler := cfg.Admin.newAdminHandler(addr, true)
handler := cfg.Admin.newAdminHandler(addr, true, ctx)

// create client certificate pool for TLS mutual auth, and extract public keys
// so that we can enforce access controls at the application layer
Expand Down Expand Up @@ -675,13 +677,7 @@ func (remote RemoteAdmin) enforceAccessControls(r *http.Request) error {
// key recognized; make sure its HTTP request is permitted
for _, accessPerm := range adminAccess.Permissions {
// verify method
methodFound := accessPerm.Methods == nil
for _, method := range accessPerm.Methods {
if method == r.Method {
methodFound = true
break
}
}
methodFound := accessPerm.Methods == nil || slices.Contains(accessPerm.Methods, r.Method)
if !methodFound {
return APIError{
HTTPStatus: http.StatusForbidden,
Expand Down Expand Up @@ -877,13 +873,9 @@ func (h adminHandler) handleError(w http.ResponseWriter, r *http.Request, err er
// a trustworthy/expected value. This helps to mitigate DNS
// rebinding attacks.
func (h adminHandler) checkHost(r *http.Request) error {
var allowed bool
for _, allowedOrigin := range h.allowedOrigins {
if r.Host == allowedOrigin.Host {
allowed = true
break
}
}
allowed := slices.ContainsFunc(h.allowedOrigins, func(u *url.URL) bool {
return r.Host == u.Host
})
if !allowed {
return APIError{
HTTPStatus: http.StatusForbidden,
Expand Down
9 changes: 7 additions & 2 deletions caddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
func run(newCfg *Config, start bool) (Context, error) {
ctx, err := provisionContext(newCfg, start)
if err != nil {
globalMetrics.configSuccess.Set(0)
return ctx, err
}

Expand All @@ -410,6 +411,7 @@ func run(newCfg *Config, start bool) (Context, error) {
// some of the other apps at runtime
err = ctx.cfg.Admin.provisionAdminRouters(ctx)
if err != nil {
globalMetrics.configSuccess.Set(0)
return ctx, err
}

Expand All @@ -435,9 +437,11 @@ func run(newCfg *Config, start bool) (Context, error) {
return nil
}()
if err != nil {
globalMetrics.configSuccess.Set(0)
return ctx, err
}

globalMetrics.configSuccess.Set(1)
globalMetrics.configSuccessTime.SetToCurrentTime()
// now that the user's config is running, finish setting up anything else,
// such as remote admin endpoint, config loader, etc.
return ctx, finishSettingUp(ctx, ctx.cfg)
Expand Down Expand Up @@ -471,6 +475,7 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)
ctx, cancel := NewContext(Context{Context: context.Background(), cfg: newCfg})
defer func() {
if err != nil {
globalMetrics.configSuccess.Set(0)
// if there were any errors during startup,
// we should cancel the new context we created
// since the associated config won't be used;
Expand All @@ -497,7 +502,7 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)

// start the admin endpoint (and stop any prior one)
if replaceAdminServer {
err = replaceLocalAdminServer(newCfg)
err = replaceLocalAdminServer(newCfg, ctx)
if err != nil {
return ctx, fmt.Errorf("starting caddy administration endpoint: %v", err)
}
Expand Down
8 changes: 2 additions & 6 deletions caddyconfig/caddyfile/importgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package caddyfile

import (
"fmt"
"slices"
)

type adjacency map[string][]string
Expand Down Expand Up @@ -91,12 +92,7 @@ func (i *importGraph) areConnected(from, to string) bool {
if !ok {
return false
}
for _, v := range al {
if v == to {
return true
}
}
return false
return slices.Contains(al, to)
}

func (i *importGraph) willCycle(from, to string) bool {
Expand Down
9 changes: 7 additions & 2 deletions caddyconfig/caddyfile/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,13 @@ func (p *parser) addresses() error {
return p.Errf("Site addresses cannot contain a comma ',': '%s' - put a space after the comma to separate site addresses", value)
}

token.Text = value
p.block.Keys = append(p.block.Keys, token)
// After the above, a comma surrounded by spaces would result
// in an empty token which we should ignore
if value != "" {
// Add the token as a site address
token.Text = value
p.block.Keys = append(p.block.Keys, token)
}
}

// Advance token and possibly break out of loop or return error
Expand Down
8 changes: 6 additions & 2 deletions caddyconfig/caddyfile/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,10 @@ func TestParseAll(t *testing.T) {
{"localhost:1234", "http://host2"},
}},

{`foo.example.com , example.com`, false, [][]string{
{"foo.example.com", "example.com"},
}},

{`localhost:1234, http://host2,`, true, [][]string{}},

{`http://host1.com, http://host2.com {
Expand Down Expand Up @@ -614,8 +618,8 @@ func TestParseAll(t *testing.T) {
}
for j, block := range blocks {
if len(block.Keys) != len(test.keys[j]) {
t.Errorf("Test %d: Expected %d keys in block %d, got %d",
i, len(test.keys[j]), j, len(block.Keys))
t.Errorf("Test %d: Expected %d keys in block %d, got %d: %v",
i, len(test.keys[j]), j, len(block.Keys), block.Keys)
continue
}
for k, addr := range block.GetKeysText() {
Expand Down
Loading

0 comments on commit 05c2380

Please sign in to comment.