feature/featuretags: make QR codes modular (#18358)

QR codes are used by `tailscale up --qr` to provide an easy way to
open a web-page without transcribing a difficult URI. However, there’s
no need for this feature if the client will never be called
interactively. So this PR adds the `ts_omit_qrcodes` build tag.

Updates #18182

Signed-off-by: Simon Law <sfllaw@tailscale.com>
This commit is contained in:
Simon Law
2026-01-08 10:28:40 -08:00
committed by GitHub
parent 6aac87a84c
commit 3e45e5b420
11 changed files with 103 additions and 37 deletions
+10 -6
View File
@@ -94,8 +94,10 @@ func newUpFlagSet(goos string, upArgs *upArgsT, cmd string) *flag.FlagSet {
// When adding new flags, prefer to put them under "tailscale set" instead
// of here. Setting preferences via "tailscale up" is deprecated.
upf.BoolVar(&upArgs.qr, "qr", false, "show QR code for login URLs")
upf.StringVar(&upArgs.qrFormat, "qr-format", string(qrcodes.FormatAuto), fmt.Sprintf("QR code formatting (%s, %s, %s, %s)", qrcodes.FormatAuto, qrcodes.FormatASCII, qrcodes.FormatLarge, qrcodes.FormatSmall))
if buildfeatures.HasQRCodes {
upf.BoolVar(&upArgs.qr, "qr", false, "show QR code for login URLs")
upf.StringVar(&upArgs.qrFormat, "qr-format", string(qrcodes.FormatAuto), fmt.Sprintf("QR code formatting (%s, %s, %s, %s)", qrcodes.FormatAuto, qrcodes.FormatASCII, qrcodes.FormatLarge, qrcodes.FormatSmall))
}
upf.StringVar(&upArgs.authKeyOrFile, "auth-key", "", `node authorization key; if it begins with "file:", then it's a path to a file containing the authkey`)
upf.StringVar(&upArgs.clientID, "client-id", "", "Client ID used to generate authkeys via workload identity federation")
upf.StringVar(&upArgs.clientSecretOrFile, "client-secret", "", `Client Secret used to generate authkeys via OAuth; if it begins with "file:", then it's a path to a file containing the secret`)
@@ -720,9 +722,11 @@ func runUp(ctx context.Context, cmd string, args []string, upArgs upArgsT) (retE
if upArgs.json {
js := &upOutputJSON{AuthURL: authURL, BackendState: st.BackendState}
png, err := qrcodes.EncodePNG(authURL, 128)
if err == nil {
js.QR = "data:image/png;base64," + base64.StdEncoding.EncodeToString(png)
if buildfeatures.HasQRCodes {
png, err := qrcodes.EncodePNG(authURL, 128)
if err == nil {
js.QR = "data:image/png;base64," + base64.StdEncoding.EncodeToString(png)
}
}
data, err := json.MarshalIndent(js, "", "\t")
@@ -733,7 +737,7 @@ func runUp(ctx context.Context, cmd string, args []string, upArgs upArgsT) (retE
}
} else {
fmt.Fprintf(Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", authURL)
if upArgs.qr {
if upArgs.qr && buildfeatures.HasQRCodes {
_, err := qrcodes.Fprintln(Stderr, qrcodes.Format(upArgs.qrFormat), authURL)
if err != nil {
log.Print(err)
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package main
import (
"testing"
"tailscale.com/tstest/deptest"
)
func TestOmitQRCodes(t *testing.T) {
const msg = "unexpected with ts_omit_qrcodes"
deptest.DepChecker{
GOOS: "linux",
GOARCH: "amd64",
Tags: "ts_omit_qrcodes",
BadDeps: map[string]string{
"github.com/skip2/go-qrcode": msg,
},
}.Check(t)
}
+2 -11
View File
@@ -33,9 +33,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
github.com/peterbourgon/ff/v3/ffcli from tailscale.com/cmd/tailscale/cli+
github.com/peterbourgon/ff/v3/internal from github.com/peterbourgon/ff/v3
💣 github.com/safchain/ethtool from tailscale.com/net/netkernelconf
github.com/skip2/go-qrcode from tailscale.com/util/qrcodes
github.com/skip2/go-qrcode/bitset from github.com/skip2/go-qrcode+
github.com/skip2/go-qrcode/reedsolomon from github.com/skip2/go-qrcode
💣 github.com/tailscale/wireguard-go/conn from github.com/tailscale/wireguard-go/device+
💣 github.com/tailscale/wireguard-go/device from tailscale.com/net/tstun+
github.com/tailscale/wireguard-go/ipc from github.com/tailscale/wireguard-go/device
@@ -193,7 +190,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/util/osshare from tailscale.com/cmd/tailscaled
tailscale.com/util/osuser from tailscale.com/ipn/ipnlocal+
tailscale.com/util/prompt from tailscale.com/cmd/tailscale/cli
💣 tailscale.com/util/qrcodes from tailscale.com/cmd/tailscale/cli
tailscale.com/util/qrcodes from tailscale.com/cmd/tailscale/cli
tailscale.com/util/race from tailscale.com/net/dns/resolver
tailscale.com/util/racebuild from tailscale.com/logpolicy
tailscale.com/util/rands from tailscale.com/ipn/ipnlocal+
@@ -274,9 +271,8 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
bufio from compress/flate+
bytes from bufio+
cmp from encoding/json+
compress/flate from compress/gzip+
compress/flate from compress/gzip
compress/gzip from net/http+
compress/zlib from image/png
container/list from crypto/tls+
context from crypto/tls+
crypto from crypto/ecdh+
@@ -355,13 +351,9 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
flag from tailscale.com/cmd/tailscaled+
fmt from compress/flate+
hash from crypto+
hash/adler32 from compress/zlib
hash/crc32 from compress/gzip+
hash/maphash from go4.org/mem
html from tailscale.com/ipn/ipnlocal+
image from github.com/skip2/go-qrcode+
image/color from github.com/skip2/go-qrcode+
image/png from github.com/skip2/go-qrcode
internal/abi from hash/maphash+
internal/asan from internal/runtime/maps+
internal/bisect from internal/godebug
@@ -406,7 +398,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
internal/unsafeheader from internal/reflectlite+
io from bufio+
io/fs from crypto/x509+
io/ioutil from github.com/skip2/go-qrcode
iter from bytes+
log from github.com/klauspost/compress/zstd+
log/internal from log