tstest/integration: test tailscale up when device approval is required

This patch extends the integration tests for `tailscale up` to include tailnets
where new devices need to be approved. It doesn't change the CLI, because it's
mostly working correctly already -- these tests are just to prevent future
regressions.

I've added support for `MachineAuthorized` to mock control, and I've refactored
`TestOneNodeUpAuth` to be more flexible. It now takes a sequence of steps to
run and asserts whether we got a login URL and/or machine approval URL after
each step.

Updates tailscale/corp#31476
Updates #17361

Signed-off-by: Alex Chan <alexc@tailscale.com>
This commit is contained in:
Alex Chan
2025-10-06 17:17:52 +01:00
committed by Alex Chan
parent 4543ea5c8a
commit 06f12186d9
3 changed files with 222 additions and 101 deletions

View File

@@ -1099,20 +1099,40 @@ func (tt *trafficTrap) ServeHTTP(w http.ResponseWriter, r *http.Request) {
type authURLParserWriter struct {
buf bytes.Buffer
fn func(urlStr string) error
// Handle login URLs, and count how many times they were seen
authURLFn func(urlStr string) error
// Handle machine approval URLs, and count how many times they were seen.
deviceApprovalURLFn func(urlStr string) error
}
// Note: auth URLs from testcontrol look slightly different to real auth URLs,
// e.g. http://127.0.0.1:60456/auth/96af2ff7e04ae1499a9a
var authURLRx = regexp.MustCompile(`(https?://\S+/auth/\S+)`)
// Looks for any device approval URL, which is any URL ending with `/admin`
// e.g. http://127.0.0.1:60456/admin
var deviceApprovalURLRx = regexp.MustCompile(`(https?://\S+/admin)[^\S]`)
func (w *authURLParserWriter) Write(p []byte) (n int, err error) {
n, err = w.buf.Write(p)
defer w.buf.Reset() // so it's not matched again
m := authURLRx.FindSubmatch(w.buf.Bytes())
if m != nil {
urlStr := string(m[1])
w.buf.Reset() // so it's not matched again
if err := w.fn(urlStr); err != nil {
if err := w.authURLFn(urlStr); err != nil {
return 0, err
}
}
m = deviceApprovalURLRx.FindSubmatch(w.buf.Bytes())
if m != nil && w.deviceApprovalURLFn != nil {
urlStr := string(m[1])
if err := w.deviceApprovalURLFn(urlStr); err != nil {
return 0, err
}
}
return n, err
}