From 29f0e2f78d08d29cd11c2b57db1f0da1de41eff9 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 07:55:19 +0100 Subject: [PATCH 01/10] fix: impersonate test --- features/Sdk.feature | 15 ++++++------ features/run-kuzzle-stack.sh | 2 +- .../common/collection-steps.js | 23 +++++++++++++++++++ src/common.ts | 3 ++- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/features/Sdk.feature b/features/Sdk.feature index 19470d24..7054d454 100644 --- a/features/Sdk.feature +++ b/features/Sdk.feature @@ -28,10 +28,11 @@ Feature: SDK commands Then The document "document-ricky" should exist And I should match stdout with "document-ricky" - # @mappings - # Scenario: Impersonate an user - # When I run the command "sdk:query" with: - # | arg | auth:getCurrentUser | | - # | flag | --as | gordon | - # Then I should match stdout with: - # | "_id": "gordon" | + @mappings + Scenario: Impersonate an user + Given an existing user "pandacrobate" + When I run the command "sdk:query" with: + | arg | auth:getCurrentUser | | + | flag | --as | pandacrobate | + Then I should match stdout with: + | "_id": "pandacrobate" | diff --git a/features/run-kuzzle-stack.sh b/features/run-kuzzle-stack.sh index 7dc9f13c..c4d78fbd 100755 --- a/features/run-kuzzle-stack.sh +++ b/features/run-kuzzle-stack.sh @@ -4,7 +4,7 @@ set -e # Create the folder where will be stored snapshots mkdir -p /tmp/snapshots -chmod 777 -R /tmp/snapshots +# chmod 777 -R /tmp/snapshots # Launch the kuzzle stack docker compose -f features/docker/docker-compose.yml up -d diff --git a/features/step_definitions/common/collection-steps.js b/features/step_definitions/common/collection-steps.js index b6969f4d..14483057 100644 --- a/features/step_definitions/common/collection-steps.js +++ b/features/step_definitions/common/collection-steps.js @@ -24,6 +24,29 @@ Given( } ); +Given( + "an existing user {string}", + async function (userId) { + + try { + await this.sdk.security.getUser(userId); + } catch (error) { + console.log('✔ User not found, creating...'); + await this.sdk.security.createUser(userId, { + content: { + profileIds: ['default'] + }, + credentials: { + local: { + username: userId, + password: 'password' + } + } + }); + } + } +); + Then("I list collections in index {string}", async function (index) { this.props.result = await this.sdk.collection.list(index); }); diff --git a/src/common.ts b/src/common.ts index 96b48412..f77c387f 100644 --- a/src/common.ts +++ b/src/common.ts @@ -165,6 +165,7 @@ export abstract class Kommand extends Command { this.logKo(`${e.document._id} : ${e.reason}`); } } else { + console.log(error); this.logKo(JSON.stringify(error.reason)); } @@ -192,7 +193,7 @@ export abstract class Kommand extends Command { return this.exitCode; } - beforeConnect() { + async beforeConnect() { // will be called before connecting to Kuzzle } From 945573e9cc46a4a056badc8f9ac7a69ce54b82df Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 08:01:58 +0100 Subject: [PATCH 02/10] Add doco logs to check why it fail --- .github/actions/functional-test/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/functional-test/action.yml b/.github/actions/functional-test/action.yml index 75e2e713..9c5f7393 100644 --- a/.github/actions/functional-test/action.yml +++ b/.github/actions/functional-test/action.yml @@ -15,5 +15,6 @@ runs: npm install features/run-kuzzle-stack.sh npm run test:functional:${{ inputs.test-set }} + docker compose -f features/docker/docker-compose.yml logs env: KOUROU_USAGE: "false" From b0e6d85be949949885f3c59456a44660c8dfd9c6 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 08:39:50 +0100 Subject: [PATCH 03/10] use proper cucumber test --- .github/actions/functional-test/action.yml | 1 - features/Sdk.feature | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/actions/functional-test/action.yml b/.github/actions/functional-test/action.yml index 9c5f7393..75e2e713 100644 --- a/.github/actions/functional-test/action.yml +++ b/.github/actions/functional-test/action.yml @@ -15,6 +15,5 @@ runs: npm install features/run-kuzzle-stack.sh npm run test:functional:${{ inputs.test-set }} - docker compose -f features/docker/docker-compose.yml logs env: KOUROU_USAGE: "false" diff --git a/features/Sdk.feature b/features/Sdk.feature index 7054d454..d63bade0 100644 --- a/features/Sdk.feature +++ b/features/Sdk.feature @@ -31,8 +31,7 @@ Feature: SDK commands @mappings Scenario: Impersonate an user Given an existing user "pandacrobate" - When I run the command "sdk:query" with: - | arg | auth:getCurrentUser | | - | flag | --as | pandacrobate | + When I run the command "sdk:query auth:getCurrentUser" with flags: + | --as | "pandacrobate" | Then I should match stdout with: | "_id": "pandacrobate" | From 19ff7de805bb4cbc877b0e15c624dc74b3b86f40 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 08:56:35 +0100 Subject: [PATCH 04/10] Add @security tags --- features/Sdk.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/Sdk.feature b/features/Sdk.feature index d63bade0..8fc236de 100644 --- a/features/Sdk.feature +++ b/features/Sdk.feature @@ -28,7 +28,7 @@ Feature: SDK commands Then The document "document-ricky" should exist And I should match stdout with "document-ricky" - @mappings + @security Scenario: Impersonate an user Given an existing user "pandacrobate" When I run the command "sdk:query auth:getCurrentUser" with flags: From 9eeacb142ef3fe4f513e48f224c291160530457c Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 09:15:05 +0100 Subject: [PATCH 05/10] Testing --- src/support/kuzzle.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/support/kuzzle.ts b/src/support/kuzzle.ts index 1553f004..fea87ffc 100644 --- a/src/support/kuzzle.ts +++ b/src/support/kuzzle.ts @@ -165,10 +165,13 @@ export class KuzzleSDK { { expiresIn: "2h", refresh: false } as any ); + console.log(`Impersonating user ${userKuid}...`, apiKey); + this.sdk.jwt = apiKey._source.token; await callback(); } finally { + console.log("Restoring previous token..."); this.sdk.jwt = currentToken; if (apiKey?._id) { From 5547114d1ac1d210d8a10da924d7f08374430c45 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 09:27:28 +0100 Subject: [PATCH 06/10] add logs to debug --- src/common.ts | 2 -- src/support/kuzzle.ts | 27 ++++++++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/common.ts b/src/common.ts index f77c387f..486c3d55 100644 --- a/src/common.ts +++ b/src/common.ts @@ -189,8 +189,6 @@ export abstract class Kommand extends Command { process.exit(this.exitCode); } - - return this.exitCode; } async beforeConnect() { diff --git a/src/support/kuzzle.ts b/src/support/kuzzle.ts index fea87ffc..b8f6b96c 100644 --- a/src/support/kuzzle.ts +++ b/src/support/kuzzle.ts @@ -114,8 +114,7 @@ export class KuzzleSDK { this.sdk.on("networkError", (error: any) => logger.logKo(error.message)); logger.logInfo( - `Connecting to ${this.protocol}${this.ssl ? "s" : ""}://${this.host}:${ - this.port + `Connecting to ${this.protocol}${this.ssl ? "s" : ""}://${this.host}:${this.port } ...` ); @@ -155,10 +154,10 @@ export class KuzzleSDK { */ public async impersonate(userKuid: string, callback: { (): Promise }) { const currentToken = this.sdk.jwt; - let apiKey: any; try { + console.log('Starting impersonation process...'); apiKey = await this.security.createApiKey( userKuid, "Kourou impersonation token", @@ -166,20 +165,31 @@ export class KuzzleSDK { ); console.log(`Impersonating user ${userKuid}...`, apiKey); - this.sdk.jwt = apiKey._source.token; + console.log('Executing callback...'); await callback(); + console.log('Callback completed successfully'); + } catch (error) { + console.error('Error during impersonation:', error); + throw error; } finally { - console.log("Restoring previous token..."); + console.log("Starting cleanup in finally block..."); this.sdk.jwt = currentToken; if (apiKey?._id) { - await this.security.deleteApiKey(userKuid, apiKey._id); + try { + await this.security.deleteApiKey(userKuid, apiKey._id); + console.log('API key cleanup successful'); + } catch (cleanupError) { + console.error('Error cleaning up API key:', cleanupError); + } } + console.log("Cleanup completed"); } } + disconnect() { this.sdk.disconnect(); @@ -217,9 +227,8 @@ export class KuzzleSDK { } // Construct the URL - const url = `${this.ssl ? "https" : "http"}://${this.host}:${ - this.port - }/_query`; + const url = `${this.ssl ? "https" : "http"}://${this.host}:${this.port + }/_query`; // Construct the request const body = JSON.stringify(request); From fd18532807241b6e8733136ad00868373a9ae9f3 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 09:38:01 +0100 Subject: [PATCH 07/10] Callback executed too late --- src/commands/sdk/query.ts | 2 +- src/support/kuzzle.ts | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/commands/sdk/query.ts b/src/commands/sdk/query.ts index dac1bc41..d9c75523 100644 --- a/src/commands/sdk/query.ts +++ b/src/commands/sdk/query.ts @@ -114,7 +114,7 @@ Default fallback to API action static readStdin = true; - async runSafe() { + async runSafe(): Promise { const [controller, action] = this.args["controller:action"].split(":"); const requestArgs: any = {}; diff --git a/src/support/kuzzle.ts b/src/support/kuzzle.ts index b8f6b96c..f153c858 100644 --- a/src/support/kuzzle.ts +++ b/src/support/kuzzle.ts @@ -155,6 +155,7 @@ export class KuzzleSDK { public async impersonate(userKuid: string, callback: { (): Promise }) { const currentToken = this.sdk.jwt; let apiKey: any; + let callbackResult; try { console.log('Starting impersonation process...'); @@ -168,15 +169,17 @@ export class KuzzleSDK { this.sdk.jwt = apiKey._source.token; console.log('Executing callback...'); - await callback(); + callbackResult = await callback(); // Store the result console.log('Callback completed successfully'); + + return callbackResult; // Return the callback result } catch (error) { console.error('Error during impersonation:', error); throw error; } finally { console.log("Starting cleanup in finally block..."); - this.sdk.jwt = currentToken; + // Move token restoration after cleanup if (apiKey?._id) { try { await this.security.deleteApiKey(userKuid, apiKey._id); @@ -185,11 +188,15 @@ export class KuzzleSDK { console.error('Error cleaning up API key:', cleanupError); } } - console.log("Cleanup completed"); + + // Restore token last + this.sdk.jwt = currentToken; + console.log("Token restored and cleanup completed"); } } + disconnect() { this.sdk.disconnect(); From 6e193580b2c5722931aad6c5ffe30ac276401897 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 09:48:54 +0100 Subject: [PATCH 08/10] rewrite using promise based funnction --- src/support/kuzzle.ts | 76 ++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/src/support/kuzzle.ts b/src/support/kuzzle.ts index f153c858..7332a8bb 100644 --- a/src/support/kuzzle.ts +++ b/src/support/kuzzle.ts @@ -152,51 +152,59 @@ export class KuzzleSDK { * @param {Function} callback - Callback that will be impersonated * @returns {void} */ - public async impersonate(userKuid: string, callback: { (): Promise }) { + public impersonate(userKuid: string, callback: { (): Promise }): Promise { const currentToken = this.sdk.jwt; let apiKey: any; - let callbackResult; - try { + return new Promise((resolve, reject) => { console.log('Starting impersonation process...'); - apiKey = await this.security.createApiKey( + + this.security.createApiKey( userKuid, "Kourou impersonation token", { expiresIn: "2h", refresh: false } as any - ); - - console.log(`Impersonating user ${userKuid}...`, apiKey); - this.sdk.jwt = apiKey._source.token; - - console.log('Executing callback...'); - callbackResult = await callback(); // Store the result - console.log('Callback completed successfully'); - - return callbackResult; // Return the callback result - } catch (error) { - console.error('Error during impersonation:', error); - throw error; - } finally { - console.log("Starting cleanup in finally block..."); - - // Move token restoration after cleanup - if (apiKey?._id) { - try { - await this.security.deleteApiKey(userKuid, apiKey._id); - console.log('API key cleanup successful'); - } catch (cleanupError) { - console.error('Error cleaning up API key:', cleanupError); - } - } - - // Restore token last - this.sdk.jwt = currentToken; - console.log("Token restored and cleanup completed"); - } + ) + .then((createdApiKey) => { + apiKey = createdApiKey; + console.log(`Impersonating user ${userKuid}...`, apiKey); + this.sdk.jwt = apiKey._source.token; + + console.log('Executing callback...'); + return callback(); + }) + .then((result) => { + console.log('Callback completed successfully'); + resolve(result); + }) + .catch((error) => { + console.error('Error during impersonation:', error); + reject(error); + }) + .finally(() => { + console.log("Starting cleanup in finally block..."); + + const cleanup = async () => { + if (apiKey?._id) { + try { + await this.security.deleteApiKey(userKuid, apiKey._id); + console.log('API key cleanup successful'); + } catch (cleanupError) { + console.error('Error cleaning up API key:', cleanupError); + } + } + + this.sdk.jwt = currentToken; + console.log("Token restored and cleanup completed"); + }; + + return cleanup(); + }); + }); } + disconnect() { this.sdk.disconnect(); From eee7900880cda1fb6a50863d4de4953f3f4e0a39 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 10:45:54 +0100 Subject: [PATCH 09/10] update impersonate for testing --- src/support/kuzzle.ts | 61 ++++++++++++------------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/src/support/kuzzle.ts b/src/support/kuzzle.ts index 7332a8bb..ae271fc8 100644 --- a/src/support/kuzzle.ts +++ b/src/support/kuzzle.ts @@ -152,58 +152,31 @@ export class KuzzleSDK { * @param {Function} callback - Callback that will be impersonated * @returns {void} */ - public impersonate(userKuid: string, callback: { (): Promise }): Promise { - const currentToken = this.sdk.jwt; - let apiKey: any; + public async impersonate(userKuid: string, callback: { (): Promise }) { + // const currentToken = this.sdk.jwt; - return new Promise((resolve, reject) => { - console.log('Starting impersonation process...'); + let apiKey: any; - this.security.createApiKey( + try { + apiKey = await this.security.createApiKey( userKuid, "Kourou impersonation token", { expiresIn: "2h", refresh: false } as any - ) - .then((createdApiKey) => { - apiKey = createdApiKey; - console.log(`Impersonating user ${userKuid}...`, apiKey); - this.sdk.jwt = apiKey._source.token; - - console.log('Executing callback...'); - return callback(); - }) - .then((result) => { - console.log('Callback completed successfully'); - resolve(result); - }) - .catch((error) => { - console.error('Error during impersonation:', error); - reject(error); - }) - .finally(() => { - console.log("Starting cleanup in finally block..."); - - const cleanup = async () => { - if (apiKey?._id) { - try { - await this.security.deleteApiKey(userKuid, apiKey._id); - console.log('API key cleanup successful'); - } catch (cleanupError) { - console.error('Error cleaning up API key:', cleanupError); - } - } - - this.sdk.jwt = currentToken; - console.log("Token restored and cleanup completed"); - }; - - return cleanup(); - }); - }); - } + ); + + console.log(`Impersonating user ${userKuid}...`, apiKey); + this.sdk.jwt = apiKey._source.token; + await callback(); + } finally { + // this.sdk.jwt = currentToken; + // if (apiKey?._id) { + // await this.security.deleteApiKey(userKuid, apiKey._id); + // } + } + } disconnect() { this.sdk.disconnect(); From 09a166d34bee56023badcd0e2feda0a6e64ad1b8 Mon Sep 17 00:00:00 2001 From: rolljee Date: Fri, 13 Dec 2024 16:26:13 +0100 Subject: [PATCH 10/10] fix: working tests --- features/run-kuzzle-stack.sh | 2 +- .../step_definitions/common/collection-steps.js | 1 - src/commands/app/scaffold.ts | 1 - src/common.ts | 1 - src/support/kuzzle.ts | 14 ++++++-------- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/features/run-kuzzle-stack.sh b/features/run-kuzzle-stack.sh index c4d78fbd..7dc9f13c 100755 --- a/features/run-kuzzle-stack.sh +++ b/features/run-kuzzle-stack.sh @@ -4,7 +4,7 @@ set -e # Create the folder where will be stored snapshots mkdir -p /tmp/snapshots -# chmod 777 -R /tmp/snapshots +chmod 777 -R /tmp/snapshots # Launch the kuzzle stack docker compose -f features/docker/docker-compose.yml up -d diff --git a/features/step_definitions/common/collection-steps.js b/features/step_definitions/common/collection-steps.js index 14483057..bb0f015f 100644 --- a/features/step_definitions/common/collection-steps.js +++ b/features/step_definitions/common/collection-steps.js @@ -31,7 +31,6 @@ Given( try { await this.sdk.security.getUser(userId); } catch (error) { - console.log('✔ User not found, creating...'); await this.sdk.security.createUser(userId, { content: { profileIds: ['default'] diff --git a/src/commands/app/scaffold.ts b/src/commands/app/scaffold.ts index 9067c11e..f39eec5b 100644 --- a/src/commands/app/scaffold.ts +++ b/src/commands/app/scaffold.ts @@ -62,7 +62,6 @@ export default class AppScaffold extends Kommand { } getRepo(flavor: string) { - console.log(flavor); switch (flavor) { case "generic": return "template-kuzzle-project"; diff --git a/src/common.ts b/src/common.ts index 486c3d55..70dafc37 100644 --- a/src/common.ts +++ b/src/common.ts @@ -165,7 +165,6 @@ export abstract class Kommand extends Command { this.logKo(`${e.document._id} : ${e.reason}`); } } else { - console.log(error); this.logKo(JSON.stringify(error.reason)); } diff --git a/src/support/kuzzle.ts b/src/support/kuzzle.ts index ae271fc8..2d4c62a7 100644 --- a/src/support/kuzzle.ts +++ b/src/support/kuzzle.ts @@ -153,7 +153,7 @@ export class KuzzleSDK { * @returns {void} */ public async impersonate(userKuid: string, callback: { (): Promise }) { - // const currentToken = this.sdk.jwt; + const currentToken = this.sdk.jwt; let apiKey: any; @@ -161,20 +161,18 @@ export class KuzzleSDK { apiKey = await this.security.createApiKey( userKuid, "Kourou impersonation token", - { expiresIn: "2h", refresh: false } as any + { expiresIn: "2h", refresh: "wait_for" } as any ); - console.log(`Impersonating user ${userKuid}...`, apiKey); - this.sdk.jwt = apiKey._source.token; await callback(); } finally { - // this.sdk.jwt = currentToken; + this.sdk.jwt = currentToken; - // if (apiKey?._id) { - // await this.security.deleteApiKey(userKuid, apiKey._id); - // } + if (apiKey?._id) { + await this.security.deleteApiKey(userKuid, apiKey._id); + } } }