fix: ensure app domain root matches server domain root
continuous-integration/drone/push Build is failing Details
continuous-integration/drone/pr Build is failing Details

See coop-cloud/organising#495
This commit is contained in:
decentral1se 2023-09-29 13:24:02 +02:00
parent 906bf65d47
commit b2a3d70ed3
Signed by: decentral1se
GPG Key ID: 03789458B3D0C410
5 changed files with 161 additions and 5 deletions

1
go.mod
View File

@ -12,6 +12,7 @@ require (
github.com/docker/docker v24.0.6+incompatible
github.com/docker/go-units v0.5.0
github.com/go-git/go-git/v5 v5.9.0
github.com/joeguo/tldextract v0.0.0-20220507100122-d83daa6adef8
github.com/moby/sys/signal v0.7.0
github.com/moby/term v0.5.0
github.com/olekukonko/tablewriter v0.0.5

2
go.sum
View File

@ -626,6 +626,8 @@ github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
github.com/joeguo/tldextract v0.0.0-20220507100122-d83daa6adef8 h1:Ig0ESdy6JtHI17vsb7L+UlUFpoZctKfvBZplcILeL6g=
github.com/joeguo/tldextract v0.0.0-20220507100122-d83daa6adef8/go.mod h1:oGfutRjaB95239mjFVwofaOPTwuS3vb71ZLIGCEb36g=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=

View File

@ -3,6 +3,9 @@ package dns
import (
"fmt"
"net"
"strings"
"github.com/joeguo/tldextract"
)
// EnsureIPv4 ensures that an ipv4 address is set for a domain name
@ -21,6 +24,20 @@ func EnsureDomainsResolveSameIPv4(domainName, server string) (string, error) {
return "", nil
}
domainRoot, err := getDomainRoot(domainName)
if err != nil {
return "", err
}
serverRoot, err := getDomainRoot(server)
if err != nil {
return "", err
}
if domainRoot != serverRoot {
return "", fmt.Errorf("root of app domain (%s) does not match root of server domain (%s)?", domainRoot, serverRoot)
}
var ipv4 string
domainIPv4, err := EnsureIPv4(domainName)
@ -48,3 +65,26 @@ func EnsureDomainsResolveSameIPv4(domainName, server string) (string, error) {
return ipv4, nil
}
// getDomainRoot retrieves the root of a domain.
func getDomainRoot(domainName string) (string, error) {
var root string
cache := "/tmp/tld.cache" // NOTE(d1): https://github.com/joeguo/tldextract#example
extract, err := tldextract.New(cache, false)
if err != nil {
return root, fmt.Errorf("unable to initalise domain root parser: %s", err)
}
parsed := extract.Extract(domainName)
if parsed.Flag == 0 {
return root, fmt.Errorf("unable to parse %s for domain name checks (malformed)?", domainName)
}
if strings.TrimSpace(parsed.Root) == "" || strings.TrimSpace(parsed.Tld) == "" {
return root, fmt.Errorf("unable to parse %s for domain name checks?", domainName)
}
return fmt.Sprintf("%s.%s", parsed.Root, parsed.Tld), nil
}

67
pkg/dns/dns_test.go Normal file
View File

@ -0,0 +1,67 @@
package dns
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEnsureDomainsResolveSameIPv4(t *testing.T) {
tests := []struct {
domainName string
serverName string
shouldValidate bool
}{
// NOTE(d1): DNS records get checked, so use something we control. if
// you're here because of a failing test, try `dig +short <domain>` to
// ensure stuff matches first!
{"docs.coopcloud.tech", "coopcloud.tech", true},
{"docs.coopcloud.tech", "autonomic.zone", false},
{"", "default", true}, // NOTE(d1): special case of --local
{"", "local", true}, // NOTE(d1): special case of --local
{"DEFINITELY-DOESNT-EXIST.NOWHERE.EVER.HOPEFULLY.FOO", "", false},
{"", "", false},
{"123", "", false},
}
for _, test := range tests {
_, err := EnsureDomainsResolveSameIPv4(test.domainName, test.serverName)
if err != nil && test.shouldValidate {
t.Fatal(err)
}
if err == nil && !test.shouldValidate {
t.Fatal(fmt.Errorf("should have failed but did not: %v", test))
}
}
}
func TestGetDomainRoot(t *testing.T) {
tests := []struct {
domainName string
expectedRoot string
canParse bool
}{
{"foo.com", "foo.com", true},
{"bar.foo.com", "foo.com", true},
{"baz.bar.foo.com", "foo.com", true},
{"bing.baz.bar.foo.com", "foo.com", true},
{"", "", false},
{"123", "", false},
{"aaaaaaaaa", "", false},
}
for _, test := range tests {
root, err := getDomainRoot(test.domainName)
if err != nil && test.canParse {
t.Fatal(err)
} else {
assert.Equal(t, root, test.expectedRoot)
}
if err == nil && !test.canParse {
t.Fatal(fmt.Errorf("should have failed but did not: %v", test))
}
}
}

View File

@ -246,7 +246,7 @@ teardown(){
assert_not_exists "$ABRA_DIR/servers/$TEST_SERVER/gitea.$TEST_SERVER.env"
}
# bats test_tags=slow
# bats test_tags=slow,domain
@test "skip domain check if missing DOMAIN=" {
run cp "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env" "$BATS_TMPDIR/$TEST_APP_DOMAIN.env"
assert_success
@ -272,8 +272,10 @@ teardown(){
assert_success
}
@test "ensure domain is checked" {
appDomain="custom-html.DOESNTEXIST"
# bats test_tags=domain
@test "ensure app domain root matches server root" {
# NOTE(d1): *.example.com never matches *.$TEST_SERVER
appDomain="custom-html.example.com"
run $ABRA app new custom-html \
--no-input \
@ -284,10 +286,54 @@ teardown(){
run $ABRA app deploy "$appDomain" --no-input
assert_failure
assert_output --partial 'no such host'
assert_output --regexp 'root of app domain.*does not match root of server domain'
}
# bats test_tags=slow
# bats test_tags=domain
@test "ensure domain check for malformed url" {
appDomain="custom-html.is.malformed.url"
run $ABRA app new custom-html \
--no-input \
--server "$TEST_SERVER" \
--domain "$appDomain"
assert_success
assert_exists "$ABRA_DIR/servers/$TEST_SERVER/$appDomain.env"
run $ABRA app deploy "$appDomain" --no-input
assert_failure
assert_output --regexp 'malformed'
}
# bats test_tags=domain
@test "ensure domain check for non-existant domain" {
run mkdir -p "$ABRA_DIR/servers/DOESNTEXIST.com"
assert_success
assert_exists "$ABRA_DIR/servers/DOESNTEXIST.com"
run $ABRA app new custom-html \
--no-input \
--server "DOESNTEXIST.com" \
--domain "ch.DOESNTEXIST.com"
assert_success
assert_exists "$ABRA_DIR/servers/DOESNTEXIST.com/ch.DOESNTEXIST.com.env"
run docker context create --docker host=ssh://incorrect DOESNTEXIST.com
assert_success
run $ABRA app deploy ch.DOESNTEXIST.com --no-input
assert_failure
assert_output --regexp 'could not resolve'
run rm -rf "$ABRA_DIR/servers/DOESNTEXIST.com"
assert_success
assert_not_exists "$ABRA_DIR/servers/DOESNTEXIST.com"
run docker context rm DOESNTEXIST.com
assert_success
}
# bats test_tags=slow,domain
@test "skip domain check when requested" {
run $ABRA app deploy "$TEST_APP_DOMAIN" \
--no-input --no-converge-checks --no-domain-checks