-
Notifications
You must be signed in to change notification settings - Fork 1
sync dev to master #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
97649fe
d73289a
d043096
55bce4b
8ef6a2c
bcc497c
3a57300
a7a6694
9993ae4
de87c0a
048d407
17f01ff
5919454
1208653
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| version: 2.1 | ||
|
|
||
| parameters: | ||
| reset-db: | ||
| type: boolean | ||
| default: false | ||
| defaults: &defaults | ||
| docker: | ||
| - image: cimg/python:3.13.2-browsers | ||
| install_dependency: &install_dependency | ||
| name: Installation of build and deployment dependencies. | ||
| command: | | ||
| sudo apt update | ||
| sudo apt install -y jq python3-pip | ||
| sudo pip3 install awscli --upgrade | ||
| install_deploysuite: &install_deploysuite | ||
| name: Installation of install_deploysuite. | ||
| command: | | ||
| git clone --branch v1.4.19 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| cp ./../buildscript/master_deploy.sh . | ||
| cp ./../buildscript/buildenv.sh . | ||
| cp ./../buildscript/awsconfiguration.sh . | ||
| cp ./../buildscript/psvar-processor.sh . | ||
| builddeploy_steps: &builddeploy_steps | ||
| - checkout | ||
| - setup_remote_docker | ||
| - run: *install_dependency | ||
| - run: *install_deploysuite | ||
| - run: docker buildx build --no-cache=true --build-arg RESET_DB_ARG=<<pipeline.parameters.reset-db>> --build-arg SEED_DATA_ARG=${DEPLOYMENT_ENVIRONMENT} -t ${APPNAME}:latest . | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| - run: | ||
| name: Running MasterScript. | ||
| command: | | ||
| ./awsconfiguration.sh $DEPLOY_ENV | ||
| source awsenvconf | ||
| ./psvar-processor.sh -t appenv -p /config/${APPNAME}/deployvar | ||
| source deployvar_env | ||
| ./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -j /config/${APPNAME}/appvar,/config/common/global-appvar -i ${APPNAME} -p FARGATE | ||
| jobs: | ||
| # Build & Deploy against development backend | ||
| "build-dev": | ||
| !!merge <<: *defaults | ||
| environment: | ||
| DEPLOY_ENV: "DEV" | ||
| LOGICAL_ENV: "dev" | ||
| APPNAME: "groups-api-v6" | ||
| DEPLOYMENT_ENVIRONMENT: 'dev' | ||
| steps: *builddeploy_steps | ||
|
|
||
| "build-prod": | ||
| !!merge <<: *defaults | ||
| environment: | ||
| DEPLOY_ENV: "PROD" | ||
| LOGICAL_ENV: "prod" | ||
| APPNAME: "groups-api-v6" | ||
| DEPLOYMENT_ENVIRONMENT: 'prod' | ||
| steps: *builddeploy_steps | ||
|
|
||
| workflows: | ||
| version: 2 | ||
| build: | ||
| jobs: | ||
| # Development builds are executed on "develop" branch only. | ||
| - "build-dev": | ||
| context: org-global | ||
| filters: | ||
| branches: | ||
| only: | ||
| - develop | ||
|
|
||
| # Production builds are exectuted only on tagged commits to the | ||
| # master branch. | ||
| - "build-prod": | ||
| context: org-global | ||
| filters: | ||
| branches: | ||
| only: | ||
| - master | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| name: AI PR Reviewer | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: | ||
| - opened | ||
| - synchronize | ||
| permissions: | ||
| pull-requests: write | ||
| jobs: | ||
| tc-ai-pr-review: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout Repo | ||
| uses: actions/checkout@v3 | ||
|
|
||
| - name: TC AI PR Reviewer | ||
| uses: topcoder-platform/tc-ai-pr-reviewer@master | ||
| with: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # The GITHUB_TOKEN is there by default so you just need to keep it like it is and not necessarily need to add it as secret as it will throw an error. [More Details](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret) | ||
| LAB45_API_KEY: ${{ secrets.LAB45_API_KEY }} | ||
| exclude: '**/*.json, **/*.md, **/*.jpg, **/*.png, **/*.jpeg, **/*.bmp, **/*.webp' # Optional: exclude patterns separated by commas | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,7 +37,7 @@ import { | |
|
|
||
| import { M2MService } from 'src/shared/modules/global/m2m.service'; | ||
|
|
||
| const ADMIN_GROUP_FIELDS = ['status']; | ||
| const ADMIN_GROUP_FIELDS: string[] = []; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
|
|
||
| export const ALLOWED_FIELD_NAMES = [ | ||
| 'id', | ||
|
|
@@ -52,6 +52,7 @@ export const ALLOWED_FIELD_NAMES = [ | |
| 'domain', | ||
| 'organizationId', | ||
| 'oldId', | ||
| 'status', | ||
| ]; | ||
|
|
||
| @Injectable() | ||
|
|
@@ -128,10 +129,6 @@ export class GroupService { | |
|
|
||
| if (criteria.oldId) { | ||
| prismaFilter.where.oldId = criteria.oldId; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| } else { | ||
| prismaFilter.where.oldId = { | ||
| not: null, | ||
| }; | ||
| } | ||
| if (criteria.name) { | ||
| prismaFilter.where.name = { | ||
|
|
@@ -352,13 +349,18 @@ export class GroupService { | |
| await checkGroupName(dto.name, '', tx); | ||
|
|
||
| // create group | ||
| const createdBy = authUser.userId ? authUser.userId : '00000000'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| const createdAt = new Date().toISOString(); | ||
| const groupData = { | ||
| ...dto, | ||
| domain: dto.domain || '', | ||
| ssoId: dto.ssoId || '', | ||
| organizationId: dto.organizationId || '', | ||
| createdBy: authUser.userId ? authUser.userId : '00000000', | ||
| createdAt: new Date().toISOString(), | ||
| createdBy, | ||
| createdAt, | ||
| // Initialize updated fields to match created fields on creation | ||
| updatedBy: createdBy, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| updatedAt: createdAt, | ||
| }; | ||
|
|
||
| const result = await tx.group.create({ data: groupData }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,13 +65,18 @@ export class SubGroupService { | |
| await checkGroupName(dto.name, '', tx); | ||
|
|
||
| // create group | ||
| const createdBy = authUser.userId ? authUser.userId : '00000000'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| const createdAt = new Date().toISOString(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| const groupData = { | ||
| ...dto, | ||
| domain: dto.domain || '', | ||
| ssoId: dto.ssoId || '', | ||
| organizationId: dto.organizationId || '', | ||
| createdBy: authUser.userId ? authUser.userId : '00000000', | ||
| createdAt: new Date().toISOString(), | ||
| createdBy, | ||
| createdAt, | ||
| // Initialize updated fields to match created fields on creation | ||
| updatedBy: createdBy, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| updatedAt: createdAt, | ||
| }; | ||
|
|
||
| const subGroup = await tx.group.create({ data: groupData }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,14 +22,59 @@ async function bootstrap() { | |
| app.setGlobalPrefix(`${apiVer}`); | ||
|
|
||
| // CORS related settings | ||
| const topcoderOriginPatterns = [ | ||
| /^https?:\/\/([\w-]+\.)*topcoder\.com(?::\d+)?$/i, | ||
| /^https?:\/\/([\w-]+\.)*topcoder-dev\.com(?::\d+)?$/i, | ||
| ]; | ||
|
|
||
| const allowList: (string | RegExp)[] = [ | ||
| 'http://localhost:3000', | ||
| /\.localhost:3000$/, | ||
| ]; | ||
|
|
||
| if (process.env.CORS_ALLOWED_ORIGIN) { | ||
| try { | ||
| allowList.push(new RegExp(process.env.CORS_ALLOWED_ORIGIN)); | ||
| } catch (error) { | ||
| const errorMessage = | ||
| error instanceof Error ? error.message : String(error); | ||
| logger.warn( | ||
| `Invalid CORS_ALLOWED_ORIGIN pattern (${process.env.CORS_ALLOWED_ORIGIN}): ${errorMessage}`, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| const isAllowedOrigin = (origin: string): boolean => { | ||
| if ( | ||
| allowList.some((allowedOrigin) => { | ||
| if (allowedOrigin instanceof RegExp) { | ||
| return allowedOrigin.test(origin); | ||
| } | ||
| return allowedOrigin === origin; | ||
| }) | ||
| ) { | ||
| return true; | ||
| } | ||
|
|
||
| return topcoderOriginPatterns.some((pattern) => pattern.test(origin)); | ||
| }; | ||
|
|
||
| const corsConfig: cors.CorsOptions = { | ||
| allowedHeaders: | ||
| 'Origin, X-Requested-With, Content-Type, Accept, Authorization, Access-Control-Allow-Origin, Access-Control-Allow-Headers,currentOrg,overrideOrg,x-atlassian-cloud-id,x-api-key,x-orgid', | ||
| credentials: true, | ||
| origin: process.env.CORS_ALLOWED_ORIGIN | ||
| ? new RegExp(process.env.CORS_ALLOWED_ORIGIN) | ||
| : ['http://localhost:3000', /\.localhost:3000$/], | ||
| methods: 'GET, POST, OPTIONS, PUT, DELETE, PATCH', | ||
| origin: (requestOrigin, callback) => { | ||
| if (!requestOrigin) { | ||
| return callback(null, false); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| } | ||
|
|
||
| if (isAllowedOrigin(requestOrigin)) { | ||
| return callback(null, requestOrigin); | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| return callback(null, false); | ||
| }, | ||
| }; | ||
| app.use(cors(corsConfig)); | ||
| logger.log('CORS configuration applied'); | ||
|
|
@@ -147,7 +192,7 @@ async function bootstrap() { | |
| const document = SwaggerModule.createDocument(app, config, { | ||
| include: [ApiModule], | ||
| }); | ||
| SwaggerModule.setup(`/api-docs`, app, document); | ||
| SwaggerModule.setup(`/v6/groups/api-docs`, app, document); | ||
| logger.log('Swagger documentation configured'); | ||
|
|
||
| // Add an event handler to log uncaught promise rejections and prevent the server from crashing | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| * Enum defining user roles for role-based access control | ||
| */ | ||
| export enum UserRole { | ||
| Admin = 'Administrator', | ||
| Admin = 'administrator', | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| Copilot = 'Copilot', | ||
| Reviewer = 'Reviewer', | ||
| Submitter = 'Submitter', | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,15 @@ const TEST_M2M_TOKENS: Record<string, string[]> = { | |
| 'm2m-token-groups': [Scope.AllGroups], | ||
| }; | ||
|
|
||
| const SCOPE_SYNONYMS: Record<string, string[]> = { | ||
| 'read:group': [Scope.ReadGroups], | ||
| [Scope.ReadGroups]: ['read:group'], | ||
| 'write:group': [Scope.WriteGroups], | ||
| [Scope.WriteGroups]: ['write:group'], | ||
| 'all:group': [Scope.AllGroups], | ||
| [Scope.AllGroups]: ['all:group'], | ||
| }; | ||
|
|
||
| @Injectable() | ||
| export class JwtService implements OnModuleInit { | ||
| private jwksClientInstance: jwksClient.JwksClient; | ||
|
|
@@ -177,16 +186,30 @@ export class JwtService implements OnModuleInit { | |
| */ | ||
| private expandScopes(scopes: string[]): string[] { | ||
| const expandedScopes = new Set<string>(); | ||
| const queue = [...scopes]; | ||
|
|
||
| // Add all original scopes | ||
| scopes.forEach((scope) => expandedScopes.add(scope)); | ||
|
|
||
| // Expand all "all:*" scopes | ||
| scopes.forEach((scope) => { | ||
| if (ALL_SCOPE_MAPPINGS[scope]) { | ||
| ALL_SCOPE_MAPPINGS[scope].forEach((s) => expandedScopes.add(s)); | ||
| while (queue.length > 0) { | ||
| const scope = queue.shift(); | ||
| if (!scope || expandedScopes.has(scope)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| continue; | ||
| } | ||
| }); | ||
|
|
||
| expandedScopes.add(scope); | ||
|
|
||
| const synonyms = SCOPE_SYNONYMS[scope] ?? []; | ||
| synonyms.forEach((alias) => { | ||
| if (!expandedScopes.has(alias)) { | ||
| queue.push(alias); | ||
| } | ||
| }); | ||
|
|
||
| const mappedScopes = ALL_SCOPE_MAPPINGS[scope] ?? []; | ||
| mappedScopes.forEach((alias) => { | ||
| if (!expandedScopes.has(alias)) { | ||
| queue.push(alias); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| return Array.from(expandedScopes); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[⚠️
maintainability]Using
sudo pip3 installcan lead to permission issues and conflicts with system packages. Consider using a virtual environment or a tool likepipenvto manage Python dependencies.