From 297d0838a8bf228a856a31f09bc82df5790c6eab Mon Sep 17 00:00:00 2001 From: Cleve Stuart Date: Tue, 3 Dec 2024 09:39:37 -0500 Subject: [PATCH 1/8] FE-5990 Set argv.secret to 'secret' when --local passed in and --secret is not. Always respect argv.secret when getting a secret with FaunaClient.getSecret. --- src/commands/query.mjs | 2 +- src/commands/shell.mjs | 2 +- src/lib/auth/accountKeys.mjs | 6 +++--- src/lib/command-helpers.mjs | 6 +++++- src/lib/fauna-client.mjs | 12 +++++++++++- test/config.mjs | 34 ++++++++++++++++++++++++++++++++-- 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/commands/query.mjs b/src/commands/query.mjs index d06e75f5..6ca8dd9c 100644 --- a/src/commands/query.mjs +++ b/src/commands/query.mjs @@ -61,7 +61,7 @@ async function queryCommand(argv) { // get the query handler and run the query try { - const secret = await getSecret(); + const secret = await getSecret({ secretArg: argv.secret }); const { url, timeout, typecheck, extra, json, apiVersion } = argv; const results = await container.resolve("runQueryFromString")(expression, { apiVersion, diff --git a/src/commands/shell.mjs b/src/commands/shell.mjs index 72fec269..8e1a6586 100644 --- a/src/commands/shell.mjs +++ b/src/commands/shell.mjs @@ -91,7 +91,7 @@ async function buildCustomEval(argv) { let res; try { - const secret = await getSecret(); + const secret = await getSecret({ secretArg: argv.secret }); const { url, timeout, typecheck } = argv; res = await runQueryFromString(cmd, { apiVersion, diff --git a/src/lib/auth/accountKeys.mjs b/src/lib/auth/accountKeys.mjs index 7c8774ce..d933a830 100644 --- a/src/lib/auth/accountKeys.mjs +++ b/src/lib/auth/accountKeys.mjs @@ -24,7 +24,7 @@ export class AccountKeys { // Let users know if the creds they provided are invalid (empty) if (!key && keySource !== "credentials-file") { throw new Error( - `The account key provided by ${keySource} is invalid. Please provide an updated value.`, + `The account key provided by '${keySource}' is invalid. Please provide an updated value.`, ); } } @@ -56,7 +56,7 @@ export class AccountKeys { */ promptLogin() { throw new Error( - `The requested user ${this.user || ""} is not signed in or has expired.\nPlease re-authenticate\n\n + `The requested user '${this.user || ""}' is not signed in or has expired.\nPlease re-authenticate\n\n To sign in, run:\n\nfauna login\n `, ); @@ -69,7 +69,7 @@ export class AccountKeys { async onInvalidCreds() { if (this.keySource !== "credentials-file") { throw new Error( - `Account key provided by ${this.keySource} is invalid. Please provide an updated account key.`, + `Account key provided by '${this.keySource}' is invalid. Please provide an updated account key.`, ); } await this.refreshKey(); diff --git a/src/lib/command-helpers.mjs b/src/lib/command-helpers.mjs index d0260095..24c6005d 100644 --- a/src/lib/command-helpers.mjs +++ b/src/lib/command-helpers.mjs @@ -96,7 +96,7 @@ function yargsWithCommonOptions(yargs, options) { return yargs .options({ ...options, }) .check((argv) => { - // If --local is provided and --url is not, set the default URL for local + // If --local is provided and --url is not, set argv.url to "http://localhost:8443" if (!argv.url) { if (argv.local) { argv.url = 'http://localhost:8443'; @@ -104,6 +104,10 @@ function yargsWithCommonOptions(yargs, options) { argv.url = 'https://db.fauna.com'; } } + // if --local is provided and --secret is not set argv.secret to "secret" + if (!argv.secret && argv.local) { + argv.secret = 'secret'; + } return true; // Validation passed }); } diff --git a/src/lib/fauna-client.mjs b/src/lib/fauna-client.mjs index 2dd1d71f..640e9ad3 100644 --- a/src/lib/fauna-client.mjs +++ b/src/lib/fauna-client.mjs @@ -71,7 +71,17 @@ export default class FaunaClient { } } -export const getSecret = async () => { +/** + * Gets a secret. Defaults to the secretArg. If the secretArg is undefined + * fetches a secret for the current credentials. + * @param opts {Object} + * @param opts.secretArg {string} The secret passed as an argument, if any. + * @return {string} the secret + */ +export async function getSecret({ secretArg }) { + if (secretArg !== undefined) { + return secretArg; + } const credentials = container.resolve("credentials"); if (!credentials.databaseKeys.key) { return await credentials.databaseKeys.getOrRefreshKey(); diff --git a/test/config.mjs b/test/config.mjs index 1a96a461..e71e32f0 100644 --- a/test/config.mjs +++ b/test/config.mjs @@ -198,7 +198,7 @@ describe("configuration file", function () { }); }); - it("--local arg sets the url to http://localhost:8443 if no URL is given", async function () { + it("--local arg sets the argv.url to http://localhost:8443 if no --url is given", async function () { fs.readdirSync.withArgs(process.cwd()).returns([]); await runBasicTest({ cmd: `eval "Database.all()" --secret "no-config" --local`, @@ -213,7 +213,7 @@ describe("configuration file", function () { }); }); - it("--url arg takes precedence over --local arg for the URL", async function () { + it("--url arg takes precedence over --local arg for the argv.url", async function () { fs.readdirSync.withArgs(process.cwd()).returns([]); await runBasicTest({ cmd: `eval "Database.all()" --secret "no-config" --local --url http://localhost:hibob`, @@ -228,6 +228,36 @@ describe("configuration file", function () { }); }); + it("--local sets the argv.secret to 'secret' if no --secret is given", async function () { + fs.readdirSync.withArgs(process.cwd()).returns([]); + await runBasicTest({ + cmd: `eval "Database.all()" --local`, + argvMatcher: sinon.match({ + apiVersion: "10", + secret: "secret", + url: "http://localhost:8443", + timeout: 5000, + typecheck: undefined, + }), + objectToReturn: databaseObject, + }); + }); + + it("--secret arg takes precedence over --local arg for the argv.secret", async function () { + fs.readdirSync.withArgs(process.cwd()).returns([]); + await runBasicTest({ + cmd: `eval "Database.all()" --local --secret "sauce"`, + argvMatcher: sinon.match({ + apiVersion: "10", + secret: "sauce", + url: "http://localhost:8443", + timeout: 5000, + typecheck: undefined, + }), + objectToReturn: databaseObject, + }); + }); + it("exits with an error if multiple default files exist", async function () { fs.readdirSync .withArgs(process.cwd()) From be77c20ae9a71ff38eb924a7bfb8c7a4bd3bf7b1 Mon Sep 17 00:00:00 2001 From: Paul Paterson Date: Tue, 3 Dec 2024 09:46:29 -0500 Subject: [PATCH 2/8] fix javadoc type --- src/lib/fauna-client.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/fauna-client.mjs b/src/lib/fauna-client.mjs index 640e9ad3..4ae68c4f 100644 --- a/src/lib/fauna-client.mjs +++ b/src/lib/fauna-client.mjs @@ -76,7 +76,7 @@ export default class FaunaClient { * fetches a secret for the current credentials. * @param opts {Object} * @param opts.secretArg {string} The secret passed as an argument, if any. - * @return {string} the secret + * @return {Promise} the secret */ export async function getSecret({ secretArg }) { if (secretArg !== undefined) { From 2cd2e763fda595980f57e8a4ecda9ec9d09e02a9 Mon Sep 17 00:00:00 2001 From: Cleve Stuart <90649124+cleve-fauna@users.noreply.github.com> Date: Tue, 3 Dec 2024 06:48:07 -0800 Subject: [PATCH 3/8] Update src/lib/fauna-client.mjs --- src/lib/fauna-client.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/fauna-client.mjs b/src/lib/fauna-client.mjs index 4ae68c4f..4a4bc6ed 100644 --- a/src/lib/fauna-client.mjs +++ b/src/lib/fauna-client.mjs @@ -75,7 +75,7 @@ export default class FaunaClient { * Gets a secret. Defaults to the secretArg. If the secretArg is undefined * fetches a secret for the current credentials. * @param opts {Object} - * @param opts.secretArg {string} The secret passed as an argument, if any. + * @param opts.secretArg {string | undefined} The secret passed as an argument, if any. * @return {Promise} the secret */ export async function getSecret({ secretArg }) { From 99750b3fa016f87867a9c1ba4dd6d73e6e49b755 Mon Sep 17 00:00:00 2001 From: Cleve Stuart <90649124+cleve-fauna@users.noreply.github.com> Date: Tue, 3 Dec 2024 06:50:14 -0800 Subject: [PATCH 4/8] Update src/lib/fauna-client.mjs From 2ca3a71e0072f4c0a55654b2bd5ea5c59d804098 Mon Sep 17 00:00:00 2001 From: Cleve Stuart Date: Tue, 3 Dec 2024 11:20:05 -0500 Subject: [PATCH 5/8] Use middlware --- src/commands/query.mjs | 2 +- src/commands/shell.mjs | 2 +- src/lib/auth/credentials.mjs | 2 +- src/lib/auth/databaseKeys.mjs | 6 +++++- src/lib/command-helpers.mjs | 8 ++------ src/lib/fauna-client.mjs | 10 ++-------- 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/commands/query.mjs b/src/commands/query.mjs index 6ca8dd9c..d06e75f5 100644 --- a/src/commands/query.mjs +++ b/src/commands/query.mjs @@ -61,7 +61,7 @@ async function queryCommand(argv) { // get the query handler and run the query try { - const secret = await getSecret({ secretArg: argv.secret }); + const secret = await getSecret(); const { url, timeout, typecheck, extra, json, apiVersion } = argv; const results = await container.resolve("runQueryFromString")(expression, { apiVersion, diff --git a/src/commands/shell.mjs b/src/commands/shell.mjs index 8e1a6586..72fec269 100644 --- a/src/commands/shell.mjs +++ b/src/commands/shell.mjs @@ -91,7 +91,7 @@ async function buildCustomEval(argv) { let res; try { - const secret = await getSecret({ secretArg: argv.secret }); + const secret = await getSecret(); const { url, timeout, typecheck } = argv; res = await runQueryFromString(cmd, { apiVersion, diff --git a/src/lib/auth/credentials.mjs b/src/lib/auth/credentials.mjs index 8ec6cdb5..18895f00 100644 --- a/src/lib/auth/credentials.mjs +++ b/src/lib/auth/credentials.mjs @@ -14,7 +14,7 @@ const validateCredentialArgs = (argv) => { // The '--role' option is not supported when using a secret. Secrets have an // implicit role. throw new Error( - "The '--role' option is not supported when using a secret. It will be ignored.", + "The '--role' option is not supported when using a '--secret'. Please specify only one.", ); } }; diff --git a/src/lib/auth/databaseKeys.mjs b/src/lib/auth/databaseKeys.mjs index 3ea59275..fc7be54d 100644 --- a/src/lib/auth/databaseKeys.mjs +++ b/src/lib/auth/databaseKeys.mjs @@ -46,10 +46,14 @@ export class DatabaseKeys { */ static resolveKeySources(argv, storedKey) { let key, keySource; - // argv.secret come from flag, config, or FAUNA_SECRET + // argv.secret comes from flag, config, or FAUNA_SECRET if (argv.secret) { key = argv.secret; keySource = "user"; + // argv.local comes from a flag or config. + } else if (argv.local) { + key = "secret"; + keySource = "user"; } else { key = storedKey; keySource = "credentials-file"; diff --git a/src/lib/command-helpers.mjs b/src/lib/command-helpers.mjs index 24c6005d..cd85fd2c 100644 --- a/src/lib/command-helpers.mjs +++ b/src/lib/command-helpers.mjs @@ -56,8 +56,8 @@ const COMMON_QUERY_OPTIONS = { * @param {string} argv.secret - The secret to use */ export const validateDatabaseOrSecret = (argv) => { - if (!argv.database && !argv.secret) { - throw new Error("No database or secret specified. Pass --database or --secret."); + if (!argv.database && !argv.secret && !argv.local) { + throw new Error("No database or secret specified. Pass either --database, or --secret, or --local."); } } @@ -104,10 +104,6 @@ function yargsWithCommonOptions(yargs, options) { argv.url = 'https://db.fauna.com'; } } - // if --local is provided and --secret is not set argv.secret to "secret" - if (!argv.secret && argv.local) { - argv.secret = 'secret'; - } return true; // Validation passed }); } diff --git a/src/lib/fauna-client.mjs b/src/lib/fauna-client.mjs index 4a4bc6ed..7bd9a35a 100644 --- a/src/lib/fauna-client.mjs +++ b/src/lib/fauna-client.mjs @@ -72,16 +72,10 @@ export default class FaunaClient { } /** - * Gets a secret. Defaults to the secretArg. If the secretArg is undefined - * fetches a secret for the current credentials. - * @param opts {Object} - * @param opts.secretArg {string | undefined} The secret passed as an argument, if any. + * Gets a secret for the current credentials. * @return {Promise} the secret */ -export async function getSecret({ secretArg }) { - if (secretArg !== undefined) { - return secretArg; - } +export async function getSecret() { const credentials = container.resolve("credentials"); if (!credentials.databaseKeys.key) { return await credentials.databaseKeys.getOrRefreshKey(); From e11f17fb8f93f1ac81da630982fe99dac9f6f49c Mon Sep 17 00:00:00 2001 From: Cleve Stuart Date: Tue, 3 Dec 2024 11:33:55 -0500 Subject: [PATCH 6/8] Use middleware not check --- src/lib/command-helpers.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/command-helpers.mjs b/src/lib/command-helpers.mjs index cd85fd2c..227c4330 100644 --- a/src/lib/command-helpers.mjs +++ b/src/lib/command-helpers.mjs @@ -95,8 +95,7 @@ export function yargsWithCommonConfigurableQueryOptions(yargs) { function yargsWithCommonOptions(yargs, options) { return yargs .options({ ...options, }) - .check((argv) => { - // If --local is provided and --url is not, set argv.url to "http://localhost:8443" + .middleware((argv) => { if (!argv.url) { if (argv.local) { argv.url = 'http://localhost:8443'; @@ -104,6 +103,8 @@ function yargsWithCommonOptions(yargs, options) { argv.url = 'https://db.fauna.com'; } } - return true; // Validation passed + if (!argv.secret && argv.local) { + argv.secret = "secret"; + } }); } From 70af84646fa47d6c6be1e0f9cfdce903e9dcfa31 Mon Sep 17 00:00:00 2001 From: Cleve Stuart Date: Tue, 3 Dec 2024 11:36:41 -0500 Subject: [PATCH 7/8] Move middlware to the cli.mjs --- src/cli.mjs | 12 ++++++++++++ src/lib/command-helpers.mjs | 14 +------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/cli.mjs b/src/cli.mjs index 0f6ccee9..f240cd84 100644 --- a/src/cli.mjs +++ b/src/cli.mjs @@ -104,6 +104,18 @@ function buildYargs(argvInput) { .env("FAUNA") .config("config", configParser) .middleware([checkForUpdates, logArgv], true) + .middleware((argv) => { + if (!argv.url) { + if (argv.local) { + argv.url = 'http://localhost:8443'; + } else { + argv.url = 'https://db.fauna.com'; + } + } + if (!argv.secret && argv.local) { + argv.secret = "secret"; + } + }) .middleware([fixPaths, buildCredentials], false) .command(queryCommand) .command("shell", "start an interactive shell", shellCommand) diff --git a/src/lib/command-helpers.mjs b/src/lib/command-helpers.mjs index 227c4330..eabf2ba1 100644 --- a/src/lib/command-helpers.mjs +++ b/src/lib/command-helpers.mjs @@ -94,17 +94,5 @@ export function yargsWithCommonConfigurableQueryOptions(yargs) { function yargsWithCommonOptions(yargs, options) { return yargs - .options({ ...options, }) - .middleware((argv) => { - if (!argv.url) { - if (argv.local) { - argv.url = 'http://localhost:8443'; - } else { - argv.url = 'https://db.fauna.com'; - } - } - if (!argv.secret && argv.local) { - argv.secret = "secret"; - } - }); + .options({ ...options, }); } From ae25c5584b47db31f0280ae590697b8e91a51186 Mon Sep 17 00:00:00 2001 From: Cleve Stuart Date: Tue, 3 Dec 2024 11:39:19 -0500 Subject: [PATCH 8/8] Don't look for local. Rely on the middlware to set secret --- src/lib/auth/databaseKeys.mjs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lib/auth/databaseKeys.mjs b/src/lib/auth/databaseKeys.mjs index fc7be54d..efee6515 100644 --- a/src/lib/auth/databaseKeys.mjs +++ b/src/lib/auth/databaseKeys.mjs @@ -50,10 +50,6 @@ export class DatabaseKeys { if (argv.secret) { key = argv.secret; keySource = "user"; - // argv.local comes from a flag or config. - } else if (argv.local) { - key = "secret"; - keySource = "user"; } else { key = storedKey; keySource = "credentials-file";