Skip to content

Initialize console if -U is specified #121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 7, 2022
Merged

Initialize console if -U is specified #121

merged 8 commits into from
Sep 7, 2022

Conversation

apoorvdeshmukh
Copy link
Contributor

@apoorvdeshmukh apoorvdeshmukh commented Aug 19, 2022

In absence of console or when console reference line is set
to nil, noPwd is set to true which disables password prompt
and when console is not initialized, password cannot be read
from user. This is why when -i is specified, console is not
initialized and we do not see password prompt.
This commit initializes console even if -U is specified so
that password can be read interactively from user.
Resolves #115

Validation:

go-sqlcmd>.\sqlcmd.exe -i test.sql -U sa
Password:



------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Microsoft SQL Server 2012 (SP4-GDR) (KB4583465) - 11.0.7507.2 (X64)
        Nov  1 2020 00:48:37
        Copyright (c) Microsoft Corporation
        Enterprise Edition: Core-based Licensing (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)


(1 row affected)

In absence of console or when console reference line is set
to nil, noPwd is set to true which disables password prompt
and when console is not initialized, password cannot be read
from user. This is why when -i is specified, console is not
initialized and we do not see password prompt.
This commit initializes console even if -U is specified so
that password can be read interactively from user.
@shueybubbles
Copy link
Collaborator

pls add a test that fails without the fix.

@@ -162,8 +162,8 @@ func TestUnicodeOutput(t *testing.T) {
}
vars := sqlcmd.InitializeVariables(!args.DisableCmdAndWarn)
setVars(vars, &args)

exitCode, err := run(vars, &args)
sqlcmdConsole := getSqlcmdConsole(args)
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's go with a model that doesn't require so many changes.
Just define a type like

type allocConsole func(historyFile string) sqlcmd.Console

And create a field whose default assignment is console.NewConsole. The test can override it by assigning it a new func.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The unit test now no more relies on the console allocator function hence have removed it.
The unit test will validate console initialization and conditions for password prompt based on the parameters supplied.

@apoorvdeshmukh apoorvdeshmukh added the Not to be merged PR not to be merged. POC/Demo/Repro label Aug 21, 2022
@shueybubbles
Copy link
Collaborator

setConnect(&s.Connect, args, vars)

maybe the uactive assignment should move below this line , and use change s.Connect.requiresPassword to RequiresPassword and call it here


Refers to: cmd/sqlcmd/main.go:224 in 73fc6e1. [](commit_id = 73fc6e1, deletion_comment = False)

var line sqlcmd.Console = nil
if iactive {
line = console.NewConsole("")
if connectConfig.RequiresPassword() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

don't you still need the iactive check? How are you testing this before pushing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My bad. I missed that locally it is only using SQL authentication.
Adding testcases for AAD modes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added the iactive check.

@shueybubbles
Copy link
Collaborator

setConnect(&s.Connect, args, vars)

i think this can change to copy connectConfig to s.Connect instead


Refers to: cmd/sqlcmd/main.go:235 in 99140d4. [](commit_id = 99140d4, deletion_comment = False)

@apoorvdeshmukh apoorvdeshmukh force-pushed the 115 branch 3 times, most recently from cad1251 to c634d1f Compare September 6, 2022 06:42
@apoorvdeshmukh apoorvdeshmukh removed the Not to be merged PR not to be merged. POC/Demo/Repro label Sep 6, 2022
@@ -201,22 +201,28 @@ func setConnect(connect *sqlcmd.ConnectSettings, args *SQLCmdArguments, vars *sq
connect.ErrorSeverityLevel = args.ErrorSeverityLevel
}

func IsConsoleInitializationRequired(connect *sqlcmd.ConnectSettings, args *SQLCmdArguments) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

IsCons

isConsoleInitializationRequired
no need for this to be public

vars := sqlcmd.InitializeVariables(!args.DisableCmdAndWarn)
setVars(vars, &args)
var connectConfig sqlcmd.ConnectSettings
setConnect(&connectConfig, &args, vars)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's not use setVars and setConnect in this test. Their behavior depends on the values of environment variables set in the pipeline.
Just set the specific combinations of authentication type and user name/password in each struct explicitly and validate the right values for isConsoleInitializationRequired.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

setConnect only seems to set password from env variable and that too if DisableCmdAndWarn is false.
servername and usernamre is fetched from vars.get() vars is obtained from InitializeVariables() which has an argument to indicate if values should be fetched from end. In this case DisableCmdAndWarn is set to true and value of DisableCmdAndWarn is passed to ensure that we don't fetch anything from env.
setVars() doesn't seems to fetch any anything from env.
I will, however, parameterize the test to add more scenarios.

@@ -167,7 +167,7 @@ func TestConnectCommand(t *testing.T) {
err := connectCommand(s, []string{"someserver -U someuser"}, 1)
assert.NoError(t, err, "connectCommand with valid arguments doesn't return an error on connect failure")
assert.True(t, prompted, "connectCommand with user name and no password should prompt for password")
assert.NotEqual(t, "someserver", s.Connect.ServerName, "On error, sqlCmd.Connect does not copy inputs")
assert.Equal(t, "someserver", s.Connect.ServerName, "servername should match with the input parameter")

Copy link
Collaborator

@shueybubbles shueybubbles Sep 6, 2022

Choose a reason for hiding this comment

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

why is this changing? s.Connect.ServerName being changed implies that the connection attempt succeeded when it should have failed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for adding the context. This was a side effect of changing type of connect from ConnectSettings to a pointer to ConnectSettings in sqlcmd struct.
In connectCommand() we copy s.Connect to local connect object to establish connection.
I will fix this in my next commit.

Copy link
Collaborator

Choose a reason for hiding this comment

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

if the message in the assert didn't provide sufficient context, please update the assert message to be clearer.

connectConfig.AuthenticationMethod = testcase.authenticationMethod
connectConfig.Password = testcase.pwd
assert.Equal(t, testcase.expectedResult, isConsoleInitializationRequired(&connectConfig, &args), "Unexpected test result encountered for console initialization")
assert.Equal(t, testcase.expectedResult, connectConfig.RequiresPassword() && connectConfig.Password == "", "Unexpected test result encountered for password prompt conditions")
Copy link
Collaborator

Choose a reason for hiding this comment

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

sse

this assert is odd. Shouldn't you assert that if RequiresPassword is true then Password == ""?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. This was to avoid the conditional check and to assert the same condition for password prompt that we use in connectDb()

Copy link
Collaborator

@shueybubbles shueybubbles left a comment

Choose a reason for hiding this comment

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

:shipit:

@apoorvdeshmukh apoorvdeshmukh merged commit fe6b80a into main Sep 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Password prompt is not displayed when -i and -U switch are specified
2 participants