Fix 764 (#2093)
* Fix KeyExpiration when a zero time value has a timezone When a zero time value is loaded from JSON or a DB in a way that assigns it the local timezone, it does not roudtrip in JSON as a value for which IsZero returns true. This causes KeyExpiry to be treated as a far past value instead of a nilish value. See https://github.com/golang/go/issues/57040 * Fix whitespace * Ensure that postgresql is used for all tests when env var is set * Pass through value of HEADSCALE_INTEGRATION_POSTGRES env var * Add option to set timezone on headscale container * Add test for registration with auth key in alternate timezone
This commit is contained in:
parent
aa0f3d43cc
commit
3101f895a7
8 changed files with 91 additions and 7 deletions
1
.github/workflows/test-integration.yaml
vendored
1
.github/workflows/test-integration.yaml
vendored
|
@ -45,6 +45,7 @@ jobs:
|
||||||
- TestPingAllByIPPublicDERP
|
- TestPingAllByIPPublicDERP
|
||||||
- TestAuthKeyLogoutAndRelogin
|
- TestAuthKeyLogoutAndRelogin
|
||||||
- TestEphemeral
|
- TestEphemeral
|
||||||
|
- TestEphemeralInAlternateTimezone
|
||||||
- TestEphemeral2006DeletedTooQuickly
|
- TestEphemeral2006DeletedTooQuickly
|
||||||
- TestPingAllByHostname
|
- TestPingAllByHostname
|
||||||
- TestTaildrop
|
- TestTaildrop
|
||||||
|
|
|
@ -70,6 +70,8 @@ after improving the test harness as part of adopting [#1460](https://github.com/
|
||||||
- Make registration page easier to use on mobile devices
|
- Make registration page easier to use on mobile devices
|
||||||
- Make write-ahead-log default on and configurable for SQLite [#1985](https://github.com/juanfont/headscale/pull/1985)
|
- Make write-ahead-log default on and configurable for SQLite [#1985](https://github.com/juanfont/headscale/pull/1985)
|
||||||
- Add APIs for managing headscale policy. [#1792](https://github.com/juanfont/headscale/pull/1792)
|
- Add APIs for managing headscale policy. [#1792](https://github.com/juanfont/headscale/pull/1792)
|
||||||
|
- Fix for registering nodes using preauthkeys when running on a postgres database in a non-UTC timezone. [#764](https://github.com/juanfont/headscale/issues/764)
|
||||||
|
- Make sure integration tests cover postgres for all scenarios
|
||||||
|
|
||||||
## 0.22.3 (2023-05-12)
|
## 0.22.3 (2023-05-12)
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ func tailNode(
|
||||||
User: tailcfg.UserID(node.UserID),
|
User: tailcfg.UserID(node.UserID),
|
||||||
|
|
||||||
Key: node.NodeKey,
|
Key: node.NodeKey,
|
||||||
KeyExpiry: keyExpiry,
|
KeyExpiry: keyExpiry.UTC(),
|
||||||
|
|
||||||
Machine: node.MachineKey,
|
Machine: node.MachineKey,
|
||||||
DiscoKey: node.DiscoKey,
|
DiscoKey: node.DiscoKey,
|
||||||
|
@ -102,7 +102,7 @@ func tailNode(
|
||||||
Endpoints: node.Endpoints,
|
Endpoints: node.Endpoints,
|
||||||
DERP: derp,
|
DERP: derp,
|
||||||
Hostinfo: node.Hostinfo.View(),
|
Hostinfo: node.Hostinfo.View(),
|
||||||
Created: node.CreatedAt,
|
Created: node.CreatedAt.UTC(),
|
||||||
|
|
||||||
Online: node.IsOnline,
|
Online: node.IsOnline,
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package mapper
|
package mapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -205,3 +206,68 @@ func TestTailNode(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNodeExpiry(t *testing.T) {
|
||||||
|
tp := func(t time.Time) *time.Time {
|
||||||
|
return &t
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
exp *time.Time
|
||||||
|
wantTime time.Time
|
||||||
|
wantTimeZero bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no-expiry",
|
||||||
|
exp: nil,
|
||||||
|
wantTimeZero: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "zero-expiry",
|
||||||
|
exp: &time.Time{},
|
||||||
|
wantTimeZero: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "localtime",
|
||||||
|
exp: tp(time.Time{}.Local()),
|
||||||
|
wantTimeZero: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
node := &types.Node{
|
||||||
|
GivenName: "test",
|
||||||
|
Expiry: tt.exp,
|
||||||
|
}
|
||||||
|
tn, err := tailNode(
|
||||||
|
node,
|
||||||
|
0,
|
||||||
|
&policy.ACLPolicy{},
|
||||||
|
&types.Config{},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("nodeExpiry() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round trip the node through JSON to ensure the time is serialized correctly
|
||||||
|
seri, err := json.Marshal(tn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("nodeExpiry() error = %v", err)
|
||||||
|
}
|
||||||
|
var deseri tailcfg.Node
|
||||||
|
err = json.Unmarshal(seri, &deseri)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("nodeExpiry() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.wantTimeZero {
|
||||||
|
if !deseri.KeyExpiry.IsZero() {
|
||||||
|
t.Errorf("nodeExpiry() = %v, want zero", deseri.KeyExpiry)
|
||||||
|
}
|
||||||
|
} else if deseri.KeyExpiry != tt.wantTime {
|
||||||
|
t.Errorf("nodeExpiry() = %v, want %v", deseri.KeyExpiry, tt.wantTime)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -215,6 +215,14 @@ func TestAuthKeyLogoutAndRelogin(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEphemeral(t *testing.T) {
|
func TestEphemeral(t *testing.T) {
|
||||||
|
testEphemeralWithOptions(t, hsic.WithTestName("ephemeral"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEphemeralInAlternateTimezone(t *testing.T) {
|
||||||
|
testEphemeralWithOptions(t, hsic.WithTestName("ephemeral-tz"), hsic.WithTimezone("America/Los_Angeles"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEphemeralWithOptions(t *testing.T, opts ...hsic.Option) {
|
||||||
IntegrationSkip(t)
|
IntegrationSkip(t)
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
@ -227,7 +235,7 @@ func TestEphemeral(t *testing.T) {
|
||||||
"user2": len(MustTestVersions),
|
"user2": len(MustTestVersions),
|
||||||
}
|
}
|
||||||
|
|
||||||
headscale, err := scenario.Headscale(hsic.WithTestName("ephemeral"))
|
headscale, err := scenario.Headscale(opts...)
|
||||||
assertNoErrHeadscaleEnv(t, err)
|
assertNoErrHeadscaleEnv(t, err)
|
||||||
|
|
||||||
for userName, clientCount := range spec {
|
for userName, clientCount := range spec {
|
||||||
|
|
|
@ -211,6 +211,12 @@ func WithTuning(batchTimeout time.Duration, mapSessionChanSize int) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithTimezone(timezone string) Option {
|
||||||
|
return func(hsic *HeadscaleInContainer) {
|
||||||
|
hsic.env["TZ"] = timezone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// New returns a new HeadscaleInContainer instance.
|
// New returns a new HeadscaleInContainer instance.
|
||||||
func New(
|
func New(
|
||||||
pool *dockertest.Pool,
|
pool *dockertest.Pool,
|
||||||
|
|
|
@ -26,6 +26,7 @@ run_tests() {
|
||||||
--volume "$PWD:$PWD" -w "$PWD"/integration \
|
--volume "$PWD:$PWD" -w "$PWD"/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
--volume "$PWD"/control_logs:/tmp/control \
|
--volume "$PWD"/control_logs:/tmp/control \
|
||||||
|
-e "HEADSCALE_INTEGRATION_POSTGRES" \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-failfast \
|
-failfast \
|
||||||
|
|
|
@ -249,6 +249,10 @@ func (s *Scenario) Headscale(opts ...hsic.Option) (ControlServer, error) {
|
||||||
return headscale, nil
|
return headscale, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if usePostgresForTest {
|
||||||
|
opts = append(opts, hsic.WithPostgres())
|
||||||
|
}
|
||||||
|
|
||||||
headscale, err := hsic.New(s.pool, s.network, opts...)
|
headscale, err := hsic.New(s.pool, s.network, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create headscale container: %w", err)
|
return nil, fmt.Errorf("failed to create headscale container: %w", err)
|
||||||
|
@ -465,10 +469,6 @@ func (s *Scenario) CreateHeadscaleEnv(
|
||||||
tsOpts []tsic.Option,
|
tsOpts []tsic.Option,
|
||||||
opts ...hsic.Option,
|
opts ...hsic.Option,
|
||||||
) error {
|
) error {
|
||||||
if usePostgresForTest {
|
|
||||||
opts = append(opts, hsic.WithPostgres())
|
|
||||||
}
|
|
||||||
|
|
||||||
headscale, err := s.Headscale(opts...)
|
headscale, err := s.Headscale(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in a new issue