Skip to content

Commit

Permalink
Merge branch 'develop' into hp/fix/loading-github-module
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdip-b authored Feb 7, 2024
2 parents 5d23dda + 308fbf4 commit caaafcd
Show file tree
Hide file tree
Showing 29 changed files with 397 additions and 54 deletions.
21 changes: 17 additions & 4 deletions .github/workflows/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
- name: Unit tests
run: |
pnpm run db:generate-types
pnpm run test:api
pnpm run test:api -- --no-cache
- name: E2E tests
env:
Expand All @@ -57,19 +57,32 @@ jobs:
GITHUB_CALLBACK_URL: dummy
run: |
docker compose up -d
pnpm run e2e:api
pnpm run e2e:api -- --no-cache
docker compose down
- name: Upload coverage reports to Codecov
- name: Upload unit test coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
directory: ./coverage/apps/api
directory: coverage/api/
with:
flags: api-unit-tests
files: coverage-final.json

- name: Upload e2e test coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
directory: coverage-e2e/api/
with:
flags: api-e2e-tests
files: coverage-final.json

deploy-stage:
runs-on: ubuntu-latest
name: Deploy to stage
if: ${{ github.ref == 'refs/heads/develop' }}
needs: validate

steps:
- name: Checkout
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/web.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@ jobs:
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
flags: web

deploy-stage:
runs-on: ubuntu-latest
name: Deploy to stage
if: ${{ github.ref == 'refs/heads/develop' }}
needs: validate

steps:
- name: Checkout
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ node_modules
/.sass-cache
/connect.lock
/coverage
/coverage-e2e
/libpeerconnection.log
npm-debug.log
yarn-error.log
Expand Down
1 change: 1 addition & 0 deletions apps/api/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
},
"test:e2e": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage-e2e/{projectRoot}"],
"options": {
"runInBand": true,
"devServerTarget": "api:serve",
Expand Down
47 changes: 46 additions & 1 deletion apps/api/src/api-key/api-key.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('Api Key Role Controller Tests', () => {
let prisma: PrismaService
let user: User
let apiKey: ApiKey
let apiKeyValue: string

beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
Expand Down Expand Up @@ -51,7 +52,8 @@ describe('Api Key Role Controller Tests', () => {
url: '/api-key',
payload: {
name: 'Test Key',
expiresAfter: '24'
expiresAfter: '24',
authorities: ['READ_API_KEY']
},
headers: {
'x-e2e-user-email': user.email
Expand All @@ -63,12 +65,14 @@ describe('Api Key Role Controller Tests', () => {
id: expect.any(String),
name: 'Test Key',
value: expect.stringMatching(/^ks_*/),
authorities: ['READ_API_KEY'],
expiresAt: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String)
})

apiKey = response.json()
apiKeyValue = response.json().value
})

it('should be able to update the api key', async () => {
Expand All @@ -88,6 +92,7 @@ describe('Api Key Role Controller Tests', () => {
expect(response.json()).toEqual({
id: apiKey.id,
name: 'Updated Test Key',
authorities: ['READ_API_KEY'],
expiresAt: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String)
Expand All @@ -109,6 +114,7 @@ describe('Api Key Role Controller Tests', () => {
expect(response.json()).toEqual({
id: apiKey.id,
name: 'Updated Test Key',
authorities: ['READ_API_KEY'],
expiresAt: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String)
Expand All @@ -129,13 +135,52 @@ describe('Api Key Role Controller Tests', () => {
{
id: apiKey.id,
name: 'Updated Test Key',
authorities: ['READ_API_KEY'],
expiresAt: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String)
}
])
})

it('should be able to get all api keys using the API key', async () => {
const response = await app.inject({
method: 'GET',
url: '/api-key/all/as-user',
headers: {
'x-keyshade-token': apiKeyValue
}
})

expect(response.statusCode).toBe(200)
expect(response.json()).toEqual([
{
id: apiKey.id,
name: 'Updated Test Key',
authorities: ['READ_API_KEY'],
expiresAt: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String)
}
])
})

it('should not be able to create api key with invalid authorities of API key', async () => {
const response = await app.inject({
method: 'POST',
url: '/api-key',
payload: {
name: 'Test Key',
expiresAfter: '24'
},
headers: {
'x-keyshade-token': apiKeyValue
}
})

expect(response.statusCode).toBe(401)
})

it('should be able to delete the api key', async () => {
const response = await app.inject({
method: 'DELETE',
Expand Down
10 changes: 8 additions & 2 deletions apps/api/src/api-key/controller/api-key.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,25 @@ import {
UseGuards
} from '@nestjs/common'
import { ApiKeyService } from '../service/api-key.service'
import { User } from '@prisma/client'
import { CurrentUser } from '../../decorators/user.decorator'
import { CreateApiKey } from '../dto/create.api-key/create.api-key'
import { UpdateApiKey } from '../dto/update.api-key/update.api-key'
import { AdminGuard } from '../../auth/guard/admin.guard'
import { AdminGuard } from '../../auth/guard/admin/admin.guard'
import { Authority, User } from '@prisma/client'
import { RequiredApiKeyAuthorities } from '../../decorators/required-api-key-authorities.decorator'

@Controller('api-key')
export class ApiKeyController {
constructor(private readonly apiKeyService: ApiKeyService) {}

@Post()
@RequiredApiKeyAuthorities(Authority.CREATE_API_KEY)
async createApiKey(@CurrentUser() user: User, @Body() dto: CreateApiKey) {
return this.apiKeyService.createApiKey(user, dto)
}

@Put(':id')
@RequiredApiKeyAuthorities(Authority.UPDATE_API_KEY)
async updateApiKey(
@CurrentUser() user: User,
@Body() dto: UpdateApiKey,
Expand All @@ -35,16 +38,19 @@ export class ApiKeyController {
}

@Delete(':id')
@RequiredApiKeyAuthorities(Authority.DELETE_API_KEY)
async deleteApiKey(@CurrentUser() user: User, @Param('id') id: string) {
return this.apiKeyService.deleteApiKey(user, id)
}

@Get(':id')
@RequiredApiKeyAuthorities(Authority.READ_API_KEY)
async getApiKey(@CurrentUser() user: User, @Param('id') id: string) {
return this.apiKeyService.getApiKeyById(user, id)
}

@Get('all/as-user')
@RequiredApiKeyAuthorities(Authority.READ_API_KEY)
async getApiKeysOfUser(
@CurrentUser() user: User,
@Query('page') page: number = 1,
Expand Down
11 changes: 8 additions & 3 deletions apps/api/src/api-key/dto/create.api-key/create.api-key.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { ApiKey } from '@prisma/client'
import { IsString } from 'class-validator'
import { ApiKey, Authority } from '@prisma/client'
import { IsArray, IsOptional, IsString } from 'class-validator'

export class CreateApiKey {
@IsString()
name: ApiKey['name']

@IsString()
expiresAfter: '24' | '168' | '720' | '8760' | 'never' = 'never'
@IsOptional()
expiresAfter?: '24' | '168' | '720' | '8760' | 'never' = 'never'

@IsArray()
@IsOptional()
authorities?: Authority[] = []
}
17 changes: 16 additions & 1 deletion apps/api/src/api-key/service/api-key.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Injectable, Logger, NotFoundException } from '@nestjs/common'
import { User } from '@prisma/client'
import { PrismaService } from '../../prisma/prisma.service'
import { CreateApiKey } from '../dto/create.api-key/create.api-key'
import { addHoursToDate } from '../../common/add-hours-to-date'
import { generateApiKey } from '../../common/api-key-generator'
import { toSHA256 } from '../../common/to-sha256'
import { UpdateApiKey } from '../dto/update.api-key/update.api-key'
import { User } from '@prisma/client'

@Injectable()
export class ApiKeyService {
Expand All @@ -20,6 +20,11 @@ export class ApiKeyService {
data: {
name: dto.name,
value: hashedApiKey,
authorities: dto.authorities
? {
set: dto.authorities
}
: [],

Check warning on line 27 in apps/api/src/api-key/service/api-key.service.ts

View check run for this annotation

Codecov / codecov/patch

apps/api/src/api-key/service/api-key.service.ts#L27

Added line #L27 was not covered by tests
expiresAt: addHoursToDate(dto.expiresAfter),
user: {
connect: {
Expand All @@ -31,6 +36,7 @@ export class ApiKeyService {
id: true,
expiresAt: true,
name: true,
authorities: true,
createdAt: true,
updatedAt: true
}
Expand All @@ -52,6 +58,11 @@ export class ApiKeyService {
},
data: {
name: dto.name,
authorities: dto.authorities
? {

Check warning on line 62 in apps/api/src/api-key/service/api-key.service.ts

View check run for this annotation

Codecov / codecov/patch

apps/api/src/api-key/service/api-key.service.ts#L62

Added line #L62 was not covered by tests
set: dto.authorities
}
: undefined,
expiresAt: dto.expiresAfter
? addHoursToDate(dto.expiresAfter)
: undefined
Expand All @@ -60,6 +71,7 @@ export class ApiKeyService {
id: true,
expiresAt: true,
name: true,
authorities: true,
createdAt: true,
updatedAt: true
}
Expand Down Expand Up @@ -89,6 +101,7 @@ export class ApiKeyService {
id: true,
expiresAt: true,
name: true,
authorities: true,
createdAt: true,
updatedAt: true
}
Expand Down Expand Up @@ -127,6 +140,7 @@ export class ApiKeyService {
id: true,
expiresAt: true,
name: true,
authorities: true,
createdAt: true,
updatedAt: true
}
Expand Down Expand Up @@ -155,6 +169,7 @@ export class ApiKeyService {
id: true,
expiresAt: true,
name: true,
authorities: true,
createdAt: true,
updatedAt: true
}
Expand Down
7 changes: 6 additions & 1 deletion apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { PrismaModule } from '../prisma/prisma.module'
import { CommonModule } from '../common/common.module'
import { MailModule } from '../mail/mail.module'
import { APP_GUARD } from '@nestjs/core'
import { AuthGuard } from '../auth/guard/auth.guard'
import { AuthGuard } from '../auth/guard/auth/auth.guard'
import { UserModule } from '../user/user.module'
import { ProjectModule } from '../project/project.module'
import { EnvironmentModule } from '../environment/environment.module'
import { ApiKeyModule } from '../api-key/api-key.module'
import { WorkspaceModule } from '../workspace/workspace.module'
import { WorkspaceRoleModule } from '../workspace-role/workspace-role.module'
import { ApiKeyGuard } from '../auth/guard/api-key/api-key.guard'

@Module({
controllers: [AppController],
Expand All @@ -39,6 +40,10 @@ import { WorkspaceRoleModule } from '../workspace-role/workspace-role.module'
{
provide: APP_GUARD,
useClass: AuthGuard
},
{
provide: APP_GUARD,
useClass: ApiKeyGuard
}
]
})
Expand Down
7 changes: 6 additions & 1 deletion apps/api/src/auth/auth.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { User } from '@prisma/client'
import { Authority, User } from '@prisma/client'

export type UserAuthenticatedResponse = User & {
token: string
}

export type AuthenticatedUserContext = User & {
isAuthViaApiKey?: boolean
apiKeyAuthorities?: Set<Authority>
}
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions apps/api/src/auth/guard/api-key/api-key.guard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ApiKeyGuard } from './api-key.guard'

describe('ApiKeyGuard', () => {
it('should be defined', () => {
expect(new ApiKeyGuard(null)).toBeDefined()
})
})
Loading

0 comments on commit caaafcd

Please sign in to comment.