fix: ensure app domain root matches server domain root
See coop-cloud/organising#495
This commit is contained in:
parent
906bf65d47
commit
b2a3d70ed3
1
go.mod
1
go.mod
|
@ -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
2
go.sum
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue