Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions cmd/portal-tunnel/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,7 @@ type exposeFlags struct {
metricsAddr string
}

func runExposeCommand(args []string) error {
installer.StartUpdateCheck(types.ReleaseVersion)

flags := exposeFlags{}
fs := utils.NewFlagSet("expose", printExposeUsage)

func registerExposeFlags(fs *flag.FlagSet, flags *exposeFlags) {
utils.StringFlag(fs, &flags.relayCSV, "relays", "", "Additional Portal relay server API URLs (comma-separated; scheme omitted defaults to https)")
utils.StringFlagEnv(fs, &flags.multiHopCSV, "multi-hop", "", "Ordered multi-hop relay API URLs, comma-separated", "MULTI_HOP")
utils.BoolFlag(fs, &flags.discovery, "discovery", true, "Include bootstrap relays and discover additional relays")
Expand Down Expand Up @@ -113,7 +108,14 @@ func runExposeCommand(args []string) error {
utils.IntFlagEnv(fs, &flags.maxActiveRelays, "max-active-relays", 3, nil, "Maximum auto-selected single-hop relays to keep connected; multi-hop uses every eligible relay as an entry", "MAX_ACTIVE_RELAYS")
utils.IntFlagEnv(fs, &flags.multiHopDepth, "multi-hop-depth", 0, nil, "Automatically create multi-hop routes at this hop count for every eligible entry relay; 0 or 1 disables multi-hop", "MULTI_HOP_DEPTH")
utils.StringFlag(fs, &flags.metricsAddr, "metrics-addr", "", "Optional address (host:port) to serve Prometheus /metrics. Empty = disabled.")
}

func runExposeCommand(args []string) error {
installer.StartUpdateCheck(types.ReleaseVersion)

flags := exposeFlags{}
fs := utils.NewFlagSet("expose", printExposeUsage)
registerExposeFlags(fs, &flags)
if err := utils.ParseFlagSet(fs, args, printExposeUsage); err != nil {
if errors.Is(err, flag.ErrHelp) {
return nil
Expand Down Expand Up @@ -435,6 +437,9 @@ func printExposeUsage(w io.Writer) {
"portal expose 3000 --multi-hop-depth 3",
},
)
fs := utils.NewFlagSet("expose", nil)
registerExposeFlags(fs, &exposeFlags{})
utils.WriteFlagDefaults(w, fs)
}

func printListUsage(w io.Writer) {
Expand Down
26 changes: 16 additions & 10 deletions cmd/relay-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,20 @@ func resolveRelayServerConfig(args []string) (relayServerConfig, error) {

cfg := relayServerConfig{}
fs := utils.NewFlagSet("relay-server", printRootUsage)
registerRelayServerFlags(fs, &cfg)

if err := utils.ParseFlagSet(fs, args, printRootUsage); err != nil {
return relayServerConfig{}, err
}
if err := utils.RequireNoArgs(fs.Args(), "relay-server"); err != nil {
printRootUsage(os.Stderr)
return relayServerConfig{}, err
}
cfg.IdentityPath = identity.ResolveRelayStateDir(cfg.IdentityPath)
return cfg, nil
}

func registerRelayServerFlags(fs *flag.FlagSet, cfg *relayServerConfig) {
utils.StringFlagEnv(fs, &cfg.PortalURL, "portal-url", "https://localhost", "portal base URL", "PORTAL_URL")
utils.StringFlagEnv(fs, &cfg.FrontendDir, "frontend-dir", "", "custom SPA directory containing index.html; embedded frontend is used when empty", "PORTAL_FRONTEND_DIR")
utils.StringFlagEnv(fs, &cfg.IdentityPath, "identity-path", "./.portal-certs", "directory path for relay identity, policy state, and keyless materials", "IDENTITY_PATH")
Expand Down Expand Up @@ -126,16 +139,6 @@ func resolveRelayServerConfig(args []string) (relayServerConfig, error) {
utils.StringFlagEnv(fs, &cfg.AWSDNSSECKMSKeyARN, "aws-dnssec-kms-key-arn", "", "AWS KMS key ARN used to create a Route53 DNSSEC key-signing key when needed", "AWS_DNSSEC_KMS_KEY_ARN")
utils.StringFlagEnv(fs, &cfg.VultrAPIKey, "vultr-api-key", "", "Vultr API key for DNS automation (required when acme-dns-provider=vultr)", "VULTR_API_KEY")
utils.StringFlagEnv(fs, &cfg.NjallaToken, "njalla-token", "", "Njalla API token for DNS automation (required when acme-dns-provider=njalla)", "NJALLA_TOKEN")

if err := utils.ParseFlagSet(fs, args, printRootUsage); err != nil {
return relayServerConfig{}, err
}
if err := utils.RequireNoArgs(fs.Args(), "relay-server"); err != nil {
printRootUsage(os.Stderr)
return relayServerConfig{}, err
}
cfg.IdentityPath = identity.ResolveRelayStateDir(cfg.IdentityPath)
return cfg, nil
}

func runServeCommand(args []string) error {
Expand Down Expand Up @@ -275,4 +278,7 @@ func printRootUsage(w io.Writer) {
"relay-server help",
},
)
fs := utils.NewFlagSet("relay-server", nil)
registerRelayServerFlags(fs, &relayServerConfig{})
utils.WriteFlagDefaults(w, fs)
}
13 changes: 13 additions & 0 deletions utils/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,3 +523,16 @@ func WriteCommandUsage(w io.Writer, usage []string, examples []string) {
fmt.Fprintln(w, " "+strings.TrimSpace(line))
}
}

// WriteFlagDefaults prints the registered flags. Custom Usage printers replace
// FlagSet defaults, so --help would otherwise list examples and omit the flags
// agents need (identity-path, relays, api-port).
func WriteFlagDefaults(w io.Writer, fs *flag.FlagSet) {
if w == nil || fs == nil {
return
}
fmt.Fprintln(w)
fmt.Fprintln(w, "Flags:")
fs.SetOutput(w)
fs.PrintDefaults()
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
33 changes: 33 additions & 0 deletions utils/cmd_usage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package utils

import (
"bytes"
"strings"
"testing"
)

func TestWriteFlagDefaultsListsRegisteredFlags(t *testing.T) {
var buf bytes.Buffer
var identityPath string
fs := NewFlagSet("expose", nil)
StringFlagEnv(fs, &identityPath, "identity-path", "identity.json", "identity json file path", "IDENTITY_PATH")

WriteCommandUsage(&buf, []string{"portal expose [flags] <target>"}, []string{"portal expose 3000"})
WriteFlagDefaults(&buf, fs)

got := buf.String()
for _, want := range []string{"Usage:", "Examples:", "Flags:", "-identity-path", "IDENTITY_PATH"} {
if !strings.Contains(got, want) {
t.Fatalf("help missing %q\n%s", want, got)
}
}
}

func TestWriteFlagDefaultsNilIsNoop(t *testing.T) {
WriteFlagDefaults(nil, nil)
var buf bytes.Buffer
WriteFlagDefaults(&buf, nil)
if buf.Len() != 0 {
t.Fatalf("nil FlagSet should print nothing, got %q", buf.String())
}
}
Loading