hscontrol: compare a waiting login when key expiry is turned off

SaaS answers a waiting login once an admin turns the device's key expiry
off, with the client's newest node key and no login. Headscale keeps
the login waiting.
This commit is contained in:
Kristoffer Dalby committed 2026-10-28 19:06:49 +00:00
1 parent b6541f7fa8
commit e2c4d559aa
2 files changed
+8 -19

No files matched your search

-7
View File
@@ -100,13 +100,6 @@ var apiv2CompatNotReplayed = map[string][]string{
"oauth/E9b": {"{key:K-E9b}"}, // uses E7's client
}
// notCompared reports whether key falls under one of prefixes.
func notCompared(prefixes []string, key string) bool {
return slices.ContainsFunc(prefixes, func(p string) bool {
return strings.HasPrefix(key, p)
})
}
// Differences no planned change removes yet.
const (
mintScopeRefusalStatus = "TOKEN_SCOPE_REFUSAL_STATUS: SaaS refuses a token scope the client lacks with 403 and a message; headscale with 400 invalid_scope"
+8 -12
View File
@@ -30,22 +30,22 @@ import (
// pendingLoginSkipReasons lists checks where headscale differs from SaaS,
// keyed <test_id>/<step>/<node>/<check>. A listed check that matches fails,
// so a fix must delete its entry.
var pendingLoginSkipReasons = map[string]string{}
// pendingLoginNotCompared lists, by key prefix, checks left out: SaaS's
// answer there is in doubt, so it is no reference.
var pendingLoginNotCompared = []string{
"pending-login/PL-E4-restore/pl-laptop/exchange-0",
"pending-login/PL-E4-restore/pl-laptop/devices",
var pendingLoginSkipReasons = map[string]string{
"pending-login/PL-E4-restore/pl-laptop/exchange-0": loginCompletedByRestore,
"pending-login/PL-E4-restore/pl-laptop/devices": loginCompletedByRestore,
}
// SaaS behaviour recorded as it is, not followed.
const loginCompletedByRestore = "LOGIN_COMPLETED_BY_RESTORE: SaaS completes a waiting login when the device's key expiry is turned off, giving it the client's newest node key without a login; headscale keeps the login waiting"
// TestPendingLoginCompat replays a fresh machine's interactive login across
// a restart and a stop, and an expired device restarted twice while its
// login waits, then restored. Each exchange the client logged is sent as the
// client sent it: same machine and node keys, follow-ups to the URL the
// server gave. It compares each answer's flags, whether an auth URL is new or
// repeats an earlier one, and the devices on each machine with their node
// key.
// key. The replay approves no login itself, so a waiting login that SaaS
// completed on restore shows in the follow-up's answer and the node key.
func TestPendingLoginCompat(t *testing.T) {
t.Parallel()
@@ -528,10 +528,6 @@ func renderNodeKeys(keys []string) string {
func (r *pendingReplay) hold(t *testing.T, prefix string, checks []pendingCheck) {
t.Helper()
checks = slices.DeleteFunc(checks, func(c pendingCheck) bool {
return notCompared(pendingLoginNotCompared, prefix+c.name)
})
const holdTicks = 5
got := make([]string, len(checks))