From a59de60e40b6f3617a4278837e0c63fcb5752d16 Mon Sep 17 00:00:00 2001 From: rajdip-b Date: Sun, 23 Feb 2025 11:13:31 +0530 Subject: [PATCH 01/15] fix(platform): Add graceful fallback in error parsing --- apps/platform/src/hooks/use-http.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/platform/src/hooks/use-http.ts b/apps/platform/src/hooks/use-http.ts index f971b1f4..e8a03651 100644 --- a/apps/platform/src/hooks/use-http.ts +++ b/apps/platform/src/hooks/use-http.ts @@ -37,14 +37,20 @@ export function useHttp>( handle403() } else if (statusCode.toString().startsWith('4')) { // For 4xx errors - const { header, body } = JSON.parse(response.error.message) as { - header: string - body: string - } + try { + const { header, body } = JSON.parse(response.error.message) as { + header: string + body: string + } - toast.error(header, { - description: body - }) + toast.error(header, { + description: body + }) + } catch (error) { + toast.error('Faced an error processing your request', { + description: response.error.message + }) + } } else if (statusCode === 500) { handle500(response.error) } From 51c0464918d3cce2657f78bafc4818217f91a6de Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 23 Feb 2025 05:44:46 +0000 Subject: [PATCH 02/15] chore(release): 2.12.0-stage.13 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.12.0-stage.13](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.12...v2.12.0-stage.13) (2025-02-23) ### 🐛 Bug Fixes * **platform:** Add graceful fallback in error parsing ([a59de60](https://github.com/keyshade-xyz/keyshade/commit/a59de60e40b6f3617a4278837e0c63fcb5752d16)) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f8fec1..d7686d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.12.0-stage.13](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.12...v2.12.0-stage.13) (2025-02-23) + +### 🐛 Bug Fixes + +* **platform:** Add graceful fallback in error parsing ([a59de60](https://github.com/keyshade-xyz/keyshade/commit/a59de60e40b6f3617a4278837e0c63fcb5752d16)) + ## [2.12.0-stage.12](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.11...v2.12.0-stage.12) (2025-02-22) ### 🚀 Features diff --git a/package.json b/package.json index 049b6ba3..870726ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keyshade-xyz", - "version": "2.12.0-stage.12", + "version": "2.12.0-stage.13", "license": "MPL-2.0", "private": true, "engineStrict": false, From b373eeb5974ee61bd07ce586da4b56dbd0d10fab Mon Sep 17 00:00:00 2001 From: csehatt741 <77381875+csehatt741@users.noreply.github.com> Date: Sun, 23 Feb 2025 11:00:48 +0100 Subject: [PATCH 03/15] fix(api): Issue fetched via API (#788) --- .github/workflows/auto-assign.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/auto-assign.yaml b/.github/workflows/auto-assign.yaml index a4268bc6..33e1e7d8 100644 --- a/.github/workflows/auto-assign.yaml +++ b/.github/workflows/auto-assign.yaml @@ -15,32 +15,32 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const comment = context.payload.comment; - const issue = context.issue; + const issue = context.payload.issue; const owner = 'keyshade-xyz'; const repo = 'keyshade'; const userMaxConcurrentIssueCount = process.env.USER_MAX_CONCURRENT_ISSUE_COUNT || 5; - async function listIssueEvents(issue) { - const allEvents = []; + async function listIssueEvents(issueNumber) { + const events = []; let page = 1; let hasNextPage = true; while (hasNextPage) { - const issuesResponse = await github.rest.issues.listEventsForTimeline({ + const eventsResponse = await github.rest.issues.listEventsForTimeline({ owner, repo, - issue_number: issue.number, + issue_number: issueNumber, per_page: 100, page }); - allEvents.push(...issuesResponse.data); + events.push(...eventsResponse.data); - hasNextPage = issuesResponse.headers.link && issuesResponse.headers.link.includes('rel="next"'); + hasNextPage = eventsResponse.headers.link && eventsResponse.headers.link.includes('rel="next"'); page++; } - return allEvents; + return events; } async function listUserOpenIssuesWithoutActivePullRequest(user) { @@ -55,7 +55,7 @@ jobs: }); for (const issue of userOpenIssues) { - const events = await listIssueEvents(issue); + const events = await listIssueEvents(issue.number); const userPullRequestIssues = events .filter(event => event.event === 'cross-referenced') .map(event => event.source.issue) From 3baf084fcf13dee2e82f0613af854172f4cb4e0a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 23 Feb 2025 10:01:30 +0000 Subject: [PATCH 04/15] chore(release): 2.12.0-stage.14 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.12.0-stage.14](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.13...v2.12.0-stage.14) (2025-02-23) ### 🐛 Bug Fixes * **api:** Issue fetched via API ([#788](https://github.com/keyshade-xyz/keyshade/issues/788)) ([b373eeb](https://github.com/keyshade-xyz/keyshade/commit/b373eeb5974ee61bd07ce586da4b56dbd0d10fab)) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7686d76..699e7a05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.12.0-stage.14](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.13...v2.12.0-stage.14) (2025-02-23) + +### 🐛 Bug Fixes + +* **api:** Issue fetched via API ([#788](https://github.com/keyshade-xyz/keyshade/issues/788)) ([b373eeb](https://github.com/keyshade-xyz/keyshade/commit/b373eeb5974ee61bd07ce586da4b56dbd0d10fab)) + ## [2.12.0-stage.13](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.12...v2.12.0-stage.13) (2025-02-23) ### 🐛 Bug Fixes diff --git a/package.json b/package.json index 870726ec..4ac8c131 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keyshade-xyz", - "version": "2.12.0-stage.13", + "version": "2.12.0-stage.14", "license": "MPL-2.0", "private": true, "engineStrict": false, From f6ddf0fc54280c9844143ac42840fcbde1438b23 Mon Sep 17 00:00:00 2001 From: Allan Joston Fernandes <54631653+Allan2000-Git@users.noreply.github.com> Date: Sun, 23 Feb 2025 15:37:47 +0530 Subject: [PATCH 05/15] fix(api): Added import statement for crypto module (#789) --- apps/api/src/common/util.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/api/src/common/util.ts b/apps/api/src/common/util.ts index fa68f88f..25dd50f2 100644 --- a/apps/api/src/common/util.ts +++ b/apps/api/src/common/util.ts @@ -2,6 +2,7 @@ import { UserAuthenticatedResponse } from '@/auth/auth.types' import { UserWithWorkspace } from '@/user/user.types' import { Otp, PrismaClient, User } from '@prisma/client' import { Response } from 'express' +import * as crypto from 'crypto' /** * Limits the given limit to a maximum number of items per page. From d8c58fe052e327c884a6f0d40e509f0b19d6ab03 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 23 Feb 2025 10:08:24 +0000 Subject: [PATCH 06/15] chore(release): 2.12.0-stage.15 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.12.0-stage.15](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.14...v2.12.0-stage.15) (2025-02-23) ### 🐛 Bug Fixes * **api:** Added import statement for crypto module ([#789](https://github.com/keyshade-xyz/keyshade/issues/789)) ([f6ddf0f](https://github.com/keyshade-xyz/keyshade/commit/f6ddf0fc54280c9844143ac42840fcbde1438b23)) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 699e7a05..a7831618 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.12.0-stage.15](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.14...v2.12.0-stage.15) (2025-02-23) + +### 🐛 Bug Fixes + +* **api:** Added import statement for crypto module ([#789](https://github.com/keyshade-xyz/keyshade/issues/789)) ([f6ddf0f](https://github.com/keyshade-xyz/keyshade/commit/f6ddf0fc54280c9844143ac42840fcbde1438b23)) + ## [2.12.0-stage.14](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.13...v2.12.0-stage.14) (2025-02-23) ### 🐛 Bug Fixes diff --git a/package.json b/package.json index 4ac8c131..7d031741 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keyshade-xyz", - "version": "2.12.0-stage.14", + "version": "2.12.0-stage.15", "license": "MPL-2.0", "private": true, "engineStrict": false, From f17410100d845a28affc25d369733facd3809ab5 Mon Sep 17 00:00:00 2001 From: rajdip-b Date: Sun, 23 Feb 2025 17:42:23 +0530 Subject: [PATCH 07/15] chore(ci): Remove PR unassign script --- .github/workflows/pr-close.yaml | 115 -------------------------------- 1 file changed, 115 deletions(-) delete mode 100644 .github/workflows/pr-close.yaml diff --git a/.github/workflows/pr-close.yaml b/.github/workflows/pr-close.yaml deleted file mode 100644 index 5ecec9f8..00000000 --- a/.github/workflows/pr-close.yaml +++ /dev/null @@ -1,115 +0,0 @@ -name: PR Close - -on: - schedule: - - cron: '0 * * * *' # Runs every hour - -jobs: - pr-close: - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@v7 - env: - CLOSE_PR_ENABLED: ${{ vars.CLOSE_PR_ENABLED }} - CLOSE_PR_AFTER_DAYS: ${{ vars.CLOSE_PR_AFTER_DAYS }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const owner = 'keyshade-xyz'; - const repo = 'keyshade'; - const closePrEnabled = process.env.CLOSE_PR_ENABLED || false; - const closePrAfterDays = process.env.CLOSE_PR_AFTER_DAYS || 7; - const closePrAfterMilliseconds = closePrAfterDays * 24 * 60 * 60 * 1000; - const now = Date.now(); - - if(!closePrEnabled) { - console.log('!!! Dry run, there are no changes made !!!'); - } - - async function listOpenPrs() { - const pullRequests = []; - let page = 1; - let hasNextPage = true; - - while (hasNextPage) { - const pullRequestsResponse = await github.rest.pulls.list({ - owner, - repo, - state: 'open', - per_page: 100, - page - }); - - pullRequests.push(...pullRequestsResponse.data); - - hasNextPage = pullRequestsResponse.headers.link && pullRequestsResponse.headers.link.includes('rel="next"'); - page++; - } - - return pullRequests; - } - - async function listPrReviews(pullRequest) { - const reviews = []; - let page = 1; - let hasNextPage = true; - - while (hasNextPage) { - const reviewsResponse = await github.rest.pulls.listReviews({ - owner, - repo, - pull_number: pullRequest.number, - per_page: 100, - page - }); - - reviews.push(...reviewsResponse.data); - - hasNextPage = reviewsResponse.headers.link && reviewsResponse.headers.link.includes('rel="next"'); - page++; - } - - return reviews; - } - - async function closePrs() { - const pullRequests = await listOpenPrs(); - - for (const pullRequest of pullRequests) { - const reviews = await listPrReviews(pullRequest); - const unapprovedReviews = reviews.filter(review => review.state !== 'APPROVED'); - const pullRequestCreatedAt = new Date(pullRequest.created_at); - - // Check if PR has unapproved reviews - if(unapprovedReviews.length === 0) { - continue; - } - - // Check if it is time to close PR - const closePrAfter = new Date(pullRequestCreatedAt.getTime() + closePrAfterMilliseconds); - - if (now < closePrAfter) { - continue; - } - - if(closePrEnabled) { - await github.rest.pulls.update({ - owner, - repo, - pull_number: pullRequest.number, - state: 'closed' - }); - - await github.rest.issues.createComment({ - owner, - repo, - issue_number: pullRequest.number, - body: `PR closed due to inactivity`, - }); - } - - console.log(`PR '${pullRequest.number}' closed`); - } - } - - await closePrs(); \ No newline at end of file From 688e11c201f1cbdc77b8906805f384aad85f90ab Mon Sep 17 00:00:00 2001 From: Agastya sharma <72289680+Agastya221@users.noreply.github.com> Date: Sun, 23 Feb 2025 17:52:59 +0530 Subject: [PATCH 08/15] fix(web): Misalignment of toast message after joining the waitlist (#791) Co-authored-by: Rajdip Bhattacharya --- apps/web/src/components/hero/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/hero/index.tsx b/apps/web/src/components/hero/index.tsx index b87461e2..4004b1e1 100644 --- a/apps/web/src/components/hero/index.tsx +++ b/apps/web/src/components/hero/index.tsx @@ -55,9 +55,9 @@ function Hero(): React.JSX.Element { }) toast.custom((_t) => ( -
+

Welcome to Keyshade 🎉

-

+

You have been added to the waitlist. We will notify you once we launch

From ff891ae378080cbeb7599f1eee6cdaf8cbf283cb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 23 Feb 2025 12:23:48 +0000 Subject: [PATCH 09/15] chore(release): 2.12.0-stage.16 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.12.0-stage.16](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.15...v2.12.0-stage.16) (2025-02-23) ### 🐛 Bug Fixes * **web:** Misalignment of toast message after joining the waitlist ([#791](https://github.com/keyshade-xyz/keyshade/issues/791)) ([688e11c](https://github.com/keyshade-xyz/keyshade/commit/688e11c201f1cbdc77b8906805f384aad85f90ab)) ### 🔧 Miscellaneous Chores * **ci:** Remove PR unassign script ([f174101](https://github.com/keyshade-xyz/keyshade/commit/f17410100d845a28affc25d369733facd3809ab5)) --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7831618..60dc3954 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [2.12.0-stage.16](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.15...v2.12.0-stage.16) (2025-02-23) + +### 🐛 Bug Fixes + +* **web:** Misalignment of toast message after joining the waitlist ([#791](https://github.com/keyshade-xyz/keyshade/issues/791)) ([688e11c](https://github.com/keyshade-xyz/keyshade/commit/688e11c201f1cbdc77b8906805f384aad85f90ab)) + +### 🔧 Miscellaneous Chores + +* **ci:** Remove PR unassign script ([f174101](https://github.com/keyshade-xyz/keyshade/commit/f17410100d845a28affc25d369733facd3809ab5)) + ## [2.12.0-stage.15](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.14...v2.12.0-stage.15) (2025-02-23) ### 🐛 Bug Fixes diff --git a/package.json b/package.json index 7d031741..c39c2ea1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keyshade-xyz", - "version": "2.12.0-stage.15", + "version": "2.12.0-stage.16", "license": "MPL-2.0", "private": true, "engineStrict": false, From 8e30f15449fcf3333c7eaa26f4d8c6bd02f8b0a6 Mon Sep 17 00:00:00 2001 From: Rajdip Bhattacharya Date: Wed, 26 Feb 2025 19:05:55 +0530 Subject: [PATCH 10/15] fix(api): Issue with authorities and expiry field update in API Key (#800) --- .../Api Key Controller/Update API key.bru | 15 ++------------- .../api-key/dto/create.api-key/create.api-key.ts | 2 +- apps/api/src/api-key/service/api-key.service.ts | 4 +--- apps/api/src/common/util.ts | 4 ++-- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/api-collection/Api Key Controller/Update API key.bru b/api-collection/Api Key Controller/Update API key.bru index fb3140a5..54bf1a66 100644 --- a/api-collection/Api Key Controller/Update API key.bru +++ b/api-collection/Api Key Controller/Update API key.bru @@ -11,7 +11,7 @@ put { } params:path { - api_key_slug: my-key-2 + api_key_slug: test-key-0 } auth:bearer { @@ -20,18 +20,7 @@ auth:bearer { body:json { { - "authorities": [ - "READ_API_KEY", - "READ_WORKSPACE", - "READ_PROJECT", - "READ_ENVIRONMENT", - "READ_VARIABLE", - "READ_SECRET", - "CREATE_WORKSPACE", - "UPDATE_WORKSPACE", - "DELETE_WORKSPACE", - "WORKSPACE_ADMIN" - ] + "expiresAfter": "never" } } diff --git a/apps/api/src/api-key/dto/create.api-key/create.api-key.ts b/apps/api/src/api-key/dto/create.api-key/create.api-key.ts index c256390b..55527e07 100644 --- a/apps/api/src/api-key/dto/create.api-key/create.api-key.ts +++ b/apps/api/src/api-key/dto/create.api-key/create.api-key.ts @@ -11,5 +11,5 @@ export class CreateApiKey { @IsArray() @IsOptional() - authorities?: Authority[] = [] + authorities?: Authority[] } diff --git a/apps/api/src/api-key/service/api-key.service.ts b/apps/api/src/api-key/service/api-key.service.ts index b9b21672..76714f08 100644 --- a/apps/api/src/api-key/service/api-key.service.ts +++ b/apps/api/src/api-key/service/api-key.service.ts @@ -125,9 +125,7 @@ export class ApiKeyService { slug: dto.name ? await generateEntitySlug(dto.name, 'API_KEY', this.prisma) : apiKey.slug, - authorities: { - set: dto.authorities ? dto.authorities : apiKey.authorities - }, + authorities: dto.authorities ? dto.authorities : undefined, expiresAt: dto.expiresAfter ? addHoursToDate(dto.expiresAfter) : undefined diff --git a/apps/api/src/common/util.ts b/apps/api/src/common/util.ts index 25dd50f2..38309ee0 100644 --- a/apps/api/src/common/util.ts +++ b/apps/api/src/common/util.ts @@ -98,8 +98,8 @@ export const excludeFields = ( * @param hours The number of hours to add to the current date * @returns The new date with the given number of hours added, or undefined if the hours is 'never' */ -export const addHoursToDate = (hours?: string | number): Date | undefined => { - if (!hours || hours === 'never') return undefined +export const addHoursToDate = (hours?: string | number): Date | null => { + if (!hours || hours === 'never') return null const date = new Date() date.setHours(date.getHours() + +hours) From 1047671e94a11934c3bb926cc2cc7d79853b7db9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 26 Feb 2025 13:36:48 +0000 Subject: [PATCH 11/15] chore(release): 2.12.0-stage.17 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.12.0-stage.17](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.16...v2.12.0-stage.17) (2025-02-26) ### 🐛 Bug Fixes * **api:** Issue with authorities and expiry field update in API Key ([#800](https://github.com/keyshade-xyz/keyshade/issues/800)) ([8e30f15](https://github.com/keyshade-xyz/keyshade/commit/8e30f15449fcf3333c7eaa26f4d8c6bd02f8b0a6)) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60dc3954..893b6967 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.12.0-stage.17](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.16...v2.12.0-stage.17) (2025-02-26) + +### 🐛 Bug Fixes + +* **api:** Issue with authorities and expiry field update in API Key ([#800](https://github.com/keyshade-xyz/keyshade/issues/800)) ([8e30f15](https://github.com/keyshade-xyz/keyshade/commit/8e30f15449fcf3333c7eaa26f4d8c6bd02f8b0a6)) + ## [2.12.0-stage.16](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.15...v2.12.0-stage.16) (2025-02-23) ### 🐛 Bug Fixes diff --git a/package.json b/package.json index c39c2ea1..8e2a9da8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keyshade-xyz", - "version": "2.12.0-stage.16", + "version": "2.12.0-stage.17", "license": "MPL-2.0", "private": true, "engineStrict": false, From 03229446207dc7bc55d0aed5a049255fcc86ede3 Mon Sep 17 00:00:00 2001 From: csehatt741 <77381875+csehatt741@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:37:29 +0100 Subject: [PATCH 12/15] feat(cli): Error message formatted (#797) Co-authored-by: Rajdip Bhattacharya --- apps/cli/src/commands/base.command.ts | 37 +++++++++++++++++++ .../environment/create.environment.ts | 5 +-- .../environment/delete.environment.ts | 5 +-- .../commands/environment/get.environment.ts | 5 +-- .../commands/environment/list.environment.ts | 5 +-- .../environment/update.environment.ts | 7 +--- .../src/commands/project/create.project.ts | 5 +-- .../src/commands/project/delete.project.ts | 5 +-- apps/cli/src/commands/project/fork.project.ts | 5 +-- apps/cli/src/commands/project/get.project.ts | 5 +-- .../commands/project/list-forks.project.ts | 7 +--- apps/cli/src/commands/project/list.project.ts | 5 +-- apps/cli/src/commands/project/sync.project.ts | 5 +-- .../src/commands/project/unlink.project.ts | 5 +-- .../src/commands/project/update.project.ts | 5 +-- apps/cli/src/commands/secret/create.secret.ts | 5 +-- apps/cli/src/commands/secret/delete.secret.ts | 5 +-- apps/cli/src/commands/secret/list.secret.ts | 7 +--- .../src/commands/secret/revisions.secret.ts | 5 +-- .../src/commands/secret/rollback.secret.ts | 5 +-- apps/cli/src/commands/secret/update.secret.ts | 5 +-- .../src/commands/variable/create.variable.ts | 5 +-- .../src/commands/variable/delete.variable.ts | 5 +-- .../src/commands/variable/list.variable.ts | 7 +--- .../commands/variable/revisions.variable.ts | 7 +--- .../commands/variable/rollback.variable.ts | 5 +-- .../src/commands/variable/update.variable.ts | 5 +-- .../commands/workspace/create.workspace.ts | 5 +-- .../commands/workspace/delete.workspace.ts | 5 +-- .../commands/workspace/export.workspace.ts | 5 +-- .../src/commands/workspace/get.workspace.ts | 5 +-- .../src/commands/workspace/list.workspace.ts | 5 +-- .../accept-invitation.membership.ts | 5 +-- .../cancel-invitation.membership.ts | 5 +-- .../decline-invitation.membership.ts | 5 +-- .../membership/get-all-members.membership.ts | 5 +-- .../workspace/membership/invite.membership.ts | 5 +-- .../workspace/membership/leave.membership.ts | 5 +-- .../workspace/membership/remove.membership.ts | 5 +-- .../transfer-ownership.membership copy.ts | 5 +-- .../membership/update-role.membership.ts | 5 +-- .../commands/workspace/role/create.role.ts | 7 +--- .../commands/workspace/role/delete.role.ts | 7 +--- .../src/commands/workspace/role/get.role.ts | 7 +--- .../src/commands/workspace/role/list.role.ts | 7 +--- .../commands/workspace/role/update.role.ts | 7 +--- .../commands/workspace/search.workspace.ts | 7 +--- .../commands/workspace/update.workspace.ts | 5 +-- 48 files changed, 84 insertions(+), 210 deletions(-) diff --git a/apps/cli/src/commands/base.command.ts b/apps/cli/src/commands/base.command.ts index 7d96da9c..c8740afc 100644 --- a/apps/cli/src/commands/base.command.ts +++ b/apps/cli/src/commands/base.command.ts @@ -159,6 +159,43 @@ export default abstract class BaseCommand { return '' } + /** + * Logs the error + * @param message The error message + * @param error The error object containing details about the error + */ + protected logError(error: { + message: string + error: string + statusCode: number + }): void { + const { header, body } = this.extractError(error) + + Logger.error(`${header}: ${body}`) + if (this.metricsEnabled && error?.statusCode === 500) { + Logger.report(`${header}.\n` + JSON.stringify(error)) + } + } + + private extractError(error: { + message: string + error: string + statusCode: number + }) { + try { + const { header, body } = JSON.parse(error.message) as { + header: string + body: string + } + return { header, body } + } catch { + return { + header: 'Faced an error processing the request', + body: error.message + } + } + } + private async setGlobalContextFields( globalOptions: Record ): Promise { diff --git a/apps/cli/src/commands/environment/create.environment.ts b/apps/cli/src/commands/environment/create.environment.ts index 4940dfb9..aa36a0e6 100644 --- a/apps/cli/src/commands/environment/create.environment.ts +++ b/apps/cli/src/commands/environment/create.environment.ts @@ -71,10 +71,7 @@ export class CreateEnvironment extends BaseCommand { `Environment created:${environment.name} (${environment.slug})` ) } else { - Logger.error(`Failed to create environment: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to create environment.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/environment/delete.environment.ts b/apps/cli/src/commands/environment/delete.environment.ts index 393adb0f..2935a7b2 100644 --- a/apps/cli/src/commands/environment/delete.environment.ts +++ b/apps/cli/src/commands/environment/delete.environment.ts @@ -47,10 +47,7 @@ export class DeleteEnvironment extends BaseCommand { if (success) { Logger.info('Environment deleted successfully') } else { - Logger.error(`Error deleting environment: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Error deleting environment.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/environment/get.environment.ts b/apps/cli/src/commands/environment/get.environment.ts index f4cd4bba..5720dc2a 100644 --- a/apps/cli/src/commands/environment/get.environment.ts +++ b/apps/cli/src/commands/environment/get.environment.ts @@ -54,10 +54,7 @@ export class GetEnvironment extends BaseCommand { Logger.info(`Created On: ${environment.createdAt}`) Logger.info(`Updated On: ${environment.updatedAt}`) } else { - Logger.error(`Error fetching environment: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed fetching environment.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/environment/list.environment.ts b/apps/cli/src/commands/environment/list.environment.ts index 458ba3f8..a7a2d7ad 100644 --- a/apps/cli/src/commands/environment/list.environment.ts +++ b/apps/cli/src/commands/environment/list.environment.ts @@ -59,10 +59,7 @@ export class ListEnvironment extends BaseCommand { Logger.info(`- ${environment.name} (${environment.slug})`) }) } else { - Logger.error(`Failed to fetch environments: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to fetch environments.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/environment/update.environment.ts b/apps/cli/src/commands/environment/update.environment.ts index b2e298f4..4173c331 100644 --- a/apps/cli/src/commands/environment/update.environment.ts +++ b/apps/cli/src/commands/environment/update.environment.ts @@ -70,12 +70,7 @@ export class UpdateEnvironment extends BaseCommand { `Environment Slug: ${environment.slug}, Name: ${environment.name}, Description: ${environment.description}` ) } else { - Logger.error( - `Error updating Environment: ${error.message} (${error.statusCode})` - ) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Error updating environment.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/create.project.ts b/apps/cli/src/commands/project/create.project.ts index b16d282d..e8f19c5c 100644 --- a/apps/cli/src/commands/project/create.project.ts +++ b/apps/cli/src/commands/project/create.project.ts @@ -99,10 +99,7 @@ Examples: Logger.info(`Private key: ${data.privateKey}`) Logger.info(`Access level: ${data.accessLevel}`) } else { - Logger.error(`Failed to create project: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to create project.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/project/delete.project.ts b/apps/cli/src/commands/project/delete.project.ts index d72aa241..4fb46ba3 100644 --- a/apps/cli/src/commands/project/delete.project.ts +++ b/apps/cli/src/commands/project/delete.project.ts @@ -42,10 +42,7 @@ export default class DeleteProject extends BaseCommand { if (success) { Logger.info(`Project ${projectSlug} deleted successfully!`) } else { - Logger.error(`Failed to delete project: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to delete project.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/fork.project.ts b/apps/cli/src/commands/project/fork.project.ts index 248ffbce..6be88421 100644 --- a/apps/cli/src/commands/project/fork.project.ts +++ b/apps/cli/src/commands/project/fork.project.ts @@ -69,10 +69,7 @@ export default class ForkProject extends BaseCommand { Logger.info(`Created at ${data.createdAt}`) Logger.info(`Updated at ${data.updatedAt}`) } else { - Logger.error(`Failed to fork project: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to fork project.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/get.project.ts b/apps/cli/src/commands/project/get.project.ts index 94185176..75133a49 100644 --- a/apps/cli/src/commands/project/get.project.ts +++ b/apps/cli/src/commands/project/get.project.ts @@ -48,10 +48,7 @@ export default class GetProject extends BaseCommand { Logger.info(`Is Forked: ${data.isForked}`) Logger.info(`Access Level: ${data.accessLevel}`) } else { - Logger.error(`Failed fetching project: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed fetching project.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/list-forks.project.ts b/apps/cli/src/commands/project/list-forks.project.ts index cb1b046a..e02a7f98 100644 --- a/apps/cli/src/commands/project/list-forks.project.ts +++ b/apps/cli/src/commands/project/list-forks.project.ts @@ -47,12 +47,7 @@ export default class ListProjectForks extends BaseCommand { Logger.info('No forks found') } } else { - Logger.error(`Failed fetching forks: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed fetching project forks.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/list.project.ts b/apps/cli/src/commands/project/list.project.ts index cdec7b25..6bcdca5c 100644 --- a/apps/cli/src/commands/project/list.project.ts +++ b/apps/cli/src/commands/project/list.project.ts @@ -50,10 +50,7 @@ export default class ListProject extends BaseCommand { Logger.info('No projects found') } } else { - Logger.error(`Failed fetching projects: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed fetching projects.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/sync.project.ts b/apps/cli/src/commands/project/sync.project.ts index 70ad9fc5..ace31c77 100644 --- a/apps/cli/src/commands/project/sync.project.ts +++ b/apps/cli/src/commands/project/sync.project.ts @@ -56,10 +56,7 @@ export default class SyncProject extends BaseCommand { if (success) { Logger.info(`Project ${projectSlug} synced successfully!`) } else { - Logger.error(`Failed to sync project: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to sync project.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/unlink.project.ts b/apps/cli/src/commands/project/unlink.project.ts index 66b08c47..63c31df8 100644 --- a/apps/cli/src/commands/project/unlink.project.ts +++ b/apps/cli/src/commands/project/unlink.project.ts @@ -43,10 +43,7 @@ export default class UnlinkProject extends BaseCommand { if (success) { Logger.info(`Project ${projectSlug} unlinked successfully!`) } else { - Logger.error(`Failed to unlink project: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to unlink project.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/project/update.project.ts b/apps/cli/src/commands/project/update.project.ts index 8e8bdd7d..87a156a8 100644 --- a/apps/cli/src/commands/project/update.project.ts +++ b/apps/cli/src/commands/project/update.project.ts @@ -74,10 +74,7 @@ export default class UpdateProject extends BaseCommand { Logger.info(`Created at ${data.createdAt}`) Logger.info(`Updated at ${data.updatedAt}`) } else { - Logger.error(`Failed to update project: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to update project.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/secret/create.secret.ts b/apps/cli/src/commands/secret/create.secret.ts index c7d82453..5629fd02 100644 --- a/apps/cli/src/commands/secret/create.secret.ts +++ b/apps/cli/src/commands/secret/create.secret.ts @@ -96,10 +96,7 @@ export default class CreateSecret extends BaseCommand { Logger.info(`Created at ${data.secret.createdAt}`) Logger.info(`Updated at ${data.secret.updatedAt}`) } else { - Logger.error(`Failed to create secret: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to create secret.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/secret/delete.secret.ts b/apps/cli/src/commands/secret/delete.secret.ts index 23684bde..3aea6004 100644 --- a/apps/cli/src/commands/secret/delete.secret.ts +++ b/apps/cli/src/commands/secret/delete.secret.ts @@ -50,10 +50,7 @@ export default class DeleteSecret extends BaseCommand { if (success) { Logger.info(`Secret ${secretSlug} deleted successfully!`) } else { - Logger.error(`Failed to delete secret: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to delete secret.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/secret/list.secret.ts b/apps/cli/src/commands/secret/list.secret.ts index 2217cf70..28dfd782 100644 --- a/apps/cli/src/commands/secret/list.secret.ts +++ b/apps/cli/src/commands/secret/list.secret.ts @@ -92,12 +92,7 @@ export default class ListSecret extends BaseCommand { Logger.info('No secrets found') } } else { - Logger.error(`Failed fetching secrets: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed fetching secrets for project.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/secret/revisions.secret.ts b/apps/cli/src/commands/secret/revisions.secret.ts index cafbae80..7b5f5e9a 100644 --- a/apps/cli/src/commands/secret/revisions.secret.ts +++ b/apps/cli/src/commands/secret/revisions.secret.ts @@ -96,10 +96,7 @@ export default class FetchSecretRevisions extends BaseCommand { Logger.info('No revisions found') } } else { - Logger.error(`Failed fetching revisions: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed fetching revisions.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/secret/rollback.secret.ts b/apps/cli/src/commands/secret/rollback.secret.ts index f460a103..40297e8f 100644 --- a/apps/cli/src/commands/secret/rollback.secret.ts +++ b/apps/cli/src/commands/secret/rollback.secret.ts @@ -70,10 +70,7 @@ export default class RollbackSecret extends BaseCommand { if (success) { Logger.info(`Secret rolled back by ${data.count} versions successfully.`) } else { - Logger.error(`Failed to rollback secret: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to rollback secret.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/secret/update.secret.ts b/apps/cli/src/commands/secret/update.secret.ts index 128c191b..db745371 100644 --- a/apps/cli/src/commands/secret/update.secret.ts +++ b/apps/cli/src/commands/secret/update.secret.ts @@ -86,10 +86,7 @@ export default class UpdateSecret extends BaseCommand { if (success) { Logger.info('Secret updated successfully') } else { - Logger.error(`Failed to update secret: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to update secret.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/variable/create.variable.ts b/apps/cli/src/commands/variable/create.variable.ts index 0463aee3..3509308a 100644 --- a/apps/cli/src/commands/variable/create.variable.ts +++ b/apps/cli/src/commands/variable/create.variable.ts @@ -90,10 +90,7 @@ export default class CreateVariable extends BaseCommand { Logger.info(`Created at ${data.variable.createdAt}`) Logger.info(`Updated at ${data.variable.updatedAt}`) } else { - Logger.error(`Failed to create variable: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to create variable.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/variable/delete.variable.ts b/apps/cli/src/commands/variable/delete.variable.ts index 6939f2ab..2eda2c3a 100644 --- a/apps/cli/src/commands/variable/delete.variable.ts +++ b/apps/cli/src/commands/variable/delete.variable.ts @@ -50,10 +50,7 @@ export default class DeleteVariable extends BaseCommand { if (success) { Logger.info(`Variable ${variableSlug} deleted successfully!`) } else { - Logger.error(`Failed to delete variable: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to delete variable.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/variable/list.variable.ts b/apps/cli/src/commands/variable/list.variable.ts index 822cb5f6..b8ef52b8 100644 --- a/apps/cli/src/commands/variable/list.variable.ts +++ b/apps/cli/src/commands/variable/list.variable.ts @@ -78,12 +78,7 @@ export default class ListVariable extends BaseCommand { Logger.info('No variables found') } } else { - Logger.error(`Failed fetching variables: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed fetching variables for project.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/variable/revisions.variable.ts b/apps/cli/src/commands/variable/revisions.variable.ts index ba6603c5..fbcc13b4 100644 --- a/apps/cli/src/commands/variable/revisions.variable.ts +++ b/apps/cli/src/commands/variable/revisions.variable.ts @@ -90,12 +90,7 @@ export default class FetchVariableRevisions extends BaseCommand { Logger.info('No revisions found') } } else { - Logger.error(`Failed fetching revisions: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed fetching revisions for variable.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/variable/rollback.variable.ts b/apps/cli/src/commands/variable/rollback.variable.ts index 885fd7b4..09ca79c4 100644 --- a/apps/cli/src/commands/variable/rollback.variable.ts +++ b/apps/cli/src/commands/variable/rollback.variable.ts @@ -71,10 +71,7 @@ export default class RollbackVariable extends BaseCommand { `Variable rolled back by ${data.count} versions successfully!` ) } else { - Logger.error(`Failed to update variable: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to rollback variable.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/variable/update.variable.ts b/apps/cli/src/commands/variable/update.variable.ts index 5ae271c7..5834e5ce 100644 --- a/apps/cli/src/commands/variable/update.variable.ts +++ b/apps/cli/src/commands/variable/update.variable.ts @@ -76,10 +76,7 @@ export default class UpdateVariable extends BaseCommand { if (success) { Logger.info('Variable updated successfully!') } else { - Logger.error(`Failed to update variable: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to update variable.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/workspace/create.workspace.ts b/apps/cli/src/commands/workspace/create.workspace.ts index f2f2ff25..6391b0f3 100644 --- a/apps/cli/src/commands/workspace/create.workspace.ts +++ b/apps/cli/src/commands/workspace/create.workspace.ts @@ -52,10 +52,7 @@ export default class CreateWorkspace extends BaseCommand { Logger.info(`Created at ${data.createdAt}`) Logger.info(`Updated at ${data.updatedAt}`) } else { - Logger.error(`Failed to create workspace: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to create workspace.\n' + JSON.stringify(error)) - } + this.logError(error) } } diff --git a/apps/cli/src/commands/workspace/delete.workspace.ts b/apps/cli/src/commands/workspace/delete.workspace.ts index ac6805e4..09fdb731 100644 --- a/apps/cli/src/commands/workspace/delete.workspace.ts +++ b/apps/cli/src/commands/workspace/delete.workspace.ts @@ -42,10 +42,7 @@ export default class DeleteWorkspace extends BaseCommand { if (success) { Logger.info(`Workspace ${workspaceSlug} deleted successfully!`) } else { - Logger.error(`Failed to delete workspace: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to delete workspace.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/export.workspace.ts b/apps/cli/src/commands/workspace/export.workspace.ts index 84ff155d..31b8b218 100644 --- a/apps/cli/src/commands/workspace/export.workspace.ts +++ b/apps/cli/src/commands/workspace/export.workspace.ts @@ -66,10 +66,7 @@ export default class ExportWorkspace extends BaseCommand { Logger.info(JSON.stringify(data)) } } else { - Logger.error(`Failed exporting workspace: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed exporting workspace.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/get.workspace.ts b/apps/cli/src/commands/workspace/get.workspace.ts index 8763eb28..ba6b4543 100644 --- a/apps/cli/src/commands/workspace/get.workspace.ts +++ b/apps/cli/src/commands/workspace/get.workspace.ts @@ -48,10 +48,7 @@ export default class GetWorkspace extends BaseCommand { Logger.info(`Updated at: ${data.updatedAt}`) Logger.info(`Is default workspace: ${data.isDefault}`) } else { - Logger.error(`Failed fetching workspace: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed fetching workspace.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/list.workspace.ts b/apps/cli/src/commands/workspace/list.workspace.ts index 7cdbcca4..c20071e0 100644 --- a/apps/cli/src/commands/workspace/list.workspace.ts +++ b/apps/cli/src/commands/workspace/list.workspace.ts @@ -45,10 +45,7 @@ export default class ListWorkspace extends BaseCommand { Logger.info('No workspaces found') } } else { - Logger.error(`Failed fetching workspaces: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed fetching workspaces.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/accept-invitation.membership.ts b/apps/cli/src/commands/workspace/membership/accept-invitation.membership.ts index 78aac96a..0ebabcc2 100644 --- a/apps/cli/src/commands/workspace/membership/accept-invitation.membership.ts +++ b/apps/cli/src/commands/workspace/membership/accept-invitation.membership.ts @@ -43,10 +43,7 @@ export default class AcceptInvitationCommand extends BaseCommand { Logger.info('Accepted invitation sucessfully!') Logger.info(`Workspace slug: ${workspaceSlug}`) } else { - Logger.error(`Failed to accept invitation: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to accept invitation.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/cancel-invitation.membership.ts b/apps/cli/src/commands/workspace/membership/cancel-invitation.membership.ts index 78509f92..1981eece 100644 --- a/apps/cli/src/commands/workspace/membership/cancel-invitation.membership.ts +++ b/apps/cli/src/commands/workspace/membership/cancel-invitation.membership.ts @@ -57,10 +57,7 @@ export default class CancelInvitationCommand extends BaseCommand { Logger.info(`Workspace slug: ${workspaceSlug}`) Logger.info(`Invitee: ${email}`) } else { - Logger.error(`Failed to cancel invitation: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to cancel invitation.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/decline-invitation.membership.ts b/apps/cli/src/commands/workspace/membership/decline-invitation.membership.ts index f9e1a611..393ce19b 100644 --- a/apps/cli/src/commands/workspace/membership/decline-invitation.membership.ts +++ b/apps/cli/src/commands/workspace/membership/decline-invitation.membership.ts @@ -43,10 +43,7 @@ export default class DeclineInvitationCommand extends BaseCommand { Logger.info('Declined invitation sucessfully!') Logger.info(`Workspace slug: ${workspaceSlug}`) } else { - Logger.error(`Failed to decline invitation: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to decline invitation.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/get-all-members.membership.ts b/apps/cli/src/commands/workspace/membership/get-all-members.membership.ts index ada287e4..3cb033d0 100644 --- a/apps/cli/src/commands/workspace/membership/get-all-members.membership.ts +++ b/apps/cli/src/commands/workspace/membership/get-all-members.membership.ts @@ -62,10 +62,7 @@ export default class GetAllMembersOfWorkspaceCommand extends BaseCommand { Logger.info('No members found') } } else { - Logger.error(`Failed fetching members: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed fetching members.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/invite.membership.ts b/apps/cli/src/commands/workspace/membership/invite.membership.ts index 68e598b6..e01fafeb 100644 --- a/apps/cli/src/commands/workspace/membership/invite.membership.ts +++ b/apps/cli/src/commands/workspace/membership/invite.membership.ts @@ -67,10 +67,7 @@ export default class InviteUserCommand extends BaseCommand { Logger.info(`Invitee: ${email}`) Logger.info(`Roles: ${roles}`) } else { - Logger.error(`Failed to invite user: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to invite user.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/leave.membership.ts b/apps/cli/src/commands/workspace/membership/leave.membership.ts index 402361ca..15554fe9 100644 --- a/apps/cli/src/commands/workspace/membership/leave.membership.ts +++ b/apps/cli/src/commands/workspace/membership/leave.membership.ts @@ -43,10 +43,7 @@ export class LeaveWorkspaceCommand extends BaseCommand { Logger.info('Left workspace sucessfully!') Logger.info(`Workspace slug: ${workspaceSlug}`) } else { - Logger.error(`Failed to leave workspace: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to leave workspace.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/remove.membership.ts b/apps/cli/src/commands/workspace/membership/remove.membership.ts index 21ab1ae5..a02e4edc 100644 --- a/apps/cli/src/commands/workspace/membership/remove.membership.ts +++ b/apps/cli/src/commands/workspace/membership/remove.membership.ts @@ -57,10 +57,7 @@ export default class RemoveUserCommand extends BaseCommand { Logger.info(`Workspace slug: ${workspaceSlug}`) Logger.info(`Email: ${emails}`) } else { - Logger.error(`Failed to remove users: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to remove users.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/transfer-ownership.membership copy.ts b/apps/cli/src/commands/workspace/membership/transfer-ownership.membership copy.ts index 31ce7da8..f0a81978 100644 --- a/apps/cli/src/commands/workspace/membership/transfer-ownership.membership copy.ts +++ b/apps/cli/src/commands/workspace/membership/transfer-ownership.membership copy.ts @@ -61,10 +61,7 @@ export default class TransferOwnershipCommand extends BaseCommand { Logger.info(`New owner email: ${email}`) Logger.info(`Workspace slug: ${workspaceSlug}`) } else { - Logger.error(`Failed to transfer ownership: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to transfer ownership.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/membership/update-role.membership.ts b/apps/cli/src/commands/workspace/membership/update-role.membership.ts index 31dbb068..88a32b9e 100644 --- a/apps/cli/src/commands/workspace/membership/update-role.membership.ts +++ b/apps/cli/src/commands/workspace/membership/update-role.membership.ts @@ -72,10 +72,7 @@ export default class UpdateRolesCommand extends BaseCommand { Logger.info(`Member Email: ${email}`) Logger.info(`New Roles: ${roles}`) } else { - Logger.error(`Failed to update roles: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed to update roles.\n' + JSON.stringify(error)) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/role/create.role.ts b/apps/cli/src/commands/workspace/role/create.role.ts index 4415aaa2..6642c840 100644 --- a/apps/cli/src/commands/workspace/role/create.role.ts +++ b/apps/cli/src/commands/workspace/role/create.role.ts @@ -132,12 +132,7 @@ export default class CreateRoleCommand extends BaseCommand { Logger.info(`- ${project.project.name} (${project.project.slug})`) } } else { - Logger.error(`Failed creating workspace role: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed creating workspace role.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/role/delete.role.ts b/apps/cli/src/commands/workspace/role/delete.role.ts index 7ae21414..38a69d21 100644 --- a/apps/cli/src/commands/workspace/role/delete.role.ts +++ b/apps/cli/src/commands/workspace/role/delete.role.ts @@ -42,12 +42,7 @@ export default class DeleteRoleCommand extends BaseCommand { if (success) { Logger.info(`Workspace role ${workspaceRoleSlug} deleted successfully!`) } else { - Logger.error(`Failed deleting workspace role: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed deleting workspace role.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/role/get.role.ts b/apps/cli/src/commands/workspace/role/get.role.ts index 650cc4cb..eff0ffe3 100644 --- a/apps/cli/src/commands/workspace/role/get.role.ts +++ b/apps/cli/src/commands/workspace/role/get.role.ts @@ -54,12 +54,7 @@ export default class GetRoleCommand extends BaseCommand { Logger.info(`- ${project.project.name} (${project.project.slug})`) } } else { - Logger.error(`Failed fetching workspace role: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed fetching workspace role.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/role/list.role.ts b/apps/cli/src/commands/workspace/role/list.role.ts index 95882cb4..71785da4 100644 --- a/apps/cli/src/commands/workspace/role/list.role.ts +++ b/apps/cli/src/commands/workspace/role/list.role.ts @@ -59,12 +59,7 @@ export default class ListRoleCommand extends BaseCommand { Logger.info('No roles found') } } else { - Logger.error(`Failed fetching roles: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed fetching workspace roles.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/role/update.role.ts b/apps/cli/src/commands/workspace/role/update.role.ts index 0151d7cb..1746a99b 100644 --- a/apps/cli/src/commands/workspace/role/update.role.ts +++ b/apps/cli/src/commands/workspace/role/update.role.ts @@ -128,12 +128,7 @@ export default class UpdateRoleCommand extends BaseCommand { Logger.info(`- ${project.project.name} (${project.project.slug})`) } } else { - Logger.error(`Failed updating workspace role: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed updating workspace role.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/search.workspace.ts b/apps/cli/src/commands/workspace/search.workspace.ts index 87f7e745..889b2daa 100644 --- a/apps/cli/src/commands/workspace/search.workspace.ts +++ b/apps/cli/src/commands/workspace/search.workspace.ts @@ -77,12 +77,7 @@ export default class SearchWorkspace extends BaseCommand { Logger.info('') } else { - Logger.error(`Failed searching in workspace: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report( - 'Failed searching in workspace.\n' + JSON.stringify(error) - ) - } + this.logError(error) } } } diff --git a/apps/cli/src/commands/workspace/update.workspace.ts b/apps/cli/src/commands/workspace/update.workspace.ts index 48669689..f60eea10 100644 --- a/apps/cli/src/commands/workspace/update.workspace.ts +++ b/apps/cli/src/commands/workspace/update.workspace.ts @@ -68,10 +68,7 @@ export default class UpdateWorkspace extends BaseCommand { Logger.info(`Updated at: ${data.updatedAt}`) Logger.info(`Is default workspace: ${data.isDefault}`) } else { - Logger.error(`Failed updating workspace: ${error.message}`) - if (this.metricsEnabled && error?.statusCode === 500) { - Logger.report('Failed updating workspace.\n' + JSON.stringify(error)) - } + this.logError(error) } } else { Logger.info('No data provided. Skipping update.') From 93927560107d37e8dbf3c200b66d5ae916124f97 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 26 Feb 2025 13:38:18 +0000 Subject: [PATCH 13/15] chore(release): 2.12.0-stage.18 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.12.0-stage.18](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.17...v2.12.0-stage.18) (2025-02-26) ### 🚀 Features * **cli:** Error message formatted ([#797](https://github.com/keyshade-xyz/keyshade/issues/797)) ([0322944](https://github.com/keyshade-xyz/keyshade/commit/03229446207dc7bc55d0aed5a049255fcc86ede3)) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 893b6967..88085490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.12.0-stage.18](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.17...v2.12.0-stage.18) (2025-02-26) + +### 🚀 Features + +* **cli:** Error message formatted ([#797](https://github.com/keyshade-xyz/keyshade/issues/797)) ([0322944](https://github.com/keyshade-xyz/keyshade/commit/03229446207dc7bc55d0aed5a049255fcc86ede3)) + ## [2.12.0-stage.17](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.16...v2.12.0-stage.17) (2025-02-26) ### 🐛 Bug Fixes diff --git a/package.json b/package.json index 8e2a9da8..06545f28 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keyshade-xyz", - "version": "2.12.0-stage.17", + "version": "2.12.0-stage.18", "license": "MPL-2.0", "private": true, "engineStrict": false, From c6a0df9679eb4f0c1ec53ec436adc2b5f5bd84d8 Mon Sep 17 00:00:00 2001 From: Rajdip Bhattacharya Date: Wed, 26 Feb 2025 19:30:57 +0530 Subject: [PATCH 14/15] fix(api): Added back missing endpoints (#798) --- .../Fetch all by project and environment.bru | 26 +++++ .../Fetch all by project and environment.bru | 26 +++++ apps/api/src/project/project.e2e.spec.ts | 6 +- .../src/project/service/project.service.ts | 2 +- .../secret/controller/secret.controller.ts | 14 +++ apps/api/src/secret/secret.e2e.spec.ts | 98 +++++++++++++++++++ apps/api/src/secret/service/secret.service.ts | 88 ++++++++++++++++- .../controller/variable.controller.ts | 14 +++ .../src/variable/service/variable.service.ts | 82 +++++++++++++++- apps/api/src/variable/variable.e2e.spec.ts | 56 +++++++++++ apps/cli/src/commands/run.command.ts | 3 +- packages/api-client/src/controllers/secret.ts | 16 ++- .../api-client/src/controllers/variable.ts | 16 ++- packages/schema/src/secret/index.ts | 13 +++ packages/schema/src/secret/index.types.ts | 12 ++- packages/schema/src/variable/index.ts | 13 +++ packages/schema/src/variable/index.types.ts | 12 ++- 17 files changed, 487 insertions(+), 10 deletions(-) create mode 100644 api-collection/Secret Controller/Fetch all by project and environment.bru create mode 100644 api-collection/Variable Controller/Fetch all by project and environment.bru diff --git a/api-collection/Secret Controller/Fetch all by project and environment.bru b/api-collection/Secret Controller/Fetch all by project and environment.bru new file mode 100644 index 00000000..649df049 --- /dev/null +++ b/api-collection/Secret Controller/Fetch all by project and environment.bru @@ -0,0 +1,26 @@ +meta { + name: Fetch all by project and environment + type: http + seq: 5 +} + +get { + url: {{BASE_URL}}/api/secret/:project_slug/:environment_slug + body: none + auth: bearer +} + +params:path { + project_slug: + environment_slug: +} + +auth:bearer { + token: {{JWT}} +} + +docs { + ## Description + + Fetches all the secrets for a particular pair of project and environment. Used by the CLI to prefetch the existing secrets. +} \ No newline at end of file diff --git a/api-collection/Variable Controller/Fetch all by project and environment.bru b/api-collection/Variable Controller/Fetch all by project and environment.bru new file mode 100644 index 00000000..6dce3415 --- /dev/null +++ b/api-collection/Variable Controller/Fetch all by project and environment.bru @@ -0,0 +1,26 @@ +meta { + name: Fetch all by project and environment + type: http + seq: 5 +} + +get { + url: {{BASE_URL}}/api/variable/:project_slug/:environment_slug + body: none + auth: bearer +} + +params:path { + project_slug: project-1-uzukc + environment_slug: alpha-l7xvp +} + +auth:bearer { + token: {{JWT}} +} + +docs { + ## Description + + Fetches all the variables for a particular pair of project and environment. Used by the CLI to prefetch the existing variables. +} \ No newline at end of file diff --git a/apps/api/src/project/project.e2e.spec.ts b/apps/api/src/project/project.e2e.spec.ts index b984dd62..4b1c16ad 100644 --- a/apps/api/src/project/project.e2e.spec.ts +++ b/apps/api/src/project/project.e2e.spec.ts @@ -154,8 +154,10 @@ describe('Project Controller Tests', () => { }) afterEach(async () => { - await prisma.user.deleteMany() - await prisma.workspace.deleteMany() + await prisma.$transaction([ + prisma.user.deleteMany(), + prisma.workspace.deleteMany() + ]) }) it('should be defined', async () => { diff --git a/apps/api/src/project/service/project.service.ts b/apps/api/src/project/service/project.service.ts index 7db44a55..4925f6a2 100644 --- a/apps/api/src/project/service/project.service.ts +++ b/apps/api/src/project/service/project.service.ts @@ -462,7 +462,7 @@ export class ProjectService { accessLevel: project.accessLevel, isForked: true, forkedFromId: project.id, - workspaceId: workspaceId, + workspaceId, lastUpdatedById: userId } }) diff --git a/apps/api/src/secret/controller/secret.controller.ts b/apps/api/src/secret/controller/secret.controller.ts index 7f3e757e..b4e0e12d 100644 --- a/apps/api/src/secret/controller/secret.controller.ts +++ b/apps/api/src/secret/controller/secret.controller.ts @@ -110,4 +110,18 @@ export class SecretController { order ) } + + @Get('/:projectSlug/:environmentSlug') + @RequiredApiKeyAuthorities(Authority.READ_SECRET) + async getAllSecretsOfEnvironment( + @CurrentUser() user: AuthenticatedUser, + @Param('projectSlug') projectSlug: string, + @Param('environmentSlug') environmentSlug: string + ) { + return await this.secretService.getAllSecretsOfProjectAndEnvironment( + user, + projectSlug, + environmentSlug + ) + } } diff --git a/apps/api/src/secret/secret.e2e.spec.ts b/apps/api/src/secret/secret.e2e.spec.ts index 917c0f25..00370e32 100644 --- a/apps/api/src/secret/secret.e2e.spec.ts +++ b/apps/api/src/secret/secret.e2e.spec.ts @@ -1160,4 +1160,102 @@ describe('Secret Controller Tests', () => { expect(event.title).toBe('Secret rotated') }) }) + + describe('Fetch All Secrets By Project And Environment Tests', () => { + it('should be able to fetch all secrets by project and environment', async () => { + const response = await app.inject({ + method: 'GET', + url: `/secret/${project1.slug}/${environment1.slug}`, + headers: { + 'x-e2e-user-email': user1.email + } + }) + + expect(response.statusCode).toBe(200) + expect(response.json().length).toBe(1) + + const secret = response.json()[0] + expect(secret.name).toBe('Secret 1') + expect(secret.value).toBe('Secret 1 value') + expect(secret.isPlaintext).toBe(true) + }) + + it('should not be able to fetch all secrets by project and environment if project does not exists', async () => { + const response = await app.inject({ + method: 'GET', + url: `/secret/non-existing-project-slug/${environment1.slug}`, + headers: { + 'x-e2e-user-email': user1.email + } + }) + + expect(response.statusCode).toBe(404) + }) + + it('should not be able to fetch all secrets by project and environment if environment does not exists', async () => { + const response = await app.inject({ + method: 'GET', + url: `/secret/${project1.slug}/non-existing-environment-slug`, + headers: { + 'x-e2e-user-email': user1.email + } + }) + + expect(response.statusCode).toBe(404) + }) + + it('should not be able to fetch all secrets by project and environment if the user has no access to the project', async () => { + const response = await app.inject({ + method: 'GET', + url: `/secret/${project1.slug}/${environment1.slug}`, + headers: { + 'x-e2e-user-email': user2.email + } + }) + + expect(response.statusCode).toBe(401) + }) + + it('should not be sending the plaintext secret if project does not store the private key', async () => { + // Get the first environment of project 2 + const environment = await prisma.environment.findFirst({ + where: { + projectId: project2.id + } + }) + + // Create a secret in project 2 + await secretService.createSecret( + user1, + { + name: 'Secret 20', + entries: [ + { + environmentSlug: environment.slug, + value: 'Secret 20 value' + } + ], + rotateAfter: '24', + note: 'Secret 20 note' + }, + project2.slug + ) + + const response = await app.inject({ + method: 'GET', + url: `/secret/${project2.slug}/${environment.slug}`, + headers: { + 'x-e2e-user-email': user1.email + } + }) + + expect(response.statusCode).toBe(200) + expect(response.json().length).toBe(1) + + const secret = response.json()[0] + expect(secret.name).toBe('Secret 20') + expect(secret.value).not.toBe('Secret 20 value') + expect(secret.isPlaintext).toBe(false) + }) + }) }) diff --git a/apps/api/src/secret/service/secret.service.ts b/apps/api/src/secret/service/secret.service.ts index caf87540..447a68fc 100644 --- a/apps/api/src/secret/service/secret.service.ts +++ b/apps/api/src/secret/service/secret.service.ts @@ -24,7 +24,10 @@ import { AuthorizationService } from '@/auth/service/authorization.service' import { RedisClientType } from 'redis' import { REDIS_CLIENT } from '@/provider/redis.provider' import { CHANGE_NOTIFIER_RSC } from '@/socket/change-notifier.socket' -import { ChangeNotificationEvent } from 'src/socket/socket.types' +import { + ChangeNotification, + ChangeNotificationEvent +} from '@/socket/socket.types' import { paginate } from '@/common/paginate' import { addHoursToDate, @@ -770,6 +773,89 @@ export class SecretService { return { items, metadata } } + /** + * Gets all secrets of a project and environment + * @param user the user performing the action + * @param projectSlug the slug of the project + * @param environmentSlug the slug of the environment + * @returns an array of objects with the secret name and value + * @throws {NotFoundException} if the project or environment does not exist + * @throws {BadRequestException} if the user does not have the required role + */ + async getAllSecretsOfProjectAndEnvironment( + user: AuthenticatedUser, + projectSlug: Project['slug'], + environmentSlug: Environment['slug'] + ) { + // Fetch the project + const project = + await this.authorizationService.authorizeUserAccessToProject({ + user, + entity: { slug: projectSlug }, + authorities: [Authority.READ_SECRET] + }) + const projectId = project.id + + // Check access to the environment + const environment = + await this.authorizationService.authorizeUserAccessToEnvironment({ + user, + entity: { slug: environmentSlug }, + authorities: [Authority.READ_ENVIRONMENT] + }) + const environmentId = environment.id + + const secrets = await this.prisma.secret.findMany({ + where: { + projectId, + versions: { + some: { + environmentId + } + } + }, + include: { + lastUpdatedBy: { + select: { + id: true, + name: true + } + }, + versions: { + where: { + environmentId + }, + orderBy: { + version: 'desc' + }, + take: 1, + include: { + environment: { + select: { + id: true, + slug: true + } + } + } + } + } + }) + + const response: ChangeNotification[] = [] + + for (const secret of secrets) { + response.push({ + name: secret.name, + value: project.storePrivateKey + ? await decrypt(project.privateKey, secret.versions[0].value) + : secret.versions[0].value, + isPlaintext: project.storePrivateKey + }) + } + + return response + } + /** * Rotate values of secrets that have reached their rotation time * @param currentTime the current time diff --git a/apps/api/src/variable/controller/variable.controller.ts b/apps/api/src/variable/controller/variable.controller.ts index 1a15d29d..fc967cbd 100644 --- a/apps/api/src/variable/controller/variable.controller.ts +++ b/apps/api/src/variable/controller/variable.controller.ts @@ -106,4 +106,18 @@ export class VariableController { order ) } + + @Get('/:projectSlug/:environmentSlug') + @RequiredApiKeyAuthorities(Authority.READ_VARIABLE) + async getAllVariablesOfEnvironment( + @CurrentUser() user: AuthenticatedUser, + @Param('projectSlug') projectSlug: string, + @Param('environmentSlug') environmentSlug: string + ) { + return await this.variableService.getAllVariablesOfProjectAndEnvironment( + user, + projectSlug, + environmentSlug + ) + } } diff --git a/apps/api/src/variable/service/variable.service.ts b/apps/api/src/variable/service/variable.service.ts index d54e48e9..0abdcc55 100644 --- a/apps/api/src/variable/service/variable.service.ts +++ b/apps/api/src/variable/service/variable.service.ts @@ -22,7 +22,10 @@ import { RedisClientType } from 'redis' import { REDIS_CLIENT } from '@/provider/redis.provider' import { CHANGE_NOTIFIER_RSC } from '@/socket/change-notifier.socket' import { AuthorizationService } from '@/auth/service/authorization.service' -import { ChangeNotificationEvent } from 'src/socket/socket.types' +import { + ChangeNotification, + ChangeNotificationEvent +} from '@/socket/socket.types' import { paginate } from '@/common/paginate' import { getEnvironmentIdToSlugMap } from '@/common/environment' import generateEntitySlug from '@/common/slug-generator' @@ -715,6 +718,83 @@ export class VariableService { return { items, metadata } } + /** + * Gets all variables of a project and environment. + * @param user the user performing the action + * @param projectSlug the slug of the project to get the variables from + * @param environmentSlug the slug of the environment to get the variables from + * @returns an array of objects containing the name, value and whether the value is a plaintext + * @throws `NotFoundException` if the project or environment does not exist + * @throws `ForbiddenException` if the user does not have the required authority + */ + async getAllVariablesOfProjectAndEnvironment( + user: AuthenticatedUser, + projectSlug: Project['slug'], + environmentSlug: Environment['slug'] + ) { + // Check if the user has the required authorities in the project + const { id: projectId } = + await this.authorizationService.authorizeUserAccessToProject({ + user, + entity: { slug: projectSlug }, + authorities: [Authority.READ_VARIABLE] + }) + + // Check if the user has the required authorities in the environment + const { id: environmentId } = + await this.authorizationService.authorizeUserAccessToEnvironment({ + user, + entity: { slug: environmentSlug }, + authorities: [Authority.READ_ENVIRONMENT] + }) + + const variables = await this.prisma.variable.findMany({ + where: { + projectId, + versions: { + some: { + environmentId + } + } + }, + include: { + lastUpdatedBy: { + select: { + id: true, + name: true + } + }, + versions: { + where: { + environmentId + }, + select: { + value: true, + environment: { + select: { + id: true, + slug: true + } + } + }, + orderBy: { + version: 'desc' + }, + take: 1 + } + } + }) + + return variables.map( + (variable) => + ({ + name: variable.name, + value: variable.versions[0].value, + isPlaintext: true + }) as ChangeNotification + ) + } + /** * Checks if a variable with a given name already exists in a project. * Throws a ConflictException if the variable already exists. diff --git a/apps/api/src/variable/variable.e2e.spec.ts b/apps/api/src/variable/variable.e2e.spec.ts index 70872af8..b17e963a 100644 --- a/apps/api/src/variable/variable.e2e.spec.ts +++ b/apps/api/src/variable/variable.e2e.spec.ts @@ -932,4 +932,60 @@ describe('Variable Controller Tests', () => { expect(response.statusCode).toBe(401) }) }) + + describe('Get All Variables By Project And Environment Tests', () => { + it('should be able to fetch all variables by project and environment', async () => { + const response = await app.inject({ + method: 'GET', + url: `/variable/${project1.slug}/${environment1.slug}`, + headers: { + 'x-e2e-user-email': user1.email + } + }) + + expect(response.statusCode).toBe(200) + expect(response.json().length).toBe(1) + + const variable = response.json()[0] + expect(variable.name).toBe('Variable 1') + expect(variable.value).toBe('Variable 1 value') + expect(variable.isPlaintext).toBe(true) + }) + + it('should not be able to fetch all variables by project and environment if the user has no access to the project', async () => { + const response = await app.inject({ + method: 'GET', + url: `/variable/${project1.slug}/${environment1.slug}`, + headers: { + 'x-e2e-user-email': user2.email + } + }) + + expect(response.statusCode).toBe(401) + }) + + it('should not be able to fetch all variables by project and environment if the project does not exist', async () => { + const response = await app.inject({ + method: 'GET', + url: `/variable/non-existing-project-slug/${environment1.slug}`, + headers: { + 'x-e2e-user-email': user1.email + } + }) + + expect(response.statusCode).toBe(404) + }) + + it('should not be able to fetch all variables by project and environment if the environment does not exist', async () => { + const response = await app.inject({ + method: 'GET', + url: `/variable/${project1.slug}/non-existing-environment-slug`, + headers: { + 'x-e2e-user-email': user1.email + } + }) + + expect(response.statusCode).toBe(404) + }) + }) }) diff --git a/apps/cli/src/commands/run.command.ts b/apps/cli/src/commands/run.command.ts index 43bdfec6..5b624543 100644 --- a/apps/cli/src/commands/run.command.ts +++ b/apps/cli/src/commands/run.command.ts @@ -160,9 +160,10 @@ export default class RunCommand extends BaseCommand { } if (childProcess === null) { childProcess = spawn(command, { + // @ts-expect-error this just works stdio: ['inherit', 'pipe', 'pipe'], shell: true, - env: this.processEnvironmentalVariables, + env: { ...process.env, ...this.processEnvironmentalVariables }, detached: true }) diff --git a/packages/api-client/src/controllers/secret.ts b/packages/api-client/src/controllers/secret.ts index a4d961d9..176f1cd7 100644 --- a/packages/api-client/src/controllers/secret.ts +++ b/packages/api-client/src/controllers/secret.ts @@ -1,5 +1,9 @@ import { APIClient } from '@api-client/core/client' -import { ClientResponse } from '@keyshade/schema' +import { + ClientResponse, + GetAllSecretsOfEnvironmentRequest, + GetAllSecretsOfEnvironmentResponse +} from '@keyshade/schema' import { parseResponse } from '@api-client/core/response-parser' import { CreateSecretRequest, @@ -106,4 +110,14 @@ export default class SecretController { return await parseResponse(response) } + + async getAllSecretsOfEnvironment( + request: GetAllSecretsOfEnvironmentRequest, + headers?: Record + ): Promise> { + const url = `/api/secret/${request.projectSlug}/${request.environmentSlug}` + const response = await this.apiClient.get(url, headers) + + return await parseResponse(response) + } } diff --git a/packages/api-client/src/controllers/variable.ts b/packages/api-client/src/controllers/variable.ts index de60d6ea..d6ed0b23 100644 --- a/packages/api-client/src/controllers/variable.ts +++ b/packages/api-client/src/controllers/variable.ts @@ -1,7 +1,11 @@ import { APIClient } from '@api-client/core/client' import { parsePaginationUrl } from '@api-client/core/pagination-parser' import { parseResponse } from '@api-client/core/response-parser' -import { ClientResponse } from '@keyshade/schema' +import { + ClientResponse, + GetAllVariablesOfEnvironmentRequest, + GetAllVariablesOfEnvironmentResponse +} from '@keyshade/schema' import { CreateVariableRequest, CreateVariableResponse, @@ -99,4 +103,14 @@ export default class VariableController { return await parseResponse(response) } + + async getAllVariablesOfEnvironment( + request: GetAllVariablesOfEnvironmentRequest, + headers: Record + ): Promise> { + const url = `/api/variable/${request.projectSlug}/${request.environmentSlug}` + const response = await this.apiClient.get(url, headers) + + return await parseResponse(response) + } } diff --git a/packages/schema/src/secret/index.ts b/packages/schema/src/secret/index.ts index e075354b..0b1879d3 100644 --- a/packages/schema/src/secret/index.ts +++ b/packages/schema/src/secret/index.ts @@ -129,3 +129,16 @@ export const GetRevisionsOfSecretResponseSchema = PageResponseSchema( }) }) ) + +export const GetAllSecretsOfEnvironmentRequestSchema = z.object({ + projectSlug: BaseProjectSchema.shape.slug, + environmentSlug: EnvironmentSchema.shape.slug +}) + +export const GetAllSecretsOfEnvironmentResponseSchema = z.array( + z.object({ + name: z.string(), + value: z.string(), + isPlaintext: z.boolean() + }) +) diff --git a/packages/schema/src/secret/index.types.ts b/packages/schema/src/secret/index.types.ts index 43920ad2..990bf9cf 100644 --- a/packages/schema/src/secret/index.types.ts +++ b/packages/schema/src/secret/index.types.ts @@ -12,7 +12,9 @@ import { GetAllSecretsOfProjectRequestSchema, GetAllSecretsOfProjectResponseSchema, GetRevisionsOfSecretRequestSchema, - GetRevisionsOfSecretResponseSchema + GetRevisionsOfSecretResponseSchema, + GetAllSecretsOfEnvironmentRequestSchema, + GetAllSecretsOfEnvironmentResponseSchema } from '.' export type Secret = z.infer @@ -50,3 +52,11 @@ export type GetRevisionsOfSecretRequest = z.infer< export type GetRevisionsOfSecretResponse = z.infer< typeof GetRevisionsOfSecretResponseSchema > + +export type GetAllSecretsOfEnvironmentRequest = z.infer< + typeof GetAllSecretsOfEnvironmentRequestSchema +> + +export type GetAllSecretsOfEnvironmentResponse = z.infer< + typeof GetAllSecretsOfEnvironmentResponseSchema +> diff --git a/packages/schema/src/variable/index.ts b/packages/schema/src/variable/index.ts index 810e5ba2..d127db4b 100644 --- a/packages/schema/src/variable/index.ts +++ b/packages/schema/src/variable/index.ts @@ -133,3 +133,16 @@ export const GetRevisionsOfVariableResponseSchema = PageResponseSchema( }) }) ) + +export const GetAllVariablesOfEnvironmentRequestSchema = z.object({ + projectSlug: BaseProjectSchema.shape.slug, + environmentSlug: EnvironmentSchema.shape.slug +}) + +export const GetAllVariablesOfEnvironmentResponseSchema = z.array( + z.object({ + name: z.string(), + value: z.string(), + isPlaintext: z.boolean() + }) +) diff --git a/packages/schema/src/variable/index.types.ts b/packages/schema/src/variable/index.types.ts index 609fbb24..6bf88352 100644 --- a/packages/schema/src/variable/index.types.ts +++ b/packages/schema/src/variable/index.types.ts @@ -12,7 +12,9 @@ import { GetAllVariablesOfProjectRequestSchema, GetAllVariablesOfProjectResponseSchema, GetRevisionsOfVariableRequestSchema, - GetRevisionsOfVariableResponseSchema + GetRevisionsOfVariableResponseSchema, + GetAllVariablesOfEnvironmentRequestSchema, + GetAllVariablesOfEnvironmentResponseSchema } from '.' export type Variable = z.infer @@ -58,3 +60,11 @@ export type GetRevisionsOfVariableRequest = z.infer< export type GetRevisionsOfVariableResponse = z.infer< typeof GetRevisionsOfVariableResponseSchema > + +export type GetAllVariablesOfEnvironmentRequest = z.infer< + typeof GetAllVariablesOfEnvironmentRequestSchema +> + +export type GetAllVariablesOfEnvironmentResponse = z.infer< + typeof GetAllVariablesOfEnvironmentResponseSchema +> From 6b4ea2864b5645aca1c8f7c6fdd05939788a9cab Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 26 Feb 2025 14:01:46 +0000 Subject: [PATCH 15/15] chore(release): 2.12.0-stage.19 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.12.0-stage.19](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.18...v2.12.0-stage.19) (2025-02-26) ### 🐛 Bug Fixes * **api:** Added back missing endpoints ([#798](https://github.com/keyshade-xyz/keyshade/issues/798)) ([c6a0df9](https://github.com/keyshade-xyz/keyshade/commit/c6a0df9679eb4f0c1ec53ec436adc2b5f5bd84d8)) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88085490..869f6902 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.12.0-stage.19](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.18...v2.12.0-stage.19) (2025-02-26) + +### 🐛 Bug Fixes + +* **api:** Added back missing endpoints ([#798](https://github.com/keyshade-xyz/keyshade/issues/798)) ([c6a0df9](https://github.com/keyshade-xyz/keyshade/commit/c6a0df9679eb4f0c1ec53ec436adc2b5f5bd84d8)) + ## [2.12.0-stage.18](https://github.com/keyshade-xyz/keyshade/compare/v2.12.0-stage.17...v2.12.0-stage.18) (2025-02-26) ### 🚀 Features diff --git a/package.json b/package.json index 06545f28..39a26e6e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keyshade-xyz", - "version": "2.12.0-stage.18", + "version": "2.12.0-stage.19", "license": "MPL-2.0", "private": true, "engineStrict": false,