Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions cmd/lk/agent_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ func mergeCredentials(explicit, project agentCredentials) agentCredentials {
// subprocess running from dir.
func resolveCredentials(ctx context.Context, cmd *cli.Command, dir string, loadOpts ...loadOption) ([]string, error) {
explicit := explicitCredentials(cmd)
// The agent gets LIVEKIT_* credentials from the environment even under
// --user-auth, so they aren't ignored here.
envCredentialsUsed = true

// An explicitly named project always wins, mirroring resolveProject's
// priority order. Without this, ambient LIVEKIT_* shell variables (which
Expand Down
6 changes: 3 additions & 3 deletions cmd/lk/testdata/script/env-keys-with-user-auth.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# --user-auth wins over API keys in the environment: the command runs
# as the signed-in user, with a one-line note that the env keys are ignored.
# as the signed-in user, with a one-line note that the env credentials are
# ignored.
env LIVEKIT_URL=ws://env.test
env LIVEKIT_API_KEY=APIenv
env LIVEKIT_API_SECRET=secretenv
Expand All @@ -10,8 +11,7 @@ cp stderr lk.stderr
requests
cmp stdout want-requests

skip 'known bug: --user-auth ignores LIVEKIT_API_KEY and LIVEKIT_API_SECRET without saying so'
grep 'LIVEKIT_API_KEY.*ignored' lk.stderr
grep '^Ignoring LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET from environment \(--user-auth uses your session\)$' lk.stderr

-- home/.livekit/cli-config.yaml --
default_user: u_1
Expand Down
22 changes: 21 additions & 1 deletion cmd/lk/user_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"context"
"errors"
"fmt"
"os"
"strings"
"time"

Expand Down Expand Up @@ -247,9 +248,16 @@ func requireUserSession(cmd *cli.Command) (*config.CLIConfig, *config.UserConfig
// resolves the session more than once still prints the breadcrumb only once.
var userAnnounced bool

// envCredentialsUsed is set by commands that hand LIVEKIT_* credentials from
// the environment to what they run (agent runs, see resolveCredentials), so
// announceUser doesn't call them ignored.
var envCredentialsUsed bool

// announceUser surfaces which signed-in user a command acts as — the user-auth
// counterpart of the "Using project" breadcrumb (stderr, suppressed by --quiet).
// The API is named when it isn't the default, e.g. for a staging sign-in.
// The API is named when it isn't the default, e.g. for a staging sign-in. It
// also names the LIVEKIT_* credentials in the environment that the command
// ignores, since they don't switch modes (see userAuthEnabled).
func announceUser(user *config.UserConfig) {
if userAnnounced || user == nil {
return
Expand All @@ -260,6 +268,18 @@ func announceUser(user *config.UserConfig) {
} else {
out.Statusf("Using user [%s] on [%s]", util.Accented(userLabel(user)), util.Accented(publicAPIURL))
}
if envCredentialsUsed {
return
}
var ignored []string
for _, name := range []string{"LIVEKIT_URL", "LIVEKIT_API_KEY", "LIVEKIT_API_SECRET"} {
if os.Getenv(name) != "" {
ignored = append(ignored, name)
}
}
if len(ignored) > 0 {
out.Statusf("Ignoring %s from environment (--user-auth uses your session)", strings.Join(ignored, ", "))
}
}

// resolveSessionUser picks the user to act as: the one named by userRef (the
Expand Down
40 changes: 40 additions & 0 deletions cmd/lk/user_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,46 @@ func TestCloudAPIError(t *testing.T) {
}
}

// TestAnnounceUserNamesIgnoredEnvCredentials checks the note announceUser adds
// for LIVEKIT_* credentials in the environment that --user-auth leaves unused,
// and that commands handing them to an agent don't get it.
func TestAnnounceUserNamesIgnoredEnvCredentials(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary because we also have an e2e test?

prevAnnounced, prevUsed := userAnnounced, envCredentialsUsed
t.Cleanup(func() { userAnnounced, envCredentialsUsed = prevAnnounced, prevUsed })
user := &config.UserConfig{Id: "u_1", Email: "dev@example.com"}

for _, tc := range []struct {
name string
url, key string
secret string
usedByAgent bool
wantIgnoring string
}{
{name: "all three", url: "ws://env.test", key: "APIenv", secret: "secretenv",
wantIgnoring: "Ignoring LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET from environment (--user-auth uses your session)"},
{name: "only the key", key: "APIenv",
wantIgnoring: "Ignoring LIVEKIT_API_KEY from environment (--user-auth uses your session)"},
{name: "none set"},
{name: "handed to an agent", url: "ws://env.test", key: "APIenv", secret: "secretenv", usedByAgent: true},
} {
t.Run(tc.name, func(t *testing.T) {
t.Setenv("LIVEKIT_URL", tc.url)
t.Setenv("LIVEKIT_API_KEY", tc.key)
t.Setenv("LIVEKIT_API_SECRET", tc.secret)
userAnnounced, envCredentialsUsed = false, tc.usedByAgent
buf := withCapturedAnnounce(t)

announceUser(user)

if tc.wantIgnoring == "" {
assert.NotContains(t, buf.String(), "Ignoring")
} else {
assert.Contains(t, buf.String(), tc.wantIgnoring+"\n")
}
})
}
}

func TestSetUserAuthHidden(t *testing.T) {
root := &cli.Command{Flags: globalFlags}
for _, cmds := range [][]*cli.Command{ProjectCommands, WorkspaceCommands, UserCommands, CloudCommands, AgentCommands} {
Expand Down
Loading