From 6b4eb860a47034f6cd7f4056fa16362973e27511 Mon Sep 17 00:00:00 2001 From: Russell Vinegar <38586679+rustyjux@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:40:42 -0700 Subject: [PATCH 01/37] tweak style for gateway list item hover (#1184) * tweak style for gateway list item hover * ns to gw text --- src/nextapp/pages/manager/gateways/detail.tsx | 2 +- src/nextapp/pages/manager/gateways/list.tsx | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/nextapp/pages/manager/gateways/detail.tsx b/src/nextapp/pages/manager/gateways/detail.tsx index a4d597d9d..b63036fb8 100644 --- a/src/nextapp/pages/manager/gateways/detail.tsx +++ b/src/nextapp/pages/manager/gateways/detail.tsx @@ -247,7 +247,7 @@ const NamespacesPage: React.FC = () => { If you need to change the Organization or Business Unit for - your Namespace, submit a request through the{' '} + your Gateway, submit a request through the{' '} { onClick={handleNamespaceChange(namespace)} cursor="pointer" transition="background-color 0.2s" - _hover={{ backgroundColor: "#f0f0f0" }} + _hover={{ + backgroundColor: "#EDEBE9", + h2: { + color: 'bc-blue', + textDecor: 'underline', + }, + + cursor: 'pointer', + }} > @@ -302,15 +310,15 @@ const MyGatewaysPage: React.FC = () => { mr={4} boxSize={4} /> - {namespace.displayName} - + {namespace.name} From 50433c878040efd17f46b26b66480c35b0e91df9 Mon Sep 17 00:00:00 2001 From: Russell Vinegar <38586679+rustyjux@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:45:14 -0800 Subject: [PATCH 02/37] fix tests to handle redirect away from your products (#1185) * fix tests to handle redirect away from your products * upload astra scan results to debug * fix legal terms URL --- .github/workflows/aps-cypress-e2e.yaml | 6 ++++++ .github/workflows/scripts/feeder-init/legal.yaml | 2 +- e2e/cypress/tests/20-gateways/02-dropdown.ts | 10 +++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 8a8046f89..aaef58651 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -76,6 +76,12 @@ jobs: name: code-coverage path: ${{ github.workspace }}/e2e/coverage + - name: Upload Astra scan results + uses: actions/upload-artifact@v4 + with: + name: astra-scan-results + path: ${{ github.workspace }}/e2e/cypress/fixtures/state/scanResult.json + - name: Instrument the code for coverage analysis run: | # Rewrite the paths as the coverage starts with '../app'! diff --git a/.github/workflows/scripts/feeder-init/legal.yaml b/.github/workflows/scripts/feeder-init/legal.yaml index 257fc7a0d..26a7b2b03 100644 --- a/.github/workflows/scripts/feeder-init/legal.yaml +++ b/.github/workflows/scripts/feeder-init/legal.yaml @@ -2,6 +2,6 @@ entity: Legal record: id: "terms-of-use-for-api-gateway-1" title: "Terms of Use for API Gateway" - link: "https://www2.gov.bc.ca/gov/content/data/open-data/api-terms-of-use-for-ogl-information" + link: "https://www2.gov.bc.ca/gov/content/data/policy-standards/open-data/api-terms-of-use-for-ogl-information" document: terms-of-use version: 1 diff --git a/e2e/cypress/tests/20-gateways/02-dropdown.ts b/e2e/cypress/tests/20-gateways/02-dropdown.ts index 8841c581c..886110317 100644 --- a/e2e/cypress/tests/20-gateways/02-dropdown.ts +++ b/e2e/cypress/tests/20-gateways/02-dropdown.ts @@ -37,7 +37,11 @@ describe('Gateway selector dropdown', () => { it('Get current total number of gateways', () => { // Create a new gateway to ensure there is at least one gateway - cy.createGateway(); + cy.createGateway().then((response) => { + const namespace = response.gatewayId + cy.log('New namespace created: ' + namespace) + cy.activateGateway(namespace); + }); cy.visit(ad.yourProductsPath); cy.get('[data-testid="ns-dropdown-btn"]').click(); @@ -81,8 +85,8 @@ describe('Gateway selector dropdown', () => { it('Recently used gateways are shown in the dropdown', () => { cy.visit(ns.listPath) cy.get(`[data-testid="ns-list-activate-link-${gateways["namespace1"].gatewayId + '-' + customId}"]`).click() - cy.get('[data-testid="ns-dropdown-btn"]').click() - cy.get(`[data-testid="ns-dropdown-item-${gateways["namespace2"].gatewayId + '-' + customId}"]`).click() + cy.visit(ns.listPath) + cy.get(`[data-testid="ns-list-activate-link-${gateways["namespace2"].gatewayId + '-' + customId}"]`).click() cy.get('[data-testid="ns-dropdown-btn"]').click() cy.get('[data-testid="ns-dropdown-heading"]').should('contain.text', "Recently viewed") cy.get(`[data-testid="ns-dropdown-item-${gateways["namespace1"].gatewayId + '-' + customId}"]`).should('exist') From a36e6729524e282cd1a52f39beacd30e39d6439a Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Mon, 9 Dec 2024 09:21:17 -0800 Subject: [PATCH 03/37] add PR review reminders --- .github/workflows/pr-reminder.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/workflows/pr-reminder.yaml diff --git a/.github/workflows/pr-reminder.yaml b/.github/workflows/pr-reminder.yaml new file mode 100644 index 000000000..63a532f9a --- /dev/null +++ b/.github/workflows/pr-reminder.yaml @@ -0,0 +1,14 @@ +name: 'Send review reminders' +on: + schedule: + - cron: '30 8 * * 1,3,5' # Scheduled to run at 1:30 AM, Monday, Wednesday, Friday + +jobs: + remind: + runs-on: ubuntu-latest + steps: + - name: Run PR reviewer reminder + uses: bcgov/aps-devops/pr-reminder@dev + with: + token: ${{ secrets.GITHUB_TOKEN }} + dry_run: "false" From acb9071d1ebb1bbedb6a73477ce69d07c498dd78 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Mon, 16 Dec 2024 12:06:55 -0800 Subject: [PATCH 04/37] set OS for Jira GHA runner --- .github/workflows/jira.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/jira.yaml b/.github/workflows/jira.yaml index af57a5b5a..c05fbe0e5 100644 --- a/.github/workflows/jira.yaml +++ b/.github/workflows/jira.yaml @@ -4,7 +4,7 @@ on: [issues, issue_comment] jobs: sync-issues: name: Sync issues to Jira - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: ikethecoder/sync-issues-github-jira@dev with: From 1df2aabaedd87c70035aa802720fbf10103ae836 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Mon, 16 Dec 2024 12:18:40 -0800 Subject: [PATCH 05/37] Update GitHub Actions to use CodeQL SARIF upload v2 in image scan workflows --- .github/workflows/ci-anchore-img-scan.yaml | 2 +- .github/workflows/ci-trivy-img-scan.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml index 39ee38ae8..c809879b9 100644 --- a/.github/workflows/ci-anchore-img-scan.yaml +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -19,6 +19,6 @@ jobs: acs-report-enable: true fail-build: false - name: Upload Anchore Scan Results - uses: github/codeql-action/upload-sarif@v1 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: results.sarif diff --git a/.github/workflows/ci-trivy-img-scan.yaml b/.github/workflows/ci-trivy-img-scan.yaml index 4a08ebeda..bcea8fdba 100644 --- a/.github/workflows/ci-trivy-img-scan.yaml +++ b/.github/workflows/ci-trivy-img-scan.yaml @@ -24,6 +24,6 @@ jobs: template: '@/contrib/sarif.tpl' output: 'trivy-results.sarif' - name: Upload Trivy Scan Results - uses: github/codeql-action/upload-sarif@v1 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: 'trivy-results.sarif' From f3bbbd34850aa7adbefb8e506975563b4787b667 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Mon, 16 Dec 2024 12:52:39 -0800 Subject: [PATCH 06/37] Update GitHub Actions to use CodeQL SARIF upload v3 in image scan workflows --- .github/workflows/ci-anchore-img-scan.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml index c809879b9..61670c497 100644 --- a/.github/workflows/ci-anchore-img-scan.yaml +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -19,6 +19,6 @@ jobs: acs-report-enable: true fail-build: false - name: Upload Anchore Scan Results - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: results.sarif From e21eafaceb6f49e32d7fb2584efbcb4afa1725ee Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Mon, 16 Dec 2024 13:55:48 -0800 Subject: [PATCH 07/37] Remove deprecated acs-report-enable option from Anchore image scan workflow --- .github/workflows/ci-anchore-img-scan.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml index 61670c497..8c60b6393 100644 --- a/.github/workflows/ci-anchore-img-scan.yaml +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -16,7 +16,6 @@ jobs: uses: anchore/scan-action@main with: image: 'bcgov/api-services-portal:anchore-scan' - acs-report-enable: true fail-build: false - name: Upload Anchore Scan Results uses: github/codeql-action/upload-sarif@v3 From bc59a964267fada73336369217c5220c1eed906f Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 17 Dec 2024 12:31:49 -0800 Subject: [PATCH 08/37] Update Dockerfiles to use Node.js 22 --- Dockerfile | 2 +- feeds/Dockerfile | 2 +- local/cypress-jwks-url/Dockerfile | 2 +- local/html-sample-app/Dockerfile | 2 +- local/portal/Dockerfile.E2E | 2 +- oauth2-proxy/sample-upstream/Dockerfile | 2 +- src/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 35c3ec152..afaf9c2e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ #FROM node:lts-alpine3.17 -FROM node:16.14.2-alpine3.15 +FROM node:22.12.0-alpine3.21 ARG APP_VERSION ENV NEXT_PUBLIC_APP_VERSION=${APP_VERSION} diff --git a/feeds/Dockerfile b/feeds/Dockerfile index 71762d635..bfda758c6 100644 --- a/feeds/Dockerfile +++ b/feeds/Dockerfile @@ -1,5 +1,5 @@ #FROM node:lts-alpine3.17 -FROM node:16.14.2-alpine3.15 +FROM node:22.12.0-alpine3.21 RUN apk add curl jq diff --git a/local/cypress-jwks-url/Dockerfile b/local/cypress-jwks-url/Dockerfile index 9090ef854..34ab14541 100644 --- a/local/cypress-jwks-url/Dockerfile +++ b/local/cypress-jwks-url/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.14.2-alpine3.15 +FROM node:22.12.0-alpine3.21 WORKDIR /src diff --git a/local/html-sample-app/Dockerfile b/local/html-sample-app/Dockerfile index 14ff920ab..5613684e8 100644 --- a/local/html-sample-app/Dockerfile +++ b/local/html-sample-app/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.14.2-alpine3.15 +FROM node:22.12.0-alpine3.21 WORKDIR /src diff --git a/local/portal/Dockerfile.E2E b/local/portal/Dockerfile.E2E index c18e31adf..d0a18f2e6 100644 --- a/local/portal/Dockerfile.E2E +++ b/local/portal/Dockerfile.E2E @@ -1,5 +1,5 @@ #FROM node:lts-alpine3.18 -FROM node:16.14.2-alpine3.15 +FROM node:22.12.0-alpine3.21 ARG APP_VERSION ENV APP_VERSION=${APP_VERSION} diff --git a/oauth2-proxy/sample-upstream/Dockerfile b/oauth2-proxy/sample-upstream/Dockerfile index f76d6f332..6f5e0b281 100644 --- a/oauth2-proxy/sample-upstream/Dockerfile +++ b/oauth2-proxy/sample-upstream/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.14.2-alpine3.15 AS BUILD +FROM node:22.12.0-alpine3.21 AS BUILD COPY package*.json /app/ diff --git a/src/package.json b/src/package.json index 147f8aad3..8d04ff94f 100644 --- a/src/package.json +++ b/src/package.json @@ -43,7 +43,7 @@ "mock-server": "nodemon ./test/mock-server/server.js", "ks-build": "cross-env NODE_ENV=production keystone build --entry=dist/server.js --out=dist2", "start": "cross-env NODE_ENV=production keystone start --entry=dist/server.js", - "build": "NODE_OPTIONS='--dns-result-order=ipv4first' npm-run-all delete-assets copy-assets tsoa-build-v1 tsoa-build-v2 tsoa-build-v3 ts-build ks-build copy-keystone-admin-assets", + "build": "NODE_OPTIONS='--dns-result-order=ipv4first --openssl-legacy-provider' npm-run-all delete-assets copy-assets tsoa-build-v1 tsoa-build-v2 tsoa-build-v3 ts-build ks-build copy-keystone-admin-assets", "create-tables": "cross-env CREATE_TABLES=true keystone create-tables --entry=dist/server.js", "lint": "eslint ./nextapp --ext .ts,.tsx --quiet", "lint:ts": "tsc -p ./nextapp/tsconfig.json --noEmit", From 184c5f35dc75bf6377210f84e4a6119663f5d121 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 17 Dec 2024 12:49:18 -0800 Subject: [PATCH 09/37] update reminder schedule --- .github/workflows/pr-reminder.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-reminder.yaml b/.github/workflows/pr-reminder.yaml index 63a532f9a..bbec23c1d 100644 --- a/.github/workflows/pr-reminder.yaml +++ b/.github/workflows/pr-reminder.yaml @@ -1,7 +1,7 @@ name: 'Send review reminders' on: schedule: - - cron: '30 8 * * 1,3,5' # Scheduled to run at 1:30 AM, Monday, Wednesday, Friday + - cron: '30 8 * * 1,2,3,4,5' # Scheduled to run at 1:30 AM, weekdays jobs: remind: From cc306eb06fbc91aec1d43dad868f1086c50bc114 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 17 Dec 2024 12:58:40 -0800 Subject: [PATCH 10/37] adjust PR reminder timing --- .github/workflows/pr-reminder.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-reminder.yaml b/.github/workflows/pr-reminder.yaml index bbec23c1d..aab1e8922 100644 --- a/.github/workflows/pr-reminder.yaml +++ b/.github/workflows/pr-reminder.yaml @@ -1,7 +1,7 @@ name: 'Send review reminders' on: schedule: - - cron: '30 8 * * 1,2,3,4,5' # Scheduled to run at 1:30 AM, weekdays + - cron: '30 13 * * 1,2,3,4,5' # Scheduled to run at 5:30 AM PST, weekdays jobs: remind: From 091b77ed3793b2fb74ee1f0cabcae0b8ebbcacd7 Mon Sep 17 00:00:00 2001 From: Russell Vinegar <38586679+rustyjux@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:26:09 -0800 Subject: [PATCH 11/37] update ns --> gw in API endpoint names and descriptions * rename namespace-profile endpoint * update ns --> gw in API descriptions * delete routes.ts and openapi.yaml (generated during build) --- src/controllers/v3/DatasetController.ts | 4 +- src/controllers/v3/GatewayController.ts | 16 +- .../v3/GatewayDirectoryController.ts | 2 +- .../v3/GatewayServicesController.ts | 2 +- src/controllers/v3/IssuerController.ts | 4 +- src/controllers/v3/OrganizationController.ts | 12 +- src/controllers/v3/openapi.yaml | 1722 ---------------- src/controllers/v3/routes.ts | 1726 ----------------- 8 files changed, 20 insertions(+), 3468 deletions(-) delete mode 100644 src/controllers/v3/openapi.yaml delete mode 100644 src/controllers/v3/routes.ts diff --git a/src/controllers/v3/DatasetController.ts b/src/controllers/v3/DatasetController.ts index 57ff6a119..0bab150bd 100644 --- a/src/controllers/v3/DatasetController.ts +++ b/src/controllers/v3/DatasetController.ts @@ -40,7 +40,7 @@ export class DatasetController extends Controller { /** * Update metadata about a Dataset - * > `Required Scope:` Namespace.Manage + * > `Required Scope:` Gateway.Manage * * @summary Update Dataset */ @@ -66,7 +66,7 @@ export class DatasetController extends Controller { /** * Get metadata about a Dataset - * > `Required Scope:` Namespace.Manage + * > `Required Scope:` Gateway.Manage * * @summary Get Dataset */ diff --git a/src/controllers/v3/GatewayController.ts b/src/controllers/v3/GatewayController.ts index 20e208481..7e7e70831 100644 --- a/src/controllers/v3/GatewayController.ts +++ b/src/controllers/v3/GatewayController.ts @@ -121,7 +121,7 @@ export class NamespaceController extends Controller { /** * Get details about the gateway, such as permissions for what the gateway is setup with. - * > `Required Scope:` Namespace.Manage + * > `Required Scope:` Gateway.Manage * * @summary Gateway Summary * @param ns @@ -129,7 +129,7 @@ export class NamespaceController extends Controller { * @returns */ @Get('/{gatewayId}') - @OperationId('namespace-profile') + @OperationId('gateway-profile') @Security('jwt', ['Namespace.Manage']) public async profile( @Path() gatewayId: string, @@ -174,7 +174,7 @@ export class NamespaceController extends Controller { errors[`d${ind}`] = { message: err.message }; }); logger.error('%j', result); - throw new ValidateError(errors, 'Unable to create namespace'); + throw new ValidateError(errors, 'Unable to create Gateway'); } return { gatewayId: result.data.createNamespace.name, @@ -184,7 +184,7 @@ export class NamespaceController extends Controller { /** * Delete the gateway - * > `Required Scope:` Namespace.Manage + * > `Required Scope:` Gateway.Manage * * @summary Delete Gateway * @param ns @@ -192,7 +192,7 @@ export class NamespaceController extends Controller { * @returns */ @Delete('/{gatewayId}') - @OperationId('delete-namespace') + @OperationId('delete-gateway') @Security('jwt', ['Namespace.Manage']) public async delete( @Path() gatewayId: string, @@ -218,9 +218,9 @@ export class NamespaceController extends Controller { } /** - * > `Required Scope:` Namespace.View + * > `Required Scope:` Gateway.View * - * @summary Get administration activity for this gateway + * @summary Get administration activity for this Gateway * @param ns * @param first * @param skip @@ -251,7 +251,7 @@ export class NamespaceController extends Controller { /** * Get a summary of your endpoints - * > `Required Scope:` Namespace.Manage + * > `Required Scope:` Gateway.Manage * * @summary Get endpoints */ diff --git a/src/controllers/v3/GatewayDirectoryController.ts b/src/controllers/v3/GatewayDirectoryController.ts index a5de7ce90..fbbb44bbf 100644 --- a/src/controllers/v3/GatewayDirectoryController.ts +++ b/src/controllers/v3/GatewayDirectoryController.ts @@ -61,7 +61,7 @@ export class GatewayDirectoryController extends Controller { /** * Used primarily for "Preview Mode" - * List the datasets belonging to a particular namespace + * List the datasets belonging to a particular Gateway * * @param ns * @param name diff --git a/src/controllers/v3/GatewayServicesController.ts b/src/controllers/v3/GatewayServicesController.ts index 801e5837b..eb902cce6 100644 --- a/src/controllers/v3/GatewayServicesController.ts +++ b/src/controllers/v3/GatewayServicesController.ts @@ -47,7 +47,7 @@ export class GatewayController extends Controller { /** * Get a summary of your Gateway Services - * > `Required Scope:` Namespace.Manage + * > `Required Scope:` Gateway.Manage * * @summary Get Gateway Services */ diff --git a/src/controllers/v3/IssuerController.ts b/src/controllers/v3/IssuerController.ts index 98598932c..e87b34c85 100644 --- a/src/controllers/v3/IssuerController.ts +++ b/src/controllers/v3/IssuerController.ts @@ -60,8 +60,8 @@ export class IssuerController extends Controller { } /** - * Get Authorization Profiles setup in this namespace - * > `Required Scope:` Namespace.Manage + * Get Authorization Profiles setup in this Gateway + * > `Required Scope:` Gateway.Manage * * @summary Get Authorization Profiles */ diff --git a/src/controllers/v3/OrganizationController.ts b/src/controllers/v3/OrganizationController.ts index a4d904cfc..1597c3a26 100644 --- a/src/controllers/v3/OrganizationController.ts +++ b/src/controllers/v3/OrganizationController.ts @@ -181,7 +181,7 @@ export class OrganizationController extends Controller { } /** - * > `Required Scope:` Namespace.Assign + * > `Required Scope:` Gateway.Assign */ @Get('{org}/gateways') @OperationId('organization-gateways') @@ -196,7 +196,7 @@ export class OrganizationController extends Controller { } /** - * > `Required Scope:` Namespace.Assign + * > `Required Scope:` Gateway.Assign */ @Put('{org}/{orgUnit}/gateways/{gatewayId}') @OperationId('assign-namespace-to-organization') @@ -231,7 +231,7 @@ export class OrganizationController extends Controller { } /** - * > `Required Scope:` Namespace.Assign + * > `Required Scope:` Gateway.Assign */ @Delete('{org}/{orgUnit}/gateways/{gatewayId}') @OperationId('unassign-namespace-from-organization') @@ -265,16 +265,16 @@ export class OrganizationController extends Controller { } /** - * > `Required Scope:` Namespace.Assign + * > `Required Scope:` Gateway.Assign * - * @summary Get administration activity for gateways associated with this Organization + * @summary Get administration activity for Gateways associated with this Organization * @param org * @param first * @param skip * @returns Activity[] */ @Get('{org}/activity') - @OperationId('org-namespace-activity') + @OperationId('org-gateway-activity') @Security('jwt', ['Namespace.Assign']) public async namespaceActivity( @Path() org: string, diff --git a/src/controllers/v3/openapi.yaml b/src/controllers/v3/openapi.yaml deleted file mode 100644 index ec2d79f47..000000000 --- a/src/controllers/v3/openapi.yaml +++ /dev/null @@ -1,1722 +0,0 @@ -components: - examples: {} - headers: {} - parameters: {} - requestBodies: {} - responses: {} - schemas: - DatasetContact: - properties: - name: - type: string - email: - type: string - role: - type: string - enum: - - pointOfContact - nullable: false - type: object - additionalProperties: false - DatasetResource: - properties: - id: - type: string - name: - type: string - format: - type: string - enum: - - openapi-json - - json - url: - type: string - type: object - additionalProperties: false - OrganizationRefID: - type: string - OrganizationUnitRefID: - type: string - Dataset: - properties: - extForeignKey: - type: string - name: - type: string - license_title: - type: string - security_class: - type: string - view_audience: - type: string - download_audience: - type: string - record_publish_date: - type: string - notes: - type: string - title: - type: string - isInCatalog: - type: string - isDraft: - type: string - contacts: - items: - $ref: '#/components/schemas/DatasetContact' - type: array - resources: - items: - $ref: '#/components/schemas/DatasetResource' - type: array - extSource: - type: string - extRecordHash: - type: string - tags: - items: - type: string - type: array - organization: - $ref: '#/components/schemas/OrganizationRefID' - organizationUnit: - $ref: '#/components/schemas/OrganizationUnitRefID' - type: object - additionalProperties: false - BatchResult: - properties: - status: - type: number - format: double - result: - type: string - reason: - type: string - id: - type: string - ownedBy: - type: string - childResults: - items: - $ref: '#/components/schemas/BatchResult' - type: array - required: - - status - - result - type: object - additionalProperties: false - DraftDataset: - properties: - name: - type: string - license_title: - type: string - security_class: - type: string - enum: - - HIGH-CABINET - - HIGH-CONFIDENTIAL - - HIGH-SENSITIVITY - - MEDIUM-SENSITIVITY - - MEDIUM-PERSONAL - - LOW-SENSITIVITY - - LOW-PUBLIC - - PUBLIC - - 'PROTECTED A' - - 'PROTECTED B' - - 'PROTECTED C' - view_audience: - type: string - enum: - - Public - - Government - - 'Named users' - - 'Government and Business BCeID' - download_audience: - type: string - enum: - - Public - - Government - - 'Named users' - - 'Government and Business BCeID' - record_publish_date: - type: string - notes: - type: string - title: - type: string - isInCatalog: - type: boolean - isDraft: - type: boolean - contacts: - items: - $ref: '#/components/schemas/DatasetContact' - type: array - resources: - items: - $ref: '#/components/schemas/DatasetResource' - type: array - tags: - items: - type: string - type: array - organization: - $ref: '#/components/schemas/OrganizationRefID' - organizationUnit: - $ref: '#/components/schemas/OrganizationUnitRefID' - type: object - additionalProperties: false - example: - name: my_sample_dataset - license_title: 'Open Government Licence - British Columbia' - security_class: PUBLIC - view_audience: Public - download_audience: Public - record_publish_date: '2017-09-05' - notes: 'Some notes' - title: 'A title about my dataset' - tags: - - tag1 - - tag2 - organization: ministry-of-citizens-services - organizationUnit: databc - Gateway: - properties: - gatewayId: - type: string - displayName: - type: string - type: object - additionalProperties: false - ActivityDetail: - properties: - id: - type: string - message: - type: string - params: - properties: {} - additionalProperties: - type: string - type: object - activityAt: {} - blob: {} - required: - - message - - params - - activityAt - type: object - additionalProperties: false - PublishResult: - properties: - message: - type: string - results: - type: string - error: - type: string - type: object - additionalProperties: false - GatewayServiceRefID: - type: string - GatewayRouteRefID: - type: string - GatewayPlugin: - properties: - extForeignKey: - type: string - name: - type: string - extSource: - type: string - extRecordHash: - type: string - tags: - items: - type: string - type: array - config: {} - service: - $ref: '#/components/schemas/GatewayServiceRefID' - route: - $ref: '#/components/schemas/GatewayRouteRefID' - type: object - additionalProperties: false - GatewayRoute: - properties: - extForeignKey: - type: string - name: - type: string - gatewayId: - type: string - extSource: - type: string - extRecordHash: - type: string - tags: - items: - type: string - type: array - methods: - items: - type: string - type: array - paths: - items: - type: string - type: array - hosts: - items: - type: string - type: array - service: - $ref: '#/components/schemas/GatewayServiceRefID' - plugins: - items: - $ref: '#/components/schemas/GatewayPlugin' - type: array - type: object - additionalProperties: false - IssuerEnvironmentConfig: - properties: - environment: - type: string - exists: - type: boolean - issuerUrl: - type: string - clientRegistration: - type: string - enum: - - anonymous - - managed - - iat - clientId: - type: string - clientSecret: - type: string - initialAccessToken: - type: string - type: object - additionalProperties: false - example: - environment: dev - issuerUrl: 'https://idp.site/auth/realms/my-realm' - clientRegistration: managed - clientId: a-client-id - clientSecret: a-client-secret - undefinedRefID: - type: string - CredentialIssuer: - properties: - name: - type: string - gatewayId: - type: string - description: - type: string - flow: - type: string - enum: - - client-credentials - nullable: false - mode: - type: string - enum: - - auto - nullable: false - authPlugin: - type: string - clientAuthenticator: - type: string - enum: - - client-secret - - client-jwt - - client-jwt-jwks-url - instruction: - type: string - environmentDetails: - items: - $ref: '#/components/schemas/IssuerEnvironmentConfig' - type: array - resourceType: - type: string - resourceAccessScope: - type: string - isShared: - type: boolean - apiKeyName: - type: string - availableScopes: - items: - type: string - type: array - resourceScopes: - items: - type: string - type: array - clientRoles: - items: - type: string - type: array - clientMappers: - items: - type: string - type: array - inheritFrom: - $ref: '#/components/schemas/undefinedRefID' - owner: - $ref: '#/components/schemas/undefinedRefID' - type: object - additionalProperties: false - example: - name: my-auth-profile - description: 'Auth connection to my IdP' - flow: client-credentials - clientAuthenticator: client-secret - mode: auto - environmentDetails: [] - owner: janis@gov.bc.ca - OrganizationUnit: - properties: - extForeignKey: - type: string - name: - type: string - sector: - type: string - title: - type: string - description: - type: string - extSource: - type: string - extRecordHash: - type: string - tags: - items: - type: string - type: array - type: object - additionalProperties: false - Organization: - properties: - extForeignKey: - type: string - name: - type: string - sector: - type: string - title: - type: string - description: - type: string - extSource: - type: string - extRecordHash: - type: string - tags: - items: - type: string - type: array - orgUnits: - items: - $ref: '#/components/schemas/OrganizationUnit' - type: array - type: object - additionalProperties: false - GroupPermission: - properties: - resource: - type: string - scopes: - items: - type: string - type: array - required: - - scopes - type: object - additionalProperties: false - GroupRole: - properties: - name: - type: string - permissions: - items: - $ref: '#/components/schemas/GroupPermission' - type: array - required: - - name - - permissions - type: object - additionalProperties: false - GroupAccess: - properties: - name: - type: string - parent: - type: string - roles: - items: - $ref: '#/components/schemas/GroupRole' - type: array - required: - - roles - type: object - additionalProperties: false - UserReference: - properties: - id: - type: string - email: - type: string - type: object - additionalProperties: false - GroupMember: - properties: - member: - $ref: '#/components/schemas/UserReference' - roles: - items: - type: string - type: array - required: - - member - - roles - type: object - additionalProperties: false - GroupMembership: - properties: - name: - type: string - parent: - type: string - members: - items: - $ref: '#/components/schemas/GroupMember' - type: array - type: object - additionalProperties: false - OrgNamespace: - properties: - name: - type: string - orgUnit: - type: string - enabled: - type: boolean - updatedAt: - type: number - format: double - required: - - name - - orgUnit - - enabled - - updatedAt - type: object - additionalProperties: false - DraftDatasetRefID: - type: string - LegalRefID: - type: string - CredentialIssuerRefID: - type: string - Environment: - properties: - appId: - type: string - name: - type: string - enum: - - dev - - test - - prod - - sandbox - - other - active: - type: boolean - approval: - type: boolean - flow: - type: string - enum: - - public - - protected-externally - - authorization-code - - client-credentials - - kong-acl-only - - kong-api-key-only - - kong-api-key-acl - additionalDetailsToRequest: - type: string - services: - items: - $ref: '#/components/schemas/GatewayServiceRefID' - type: array - legal: - $ref: '#/components/schemas/LegalRefID' - credentialIssuer: - $ref: '#/components/schemas/CredentialIssuerRefID' - type: object - additionalProperties: false - example: - name: dev - active: false - approval: false - flow: public - appId: '00000000' - Product: - properties: - appId: - type: string - name: - type: string - description: - type: string - gatewayId: - type: string - dataset: - $ref: '#/components/schemas/DraftDatasetRefID' - environments: - items: - $ref: '#/components/schemas/Environment' - type: array - type: object - additionalProperties: false - example: - name: my-new-product - appId: '000000000000' - environments: - - - name: dev - active: false - approval: false - flow: public - appId: '00000000' - securitySchemes: - jwt: - type: oauth2 - description: 'Authz Client Credential' - flows: - clientCredentials: - tokenUrl: 'https://token_endpoint' - scopes: {} - portal: - type: http - description: 'Authz Portal Login' - scheme: bearer - bearerFormat: JWT - openid: - type: openIdConnect - description: 'OIDC Login' - openIdConnectUrl: 'https://well_known_endpoint' -info: - title: 'APS Directory API' - version: 3.0.0 - description: 'API Services Portal by BC Gov API Programme Services' - license: - name: MIT - contact: - name: 'BC Gov APS' -openapi: 3.0.0 -paths: - '/organizations/{org}/datasets': - get: - operationId: organization-datasets - responses: - '200': - description: Ok - content: - application/json: - schema: - items: - $ref: '#/components/schemas/Dataset' - type: array - description: "Get metadata about Datasets that are available by API for this organization\n> `Required Scope:` Dataset.Manage" - summary: 'Get Organization Datasets' - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Dataset.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - put: - operationId: put-organization-dataset - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Manage metadata about Datasets that are available by API for this organization\n> `Required Scope:` Dataset.Manage" - summary: 'Manage Organization Datasets' - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Dataset.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/DraftDataset' - '/organizations/{org}/datasets/{name}': - delete: - operationId: delete-dataset - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Delete a Dataset\n> `Required Scope:` Dataset.Manage" - summary: 'Delete a dataset' - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Dataset.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - - - in: path - name: name - required: true - schema: - type: string - get: - operationId: get-organization-dataset - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/Dataset' - description: "Get metadata about a Dataset that are available by API for this organization\n> `Required Scope:` Dataset.Manage" - summary: 'Get Organization Dataset' - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Dataset.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - - - in: path - name: name - required: true - schema: - type: string - /directory: - get: - operationId: directory-list - responses: - '200': - description: Ok - content: - application/json: - schema: {} - tags: - - 'API Directory' - security: [] - parameters: [] - '/directory/{id}': - get: - operationId: directory-item - responses: - '200': - description: Ok - content: - application/json: - schema: {} - tags: - - 'API Directory' - security: [] - parameters: - - - in: path - name: id - required: true - schema: - type: string - '/gateways/{gatewayId}/datasets': - put: - operationId: put-dataset - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Update metadata about a Dataset\n> `Required Scope:` Namespace.Manage" - summary: 'Update Dataset' - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/DraftDataset' - '/gateways/{gatewayId}/datasets/{name}': - get: - operationId: get-dataset - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/Dataset' - description: "Get metadata about a Dataset\n> `Required Scope:` Namespace.Manage" - summary: 'Get Dataset' - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: path - name: name - required: true - schema: - type: string - /routes/availability: - get: - operationId: check-availability - responses: - '200': - description: Ok - content: - application/json: - schema: {} - tags: - - 'Service Routes' - security: [] - parameters: - - - in: query - name: serviceName - required: true - schema: - type: string - - - in: query - name: gatewayId - required: true - schema: - type: string - /gateways/report: - get: - operationId: report - responses: - '200': - description: Ok - content: - application/json: - schema: {} - tags: - - Gateways - security: - - - jwt: [] - parameters: - - - in: query - name: ids - required: false - schema: - default: '[]' - type: string - /gateways: - get: - operationId: gateway-list - responses: - '200': - description: Ok - content: - application/json: - schema: - items: - $ref: '#/components/schemas/Gateway' - type: array - summary: 'List of Gateways available to the user' - tags: - - Gateways - security: - - - jwt: [] - parameters: [] - post: - operationId: create-gateway - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/Gateway' - description: 'Create a gateway' - summary: 'Create Gateway' - tags: - - Gateways - security: - - - jwt: [] - parameters: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Gateway' - '/gateways/{gatewayId}': - get: - operationId: namespace-profile - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/Gateway' - description: "Get details about the gateway, such as permissions for what the gateway is setup with.\n> `Required Scope:` Namespace.Manage" - summary: 'Gateway Summary' - tags: - - Gateways - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - delete: - operationId: delete-namespace - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/Gateway' - description: "Delete the gateway\n> `Required Scope:` Namespace.Manage" - summary: 'Delete Gateway' - tags: - - Gateways - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: query - name: force - required: false - schema: - default: false - type: boolean - '/gateways/{gatewayId}/activity': - get: - operationId: gateway-admin-activity - responses: - '200': - description: 'Activity[]' - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ActivityDetail' - type: array - description: '> `Required Scope:` Namespace.View' - summary: 'Get administration activity for this gateway' - tags: - - Gateways - security: - - - jwt: - - Namespace.View - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: query - name: first - required: false - schema: - default: 20 - format: double - type: number - - - in: query - name: skip - required: false - schema: - default: 0 - format: double - type: number - '/gateways/{gatewayId}/links': - get: - operationId: get-gateway-links - responses: - '200': - description: Ok - content: - application/json: - schema: - items: - properties: {host: {type: string}} - required: [host] - type: object - type: array - description: "Get a summary of your endpoints\n> `Required Scope:` Namespace.Manage" - summary: 'Get endpoints' - tags: - - Gateways - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - '/gateways/{gatewayId}/directory/{id}': - get: - operationId: get-ns-directory-dataset - responses: - '200': - description: Ok - content: - application/json: - schema: {} - description: "Used primarily for \"Preview Mode\"\nGet a particular Dataset" - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: path - name: id - required: true - schema: - type: string - '/gateways/{gatewayId}/directory': - get: - operationId: get-ns-directory - responses: - '200': - description: Ok - content: - application/json: - schema: {} - description: "Used primarily for \"Preview Mode\"\nList the datasets belonging to a particular namespace" - tags: - - 'API Directory (Administration)' - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - '/gateways/{gatewayId}/services': - put: - operationId: publish-gateway-config - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/PublishResult' - tags: - - 'Gateway Services' - security: - - - jwt: - - Gateway.Config - parameters: [] - requestBody: - required: true - content: - multipart/form-data: - schema: - type: object - properties: - dryRun: - type: string - configFile: - type: string - format: binary - required: - - dryRun - - configFile - get: - operationId: get-gateway-routes - responses: - '200': - description: Ok - content: - application/json: - schema: - items: - $ref: '#/components/schemas/GatewayRoute' - type: array - description: "Get a summary of your Gateway Services\n> `Required Scope:` Namespace.Manage" - summary: 'Get Gateway Services' - tags: - - 'Gateway Services' - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - '/identifiers/{type}': - get: - operationId: GetNewID - responses: - '200': - description: Ok - content: - application/json: - schema: - type: string - tags: - - 'New Identifiers' - security: [] - parameters: - - - in: path - name: type - required: true - schema: - type: string - enum: - - environment - - product - - application - - gateway - '/gateways/{gatewayId}/issuers': - put: - operationId: put-issuer - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Create or Update Authorization Profiles\n> `Required Scope:` CredentialIssuer.Admin" - summary: 'Manage Authorization Profiles' - tags: - - 'Authorization Profiles' - security: - - - jwt: - - CredentialIssuer.Admin - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CredentialIssuer' - get: - operationId: get-issuers - responses: - '200': - description: Ok - content: - application/json: - schema: - items: - $ref: '#/components/schemas/CredentialIssuer' - type: array - description: "Get Authorization Profiles setup in this namespace\n> `Required Scope:` Namespace.Manage" - summary: 'Get Authorization Profiles' - tags: - - 'Authorization Profiles' - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - '/gateways/{gatewayId}/issuers/{name}': - delete: - operationId: delete-issuer - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Delete an Authorization Profile\n> `Required Scope:` CredentialIssuer.Admin" - summary: 'Delete Profile' - tags: - - 'Authorization Profiles' - security: - - - jwt: - - CredentialIssuer.Admin - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: path - name: name - required: true - schema: - type: string - /organizations: - get: - operationId: organization-list - responses: - '200': - description: Ok - content: - application/json: - schema: - items: {} - type: array - tags: - - Organizations - security: [] - parameters: [] - '/organizations/{org}': - put: - operationId: put-organization - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Create Organization\n> `Required Scope:` GroupAccess.Manage" - summary: 'Create Organizations' - tags: - - Organizations - security: - - - jwt: - - GroupAccess.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Organization' - get: - operationId: organization-units - responses: - '200': - description: Ok - content: - application/json: - schema: {} - tags: - - Organizations - security: [] - parameters: - - - in: path - name: org - required: true - schema: - type: string - '/organizations/{org}/roles': - get: - operationId: get-organization-roles - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/GroupAccess' - description: '> `Required Scope:` GroupAccess.Manage' - tags: - - Organizations - security: - - - jwt: - - GroupAccess.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - '/organizations/{org}/access': - get: - operationId: get-organization-access - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/GroupMembership' - description: '> `Required Scope:` GroupAccess.Manage' - tags: - - Organizations - security: - - - jwt: - - GroupAccess.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - put: - operationId: put-organization-access - responses: - '204': - description: 'No content' - description: '> `Required Scope:` GroupAccess.Manage' - tags: - - Organizations - security: - - - jwt: - - GroupAccess.Manage - parameters: - - - in: path - name: org - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GroupMembership' - '/organizations/{org}/gateways': - get: - operationId: organization-gateways - responses: - '200': - description: Ok - content: - application/json: - schema: - items: - $ref: '#/components/schemas/OrgNamespace' - type: array - description: '> `Required Scope:` Namespace.Assign' - tags: - - Organizations - security: - - - jwt: - - Namespace.Assign - parameters: - - - in: path - name: org - required: true - schema: - type: string - '/organizations/{org}/{orgUnit}/gateways/{gatewayId}': - put: - operationId: assign-namespace-to-organization - responses: - '200': - description: Ok - content: - application/json: - schema: - properties: - result: {type: string} - required: - - result - type: object - description: '> `Required Scope:` Namespace.Assign' - tags: - - Organizations - security: - - - jwt: - - Namespace.Assign - parameters: - - - in: path - name: org - required: true - schema: - type: string - - - in: path - name: orgUnit - required: true - schema: - type: string - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: query - name: enable - required: false - schema: - default: true - type: boolean - delete: - operationId: unassign-namespace-from-organization - responses: - '200': - description: Ok - content: - application/json: - schema: - properties: - result: {type: string} - required: - - result - type: object - description: '> `Required Scope:` Namespace.Assign' - tags: - - Organizations - security: - - - jwt: - - Namespace.Assign - parameters: - - - in: path - name: org - required: true - schema: - type: string - - - in: path - name: orgUnit - required: true - schema: - type: string - - - in: path - name: gatewayId - required: true - schema: - type: string - '/organizations/{org}/activity': - get: - operationId: org-namespace-activity - responses: - '200': - description: 'Activity[]' - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ActivityDetail' - type: array - description: '> `Required Scope:` Namespace.Assign' - summary: 'Get administration activity for gateways associated with this Organization' - tags: - - Organizations - security: - - - jwt: - - Namespace.Assign - parameters: - - - in: path - name: org - required: true - schema: - type: string - - - in: query - name: first - required: false - schema: - default: 20 - format: double - type: number - - - in: query - name: skip - required: false - schema: - default: 0 - format: double - type: number - /roles: - get: - operationId: GetRoles - responses: - '200': - description: Ok - content: - application/json: - schema: {} - tags: - - Organizations - security: [] - parameters: [] - '/gateways/{gatewayId}/products': - put: - operationId: put-product - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Manage Products for APIs that will appear on the API Directory\n> `Required Scope:` Namespace.Manage" - summary: 'Manage Products' - tags: - - Products - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Product' - get: - operationId: get-products - responses: - '200': - description: Ok - content: - application/json: - schema: - items: - $ref: '#/components/schemas/Product' - type: array - description: "Get Products describing APIs that will appear on the API Directory\n> `Required Scope:` Namespace.Manage" - summary: 'Get Products' - tags: - - Products - security: - - - jwt: - - Namespace.Manage - parameters: [] - '/gateways/{gatewayId}/products/{appId}': - delete: - operationId: delete-product - responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/BatchResult' - description: "Delete a Product\n> `Required Scope:` Namespace.Manage" - summary: 'Manage Products' - tags: - - Products - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: path - name: appId - required: true - schema: - type: string - '/gateways/{gatewayId}/environments/{appId}': - delete: - operationId: delete-product-environment - responses: - '204': - description: 'No content' - description: "Delete a Product Environment\n> `Required Scope:` Namespace.Manage" - summary: 'Delete a Product Environment' - tags: - - Products - security: - - - jwt: - - Namespace.Manage - parameters: - - - in: path - name: gatewayId - required: true - schema: - type: string - - - in: path - name: appId - required: true - schema: - type: string - - - in: query - name: force - required: false - schema: - default: false - type: boolean -servers: - - - url: /ds/api/v3 -tags: - - - name: 'API Directory' - description: 'Discover all the great BC Government APIs' - - - name: 'API Directory (Administration)' - description: 'Administer datasets on the API Directory' - - - name: Organizations - description: 'Manage organizational access control' - - - name: Gateways - description: 'Get aggregated information about gateways' - - - name: 'Gateway Services' - description: 'View your Gateway Service details' - - - name: Products - description: 'Manage your Products and Environments for publishing to the API Directory' - - - name: 'Authorization Profiles' - description: 'Configure the integration to external Identity Providers' diff --git a/src/controllers/v3/routes.ts b/src/controllers/v3/routes.ts deleted file mode 100644 index 3de19b1d6..000000000 --- a/src/controllers/v3/routes.ts +++ /dev/null @@ -1,1726 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { Controller, ValidationService, FieldErrors, ValidateError, TsoaRoute, HttpStatusCodeLiteral, TsoaResponse } from '@tsoa/runtime'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { OrgDatasetController } from './OrgDatasetController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { DirectoryController } from './DirectoryController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { DatasetController } from './DatasetController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { EndpointsController } from './EndpointsController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { NamespaceController } from './GatewayController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { GatewayDirectoryController } from './GatewayDirectoryController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { GatewayController } from './GatewayServicesController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { IdentifiersController } from './IdentifierController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { IssuerController } from './IssuerController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { OrganizationController } from './OrganizationController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { OrgRoleController } from './OrgRoleController'; -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -import { ProductController } from './ProductController'; -import { expressAuthentication } from './../../auth/auth-tsoa'; -// @ts-ignore - no great way to install types from subpackage -const promiseAny = require('promise.any'); -import { iocContainer } from './../ioc'; -import { IocContainer, IocContainerFactory } from '@tsoa/runtime'; -import * as express from 'express'; -const multer = require('multer'); -const upload = multer(); - -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - -const models: TsoaRoute.Models = { - "DatasetContact": { - "dataType": "refObject", - "properties": { - "name": {"dataType":"string"}, - "email": {"dataType":"string"}, - "role": {"dataType":"enum","enums":["pointOfContact"]}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "DatasetResource": { - "dataType": "refObject", - "properties": { - "id": {"dataType":"string"}, - "name": {"dataType":"string"}, - "format": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["openapi-json"]},{"dataType":"enum","enums":["json"]}]}, - "url": {"dataType":"string"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "OrganizationRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "OrganizationUnitRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "Dataset": { - "dataType": "refObject", - "properties": { - "extForeignKey": {"dataType":"string"}, - "name": {"dataType":"string"}, - "license_title": {"dataType":"string"}, - "security_class": {"dataType":"string"}, - "view_audience": {"dataType":"string"}, - "download_audience": {"dataType":"string"}, - "record_publish_date": {"dataType":"string"}, - "notes": {"dataType":"string"}, - "title": {"dataType":"string"}, - "isInCatalog": {"dataType":"string"}, - "isDraft": {"dataType":"string"}, - "contacts": {"dataType":"array","array":{"dataType":"refObject","ref":"DatasetContact"}}, - "resources": {"dataType":"array","array":{"dataType":"refObject","ref":"DatasetResource"}}, - "extSource": {"dataType":"string"}, - "extRecordHash": {"dataType":"string"}, - "tags": {"dataType":"array","array":{"dataType":"string"}}, - "organization": {"ref":"OrganizationRefID"}, - "organizationUnit": {"ref":"OrganizationUnitRefID"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "BatchResult": { - "dataType": "refObject", - "properties": { - "status": {"dataType":"double","required":true}, - "result": {"dataType":"string","required":true}, - "reason": {"dataType":"string"}, - "id": {"dataType":"string"}, - "ownedBy": {"dataType":"string"}, - "childResults": {"dataType":"array","array":{"dataType":"refObject","ref":"BatchResult"}}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "DraftDataset": { - "dataType": "refObject", - "properties": { - "name": {"dataType":"string"}, - "license_title": {"dataType":"string"}, - "security_class": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["HIGH-CABINET"]},{"dataType":"enum","enums":["HIGH-CONFIDENTIAL"]},{"dataType":"enum","enums":["HIGH-SENSITIVITY"]},{"dataType":"enum","enums":["MEDIUM-SENSITIVITY"]},{"dataType":"enum","enums":["MEDIUM-PERSONAL"]},{"dataType":"enum","enums":["LOW-SENSITIVITY"]},{"dataType":"enum","enums":["LOW-PUBLIC"]},{"dataType":"enum","enums":["PUBLIC"]},{"dataType":"enum","enums":["PROTECTED A"]},{"dataType":"enum","enums":["PROTECTED B"]},{"dataType":"enum","enums":["PROTECTED C"]}]}, - "view_audience": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["Public"]},{"dataType":"enum","enums":["Government"]},{"dataType":"enum","enums":["Named users"]},{"dataType":"enum","enums":["Government and Business BCeID"]}]}, - "download_audience": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["Public"]},{"dataType":"enum","enums":["Government"]},{"dataType":"enum","enums":["Named users"]},{"dataType":"enum","enums":["Government and Business BCeID"]}]}, - "record_publish_date": {"dataType":"string"}, - "notes": {"dataType":"string"}, - "title": {"dataType":"string"}, - "isInCatalog": {"dataType":"boolean"}, - "isDraft": {"dataType":"boolean"}, - "contacts": {"dataType":"array","array":{"dataType":"refObject","ref":"DatasetContact"}}, - "resources": {"dataType":"array","array":{"dataType":"refObject","ref":"DatasetResource"}}, - "tags": {"dataType":"array","array":{"dataType":"string"}}, - "organization": {"ref":"OrganizationRefID"}, - "organizationUnit": {"ref":"OrganizationUnitRefID"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "Gateway": { - "dataType": "refObject", - "properties": { - "gatewayId": {"dataType":"string"}, - "displayName": {"dataType":"string"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "ActivityDetail": { - "dataType": "refObject", - "properties": { - "id": {"dataType":"string"}, - "message": {"dataType":"string","required":true}, - "params": {"dataType":"nestedObjectLiteral","nestedProperties":{},"additionalProperties":{"dataType":"string"},"required":true}, - "activityAt": {"dataType":"any","required":true}, - "blob": {"dataType":"any"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "PublishResult": { - "dataType": "refObject", - "properties": { - "message": {"dataType":"string"}, - "results": {"dataType":"string"}, - "error": {"dataType":"string"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GatewayServiceRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GatewayRouteRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GatewayPlugin": { - "dataType": "refObject", - "properties": { - "extForeignKey": {"dataType":"string"}, - "name": {"dataType":"string"}, - "extSource": {"dataType":"string"}, - "extRecordHash": {"dataType":"string"}, - "tags": {"dataType":"array","array":{"dataType":"string"}}, - "config": {"dataType":"any"}, - "service": {"ref":"GatewayServiceRefID"}, - "route": {"ref":"GatewayRouteRefID"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GatewayRoute": { - "dataType": "refObject", - "properties": { - "extForeignKey": {"dataType":"string"}, - "name": {"dataType":"string"}, - "gatewayId": {"dataType":"string"}, - "extSource": {"dataType":"string"}, - "extRecordHash": {"dataType":"string"}, - "tags": {"dataType":"array","array":{"dataType":"string"}}, - "methods": {"dataType":"array","array":{"dataType":"string"}}, - "paths": {"dataType":"array","array":{"dataType":"string"}}, - "hosts": {"dataType":"array","array":{"dataType":"string"}}, - "service": {"ref":"GatewayServiceRefID"}, - "plugins": {"dataType":"array","array":{"dataType":"refObject","ref":"GatewayPlugin"}}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "IssuerEnvironmentConfig": { - "dataType": "refObject", - "properties": { - "environment": {"dataType":"string"}, - "exists": {"dataType":"boolean"}, - "issuerUrl": {"dataType":"string"}, - "clientRegistration": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["anonymous"]},{"dataType":"enum","enums":["managed"]},{"dataType":"enum","enums":["iat"]}]}, - "clientId": {"dataType":"string"}, - "clientSecret": {"dataType":"string"}, - "initialAccessToken": {"dataType":"string"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "undefinedRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "CredentialIssuer": { - "dataType": "refObject", - "properties": { - "name": {"dataType":"string"}, - "gatewayId": {"dataType":"string"}, - "description": {"dataType":"string"}, - "flow": {"dataType":"enum","enums":["client-credentials"]}, - "mode": {"dataType":"enum","enums":["auto"]}, - "authPlugin": {"dataType":"string"}, - "clientAuthenticator": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["client-secret"]},{"dataType":"enum","enums":["client-jwt"]},{"dataType":"enum","enums":["client-jwt-jwks-url"]}]}, - "instruction": {"dataType":"string"}, - "environmentDetails": {"dataType":"array","array":{"dataType":"refObject","ref":"IssuerEnvironmentConfig"}}, - "resourceType": {"dataType":"string"}, - "resourceAccessScope": {"dataType":"string"}, - "isShared": {"dataType":"boolean"}, - "apiKeyName": {"dataType":"string"}, - "availableScopes": {"dataType":"array","array":{"dataType":"string"}}, - "resourceScopes": {"dataType":"array","array":{"dataType":"string"}}, - "clientRoles": {"dataType":"array","array":{"dataType":"string"}}, - "clientMappers": {"dataType":"array","array":{"dataType":"string"}}, - "inheritFrom": {"ref":"undefinedRefID"}, - "owner": {"ref":"undefinedRefID"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "OrganizationUnit": { - "dataType": "refObject", - "properties": { - "extForeignKey": {"dataType":"string"}, - "name": {"dataType":"string"}, - "sector": {"dataType":"string"}, - "title": {"dataType":"string"}, - "description": {"dataType":"string"}, - "extSource": {"dataType":"string"}, - "extRecordHash": {"dataType":"string"}, - "tags": {"dataType":"array","array":{"dataType":"string"}}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "Organization": { - "dataType": "refObject", - "properties": { - "extForeignKey": {"dataType":"string"}, - "name": {"dataType":"string"}, - "sector": {"dataType":"string"}, - "title": {"dataType":"string"}, - "description": {"dataType":"string"}, - "extSource": {"dataType":"string"}, - "extRecordHash": {"dataType":"string"}, - "tags": {"dataType":"array","array":{"dataType":"string"}}, - "orgUnits": {"dataType":"array","array":{"dataType":"refObject","ref":"OrganizationUnit"}}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GroupPermission": { - "dataType": "refObject", - "properties": { - "resource": {"dataType":"string"}, - "scopes": {"dataType":"array","array":{"dataType":"string"},"required":true}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GroupRole": { - "dataType": "refObject", - "properties": { - "name": {"dataType":"string","required":true}, - "permissions": {"dataType":"array","array":{"dataType":"refObject","ref":"GroupPermission"},"required":true}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GroupAccess": { - "dataType": "refObject", - "properties": { - "name": {"dataType":"string"}, - "parent": {"dataType":"string"}, - "roles": {"dataType":"array","array":{"dataType":"refObject","ref":"GroupRole"},"required":true}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "UserReference": { - "dataType": "refObject", - "properties": { - "id": {"dataType":"string"}, - "email": {"dataType":"string"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GroupMember": { - "dataType": "refObject", - "properties": { - "member": {"ref":"UserReference","required":true}, - "roles": {"dataType":"array","array":{"dataType":"string"},"required":true}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "GroupMembership": { - "dataType": "refObject", - "properties": { - "name": {"dataType":"string"}, - "parent": {"dataType":"string"}, - "members": {"dataType":"array","array":{"dataType":"refObject","ref":"GroupMember"}}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "OrgNamespace": { - "dataType": "refObject", - "properties": { - "name": {"dataType":"string","required":true}, - "orgUnit": {"dataType":"string","required":true}, - "enabled": {"dataType":"boolean","required":true}, - "updatedAt": {"dataType":"double","required":true}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "DraftDatasetRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "LegalRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "CredentialIssuerRefID": { - "dataType": "refAlias", - "type": {"dataType":"string","validators":{}}, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "Environment": { - "dataType": "refObject", - "properties": { - "appId": {"dataType":"string"}, - "name": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["dev"]},{"dataType":"enum","enums":["test"]},{"dataType":"enum","enums":["prod"]},{"dataType":"enum","enums":["sandbox"]},{"dataType":"enum","enums":["other"]}]}, - "active": {"dataType":"boolean"}, - "approval": {"dataType":"boolean"}, - "flow": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["public"]},{"dataType":"enum","enums":["protected-externally"]},{"dataType":"enum","enums":["authorization-code"]},{"dataType":"enum","enums":["client-credentials"]},{"dataType":"enum","enums":["kong-acl-only"]},{"dataType":"enum","enums":["kong-api-key-only"]},{"dataType":"enum","enums":["kong-api-key-acl"]}]}, - "additionalDetailsToRequest": {"dataType":"string"}, - "services": {"dataType":"array","array":{"dataType":"refAlias","ref":"GatewayServiceRefID"}}, - "legal": {"ref":"LegalRefID"}, - "credentialIssuer": {"ref":"CredentialIssuerRefID"}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - "Product": { - "dataType": "refObject", - "properties": { - "appId": {"dataType":"string"}, - "name": {"dataType":"string"}, - "description": {"dataType":"string"}, - "gatewayId": {"dataType":"string"}, - "dataset": {"ref":"DraftDatasetRefID"}, - "environments": {"dataType":"array","array":{"dataType":"refObject","ref":"Environment"}}, - }, - "additionalProperties": false, - }, - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -}; -const validationService = new ValidationService(models); - -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - -export function RegisterRoutes(app: express.Router) { - // ########################################################################################################### - // NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look - // Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa - // ########################################################################################################### - app.get('/ds/api/v3/organizations/:org/datasets', - authenticateMiddleware([{"jwt":["Dataset.Manage"]}]), - - async function OrgDatasetController_getDatasets(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrgDatasetController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getDatasets.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/organizations/:org/datasets', - authenticateMiddleware([{"jwt":["Dataset.Manage"]}]), - - async function OrgDatasetController_putDataset(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - body: {"in":"body","name":"body","required":true,"ref":"DraftDataset"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrgDatasetController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.putDataset.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.delete('/ds/api/v3/organizations/:org/datasets/:name', - authenticateMiddleware([{"jwt":["Dataset.Manage"]}]), - - async function OrgDatasetController_delete(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - name: {"in":"path","name":"name","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrgDatasetController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.delete.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/organizations/:org/datasets/:name', - authenticateMiddleware([{"jwt":["Dataset.Manage"]}]), - - async function OrgDatasetController_getDataset(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - name: {"in":"path","name":"name","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrgDatasetController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getDataset.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/directory', - - async function DirectoryController_list(request: any, response: any, next: any) { - const args = { - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(DirectoryController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.list.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/directory/:id', - - async function DirectoryController_get(request: any, response: any, next: any) { - const args = { - id: {"in":"path","name":"id","required":true,"dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(DirectoryController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.get.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/gateways/:gatewayId/datasets', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function DatasetController_put(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - body: {"in":"body","name":"body","required":true,"ref":"DraftDataset"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(DatasetController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.put.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/datasets/:name', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function DatasetController_getDataset(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - name: {"in":"path","name":"name","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(DatasetController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getDataset.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/routes/availability', - - async function EndpointsController_check(request: any, response: any, next: any) { - const args = { - serviceName: {"in":"query","name":"serviceName","required":true,"dataType":"string"}, - gatewayId: {"in":"query","name":"gatewayId","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(EndpointsController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.check.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/report', - authenticateMiddleware([{"jwt":[]}]), - - async function NamespaceController_report(request: any, response: any, next: any) { - const args = { - req: {"in":"request","name":"req","required":true,"dataType":"object"}, - ids: {"default":"[]","in":"query","name":"ids","dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(NamespaceController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.report.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways', - authenticateMiddleware([{"jwt":[]}]), - - async function NamespaceController_list(request: any, response: any, next: any) { - const args = { - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(NamespaceController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.list.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function NamespaceController_profile(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(NamespaceController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.profile.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.post('/ds/api/v3/gateways', - authenticateMiddleware([{"jwt":[]}]), - - async function NamespaceController_create(request: any, response: any, next: any) { - const args = { - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - vars: {"in":"body","name":"vars","required":true,"ref":"Gateway"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(NamespaceController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.create.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.delete('/ds/api/v3/gateways/:gatewayId', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function NamespaceController_delete(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - force: {"default":false,"in":"query","name":"force","dataType":"boolean"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(NamespaceController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.delete.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/activity', - authenticateMiddleware([{"jwt":["Namespace.View"]}]), - - async function NamespaceController_namespaceActivity(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - first: {"default":20,"in":"query","name":"first","dataType":"double"}, - skip: {"default":0,"in":"query","name":"skip","dataType":"double"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(NamespaceController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.namespaceActivity.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/links', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function NamespaceController_get(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(NamespaceController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.get.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/directory/:id', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function GatewayDirectoryController_getDataset(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - id: {"in":"path","name":"id","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(GatewayDirectoryController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getDataset.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/directory', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function GatewayDirectoryController_getDatasets(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(GatewayDirectoryController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getDatasets.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/gateways/:gatewayId/services', - authenticateMiddleware([{"jwt":["Gateway.Config"]}]), - upload.single('configFile'), - - async function GatewayController_put(request: any, response: any, next: any) { - const args = { - dryRun: {"in":"formData","name":"dryRun","required":true,"dataType":"string"}, - configFile: {"in":"formData","name":"configFile","required":true,"dataType":"file"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(GatewayController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.put.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/services', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function GatewayController_getServices(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(GatewayController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getServices.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/identifiers/:type', - - async function IdentifiersController_getNewID(request: any, response: any, next: any) { - const args = { - type: {"in":"path","name":"type","required":true,"dataType":"union","subSchemas":[{"dataType":"enum","enums":["environment"]},{"dataType":"enum","enums":["product"]},{"dataType":"enum","enums":["application"]},{"dataType":"enum","enums":["gateway"]}]}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(IdentifiersController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getNewID.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/gateways/:gatewayId/issuers', - authenticateMiddleware([{"jwt":["CredentialIssuer.Admin"]}]), - - async function IssuerController_put(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - body: {"in":"body","name":"body","required":true,"ref":"CredentialIssuer"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(IssuerController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.put.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/issuers', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function IssuerController_get(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(IssuerController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.get.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.delete('/ds/api/v3/gateways/:gatewayId/issuers/:name', - authenticateMiddleware([{"jwt":["CredentialIssuer.Admin"]}]), - - async function IssuerController_delete(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - name: {"in":"path","name":"name","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(IssuerController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.delete.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/organizations', - - async function OrganizationController_listOrganizations(request: any, response: any, next: any) { - const args = { - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.listOrganizations.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/organizations/:org', - authenticateMiddleware([{"jwt":["GroupAccess.Manage"]}]), - - async function OrganizationController_post(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - body: {"in":"body","name":"body","required":true,"ref":"Organization"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.post.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/organizations/:org', - - async function OrganizationController_listOrganizationUnits(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.listOrganizationUnits.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/organizations/:org/roles', - authenticateMiddleware([{"jwt":["GroupAccess.Manage"]}]), - - async function OrganizationController_getPolicies(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getPolicies.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/organizations/:org/access', - authenticateMiddleware([{"jwt":["GroupAccess.Manage"]}]), - - async function OrganizationController_get(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.get.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/organizations/:org/access', - authenticateMiddleware([{"jwt":["GroupAccess.Manage"]}]), - - async function OrganizationController_put(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - body: {"in":"body","name":"body","required":true,"ref":"GroupMembership"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.put.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/organizations/:org/gateways', - authenticateMiddleware([{"jwt":["Namespace.Assign"]}]), - - async function OrganizationController_listNamespaces(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.listNamespaces.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/organizations/:org/:orgUnit/gateways/:gatewayId', - authenticateMiddleware([{"jwt":["Namespace.Assign"]}]), - - async function OrganizationController_assignNamespace(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - orgUnit: {"in":"path","name":"orgUnit","required":true,"dataType":"string"}, - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - enable: {"default":true,"in":"query","name":"enable","dataType":"boolean"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.assignNamespace.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.delete('/ds/api/v3/organizations/:org/:orgUnit/gateways/:gatewayId', - authenticateMiddleware([{"jwt":["Namespace.Assign"]}]), - - async function OrganizationController_unassignNamespace(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - orgUnit: {"in":"path","name":"orgUnit","required":true,"dataType":"string"}, - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.unassignNamespace.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/organizations/:org/activity', - authenticateMiddleware([{"jwt":["Namespace.Assign"]}]), - - async function OrganizationController_namespaceActivity(request: any, response: any, next: any) { - const args = { - org: {"in":"path","name":"org","required":true,"dataType":"string"}, - first: {"default":20,"in":"query","name":"first","dataType":"double"}, - skip: {"default":0,"in":"query","name":"skip","dataType":"double"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrganizationController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.namespaceActivity.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/roles', - - async function OrgRoleController_getRoles(request: any, response: any, next: any) { - const args = { - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(OrgRoleController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.getRoles.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.put('/ds/api/v3/gateways/:gatewayId/products', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function ProductController_put(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - body: {"in":"body","name":"body","required":true,"ref":"Product"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(ProductController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.put.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.get('/ds/api/v3/gateways/:gatewayId/products', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function ProductController_get(request: any, response: any, next: any) { - const args = { - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(ProductController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.get.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.delete('/ds/api/v3/gateways/:gatewayId/products/:appId', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function ProductController_delete(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - appId: {"in":"path","name":"appId","required":true,"dataType":"string"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(ProductController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.delete.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - app.delete('/ds/api/v3/gateways/:gatewayId/environments/:appId', - authenticateMiddleware([{"jwt":["Namespace.Manage"]}]), - - async function ProductController_deleteEnvironment(request: any, response: any, next: any) { - const args = { - gatewayId: {"in":"path","name":"gatewayId","required":true,"dataType":"string"}, - appId: {"in":"path","name":"appId","required":true,"dataType":"string"}, - force: {"default":false,"in":"query","name":"force","dataType":"boolean"}, - request: {"in":"request","name":"request","required":true,"dataType":"object"}, - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - let validatedArgs: any[] = []; - try { - validatedArgs = getValidatedArgs(args, request, response); - - const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer; - - const controller: any = await container.get(ProductController); - if (typeof controller['setStatus'] === 'function') { - controller.setStatus(undefined); - } - - - const promise = controller.deleteEnvironment.apply(controller, validatedArgs as any); - promiseHandler(controller, promise, response, undefined, next); - } catch (err) { - return next(err); - } - }); - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - function authenticateMiddleware(security: TsoaRoute.Security[] = []) { - return async function runAuthenticationMiddleware(request: any, _response: any, next: any) { - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - // keep track of failed auth attempts so we can hand back the most - // recent one. This behavior was previously existing so preserving it - // here - const failedAttempts: any[] = []; - const pushAndRethrow = (error: any) => { - failedAttempts.push(error); - throw error; - }; - - const secMethodOrPromises: Promise[] = []; - for (const secMethod of security) { - if (Object.keys(secMethod).length > 1) { - const secMethodAndPromises: Promise[] = []; - - for (const name in secMethod) { - secMethodAndPromises.push( - expressAuthentication(request, name, secMethod[name]) - .catch(pushAndRethrow) - ); - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - secMethodOrPromises.push(Promise.all(secMethodAndPromises) - .then(users => { return users[0]; })); - } else { - for (const name in secMethod) { - secMethodOrPromises.push( - expressAuthentication(request, name, secMethod[name]) - .catch(pushAndRethrow) - ); - } - } - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - try { - request['user'] = await promiseAny(secMethodOrPromises); - next(); - } - catch(err) { - // Show most recent error as response - const error = failedAttempts.pop(); - error.status = error.status || 401; - next(error); - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - } - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - function isController(object: any): object is Controller { - return 'getHeaders' in object && 'getStatus' in object && 'setStatus' in object; - } - - function promiseHandler(controllerObj: any, promise: any, response: any, successStatus: any, next: any) { - return Promise.resolve(promise) - .then((data: any) => { - let statusCode = successStatus; - let headers; - if (isController(controllerObj)) { - headers = controllerObj.getHeaders(); - statusCode = controllerObj.getStatus() || statusCode; - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - returnHandler(response, statusCode, data, headers) - }) - .catch((error: any) => next(error)); - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - function returnHandler(response: any, statusCode?: number, data?: any, headers: any = {}) { - if (response.headersSent) { - return; - } - Object.keys(headers).forEach((name: string) => { - response.set(name, headers[name]); - }); - if (data && typeof data.pipe === 'function' && data.readable && typeof data._read === 'function') { - data.pipe(response); - } else if (data !== null && data !== undefined) { - response.status(statusCode || 200).json(data); - } else { - response.status(statusCode || 204).end(); - } - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - function responder(response: any): TsoaResponse { - return function(status, data, headers) { - returnHandler(response, status, data, headers); - }; - }; - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa - - function getValidatedArgs(args: any, request: any, response: any): any[] { - const fieldErrors: FieldErrors = {}; - const values = Object.keys(args).map((key) => { - const name = args[key].name; - switch (args[key].in) { - case 'request': - return request; - case 'query': - return validationService.ValidateParam(args[key], request.query[name], name, fieldErrors, undefined, {"noImplicitAdditionalProperties":"throw-on-extras"}); - case 'path': - return validationService.ValidateParam(args[key], request.params[name], name, fieldErrors, undefined, {"noImplicitAdditionalProperties":"throw-on-extras"}); - case 'header': - return validationService.ValidateParam(args[key], request.header(name), name, fieldErrors, undefined, {"noImplicitAdditionalProperties":"throw-on-extras"}); - case 'body': - return validationService.ValidateParam(args[key], request.body, name, fieldErrors, undefined, {"noImplicitAdditionalProperties":"throw-on-extras"}); - case 'body-prop': - return validationService.ValidateParam(args[key], request.body[name], name, fieldErrors, 'body.', {"noImplicitAdditionalProperties":"throw-on-extras"}); - case 'formData': - if (args[key].dataType === 'file') { - return validationService.ValidateParam(args[key], request.file, name, fieldErrors, undefined, {"noImplicitAdditionalProperties":"throw-on-extras"}); - } else if (args[key].dataType === 'array' && args[key].array.dataType === 'file') { - return validationService.ValidateParam(args[key], request.files, name, fieldErrors, undefined, {"noImplicitAdditionalProperties":"throw-on-extras"}); - } else { - return validationService.ValidateParam(args[key], request.body[name], name, fieldErrors, undefined, {"noImplicitAdditionalProperties":"throw-on-extras"}); - } - case 'res': - return responder(response); - } - }); - - if (Object.keys(fieldErrors).length > 0) { - throw new ValidateError(fieldErrors, ''); - } - return values; - } - - // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa -} - -// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa From 3c4c009c4db74e44475bf3c9a9721dc840542aa7 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 20 Dec 2024 08:02:46 -0800 Subject: [PATCH 12/37] Update Node.js engine requirement in package.json to support versions 22.x --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 8d04ff94f..14d3343ef 100644 --- a/src/package.json +++ b/src/package.json @@ -8,7 +8,7 @@ "homepage": "https://github.com/keystonejs/keystone", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=22.0.0 <23.0.0" }, "main": "dist/server.js", "nodemonConfig": { From e964a72059722ff5a11c832442a226ff0a0130b1 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 20 Dec 2024 12:29:35 -0800 Subject: [PATCH 13/37] Avoid socket hangup: enhance Keycloak auth in group service with retry logic; improve error handling in namespace service login --- src/services/keycloak/group-service.ts | 57 ++++++++++++++++++++------ src/services/org-groups/namespace.ts | 7 +++- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/services/keycloak/group-service.ts b/src/services/keycloak/group-service.ts index 45a72b7ca..d6c23c896 100644 --- a/src/services/keycloak/group-service.ts +++ b/src/services/keycloak/group-service.ts @@ -15,6 +15,10 @@ const logger = Logger('kc.group'); export class KeycloakGroupService { private allGroups: any = undefined; private kcAdminClient: KeycloakAdminClient; + private clientId: string; + private clientSecret: string; + private lastAuthTime: number = 0; + private readonly AUTH_TIMEOUT = 280 * 1000; // 280 seconds (slightly less than typical 5 min token lifetime) constructor(issuerUrl: string) { const baseUrl = issuerUrl.substr(0, issuerUrl.indexOf('/realms')); @@ -23,26 +27,52 @@ export class KeycloakGroupService { this.kcAdminClient = new KcAdminClient({ baseUrl, realmName }); } + private async ensureAuthenticated(): Promise { + if (this.clientId && (Date.now() - this.lastAuthTime > this.AUTH_TIMEOUT)) { + logger.debug('[ensureAuthenticated] Re-authenticating due to timeout'); + await this.login(this.clientId, this.clientSecret); + } + } + public async cacheGroups() { this.allGroups = await this.getAllGroups(); } public async login( clientId: string, - clientSecret: string + clientSecret: string, + retryAttempts: number = 3 ): Promise { - logger.debug('[login] %s', clientId); - - await this.kcAdminClient - .auth({ - grantType: 'client_credentials', - clientId: clientId, - clientSecret: clientSecret, - }) - .catch((err: any) => { - logger.error('[login] Login failed %s', err); - throw err; - }); + this.clientId = clientId; + this.clientSecret = clientSecret; + + const result = await this._login(retryAttempts); + this.lastAuthTime = Date.now(); + return result; + } + + private async _login(retryAttempts: number): Promise { + logger.debug('[login] %s', this.clientId); + + for (let attempt = 1; attempt <= retryAttempts; attempt++) { + try { + await this.kcAdminClient + .auth({ + grantType: 'client_credentials', + clientId: this.clientId, + clientSecret: this.clientSecret, + }); + return this; + } catch (err: any) { + if (attempt === retryAttempts) { + logger.error('[login] Login failed after %d attempts: %s', retryAttempts, err); + throw err; + } + logger.warn('[login] Attempt %d failed, retrying: %s', attempt, err); + // Add exponential backoff + await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100)); + } + } return this; } @@ -70,6 +100,7 @@ export class KeycloakGroupService { } public async updateGroup(group: GroupRepresentation): Promise { + await this.ensureAuthenticated(); logger.debug('[updateGroup] %j', group); await this.kcAdminClient.groups.update({ id: group.id }, group); } diff --git a/src/services/org-groups/namespace.ts b/src/services/org-groups/namespace.ts index ef321f51f..42c26f77a 100644 --- a/src/services/org-groups/namespace.ts +++ b/src/services/org-groups/namespace.ts @@ -13,7 +13,12 @@ export class NamespaceService { } async login(clientId: string, clientSecret: string) { - await this.groupService.login(clientId, clientSecret); + try { + await this.groupService.login(clientId, clientSecret); + } catch (err) { + logger.error('[login] Failed to login to Keycloak: %s', err); + throw new Error('Failed to authenticate with Keycloak'); + } } async markNotification(ns: string, viewed: boolean): Promise { From afea353cf82efb2d07484d71f5842582398787b3 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 20 Dec 2024 15:16:56 -0800 Subject: [PATCH 14/37] Enhance Cypress E2E test logging in GitHub Actions workflow; added current test progress --- .github/workflows/aps-cypress-e2e.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index aaef58651..ac811a32d 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -53,8 +53,16 @@ jobs: docker compose down break else - echo "Waiting for Cypress to Complete E2E Tests....." - sleep 1m + echo "Current Test Progress:" + docker logs cypress-e2e 2>&1 | grep -E "Running:|✓|×" | tail -n 5 + + # Get failure count from the most recent logs + FAILURES=$(docker logs cypress-e2e 2>&1 | grep -c "×" || true) + if [ $FAILURES -gt 0 ]; then + echo "❌ Current failure count: $FAILURES" + fi + + sleep 30s fi done From 3075f0913b5193b6358682b026499f70077f9b1f Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 20 Dec 2024 16:28:17 -0800 Subject: [PATCH 15/37] bump cli version in tests --- e2e/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 2a093d736..74f6b878b 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -22,7 +22,7 @@ COPY e2e/*.yml /e2e COPY e2e/entrypoint.sh /tmp ADD e2e/cypress /e2e/cypress -RUN curl -v -L -O https://github.com/bcgov/gwa-cli/releases/download/v3.0.4/gwa_Linux_x86_64.tgz \ +RUN curl -v -L -O https://github.com/bcgov/gwa-cli/releases/download/v3.0.5/gwa_Linux_x86_64.tgz \ && tar -xzf gwa_Linux_x86_64.tgz \ && mv gwa /usr/local/bin/. From f472539c0761b4cd336d060ddce4871c643a3be9 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 24 Dec 2024 08:17:46 -0800 Subject: [PATCH 16/37] modify show cypress progress --- .github/workflows/aps-cypress-e2e.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index ac811a32d..d4d76d6db 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -54,10 +54,11 @@ jobs: break else echo "Current Test Progress:" - docker logs cypress-e2e 2>&1 | grep -E "Running:|✓|×" | tail -n 5 + docker logs cypress-e2e 2>&1 | grep -E "Running:|✓|^[0-9]+\)" | tail -n 5 # Get failure count from the most recent logs - FAILURES=$(docker logs cypress-e2e 2>&1 | grep -c "×" || true) + # Count lines starting with a number followed by ')' + FAILURES=$(docker logs cypress-e2e 2>&1 | grep -c "^[0-9]\+)" || true) if [ $FAILURES -gt 0 ]; then echo "❌ Current failure count: $FAILURES" fi From 5b049957f32181466cdecbfdaba52435425f5bc3 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 24 Dec 2024 14:16:02 -0800 Subject: [PATCH 17/37] peg ubuntu version for GHA runner, stream all cypress logs --- .github/workflows/aps-cypress-e2e.yaml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index d4d76d6db..517aab511 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -17,7 +17,7 @@ env: jobs: cypress-run: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Build GWA API Image run: | @@ -47,22 +47,19 @@ jobs: - name: Execute Tests & Clean Up run: | + # Start following logs in the background with continuous output + docker logs -f cypress-e2e 2>&1 & + LOG_PID=$! + while true; do if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then + echo "Cypress tests completed." + # Kill the log following process + kill $LOG_PID # cleanup docker compose down break else - echo "Current Test Progress:" - docker logs cypress-e2e 2>&1 | grep -E "Running:|✓|^[0-9]+\)" | tail -n 5 - - # Get failure count from the most recent logs - # Count lines starting with a number followed by ')' - FAILURES=$(docker logs cypress-e2e 2>&1 | grep -c "^[0-9]\+)" || true) - if [ $FAILURES -gt 0 ]; then - echo "❌ Current failure count: $FAILURES" - fi - sleep 30s fi done From 00bc2d0d2e9b90075c93b4e23de40d447c8703b7 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 31 Dec 2024 11:23:41 -0800 Subject: [PATCH 18/37] use ubuntu-latest, gwa-api v1.0.40 --- .github/workflows/aps-cypress-e2e.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 517aab511..68a8e809f 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -17,11 +17,11 @@ env: jobs: cypress-run: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Build GWA API Image run: | - git clone https://github.com/bcgov/gwa-api.git + git clone https://github.com/bcgov/gwa-api.git --branch v1.0.40 cd gwa-api/microservices/gatewayApi docker build -t gwa-api:e2e . From 1eed10b6ad371e138f004c8cd2ff376d5ed35f7a Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 31 Dec 2024 08:43:03 -0800 Subject: [PATCH 19/37] add data_plane_config for gwa api --- local/gwa-api/.env.local | 1 + local/gwa-api/data_planes_config.json | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 local/gwa-api/data_planes_config.json diff --git a/local/gwa-api/.env.local b/local/gwa-api/.env.local index 7cf8877d2..be995a043 100644 --- a/local/gwa-api/.env.local +++ b/local/gwa-api/.env.local @@ -4,6 +4,7 @@ OIDC_BASE_URL=http://keycloak.localtest.me:9081/auth/realms/master TOKEN_MATCH_AUD=gwa WORKING_FOLDER=/tmp CONFIG_PATH=/tmp/production.json +DATA_PLANES_CONFIG_PATH=/tmp/gwa/data_planes_config.json ENVIRONMENT=production KONG_ADMIN_URL=http://kong.localtest.me:8001 KC_SERVER_URL=http://keycloak.localtest.me:9081/auth/ diff --git a/local/gwa-api/data_planes_config.json b/local/gwa-api/data_planes_config.json new file mode 100644 index 000000000..5015c1c75 --- /dev/null +++ b/local/gwa-api/data_planes_config.json @@ -0,0 +1,9 @@ +{ + "data_planes": { + "local.dataplane": { + "kube-api": "https://api.cloud", + "kube-ns": "xxxxxx-dev", + "validate-upstreams": false + } + } +} \ No newline at end of file From 23932d80d28362b1b2832d3fc01d7c0fb0cb1427 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Thu, 2 Jan 2025 15:07:52 -0800 Subject: [PATCH 20/37] disable migrate user tests --- e2e/cypress.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/cypress.config.ts b/e2e/cypress.config.ts index 43b2102f1..2789d860c 100644 --- a/e2e/cypress.config.ts +++ b/e2e/cypress.config.ts @@ -26,7 +26,7 @@ export default defineConfig({ './cypress/tests/07-*/*.ts', './cypress/tests/03-*/*.ts', './cypress/tests/04-*/*.ts', - './cypress/tests/05-*/*.ts', + // './cypress/tests/05-*/*.ts', './cypress/tests/08-*/*.ts', './cypress/tests/09-*/*.ts', './cypress/tests/10-*/*.ts', @@ -59,7 +59,7 @@ export default defineConfig({ }, chromeWebSecurity: false, env: { - ASTRA_SCAN_ENABLED: true, + ASTRA_SCAN_ENABLED: false, CLIENT_ID: 'aps-portal', CLIENT_SECRET: '8e1a17ed-cb93-4806-ac32-e303d1c86018', OIDC_ISSUER: 'http://keycloak.localtest.me:9081/auth/realms/master', From b95c0a3c7c9d129c29d152ab12f22678f7ff5099 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Thu, 2 Jan 2025 16:17:21 -0800 Subject: [PATCH 21/37] fix error msg for generate-config service validation --- .../tests/16-gwa-cli/02-cli-generate-config-quick-start.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/cypress/tests/16-gwa-cli/02-cli-generate-config-quick-start.ts b/e2e/cypress/tests/16-gwa-cli/02-cli-generate-config-quick-start.ts index 403087a01..b19f5d0aa 100644 --- a/e2e/cypress/tests/16-gwa-cli/02-cli-generate-config-quick-start.ts +++ b/e2e/cypress/tests/16-gwa-cli/02-cli-generate-config-quick-start.ts @@ -103,7 +103,7 @@ describe('Verify CLI commands for generate/apply config', () => { cy.executeCliCommand('gwa gateway create --generate').then((response) => { const namespace = response.stdout.match(/\bgw-\w+/g)[0] cy.executeCliCommand(command).then((response) => { - expect(response.stderr).to.contain(`Error: Service ${serviceName} is already in use. Suggestion: ${namespace}-${serviceName}`) + expect(response.stderr).to.contain(`Error: Checking service availability: Service ${serviceName} is already in use. Suggestion: ${namespace}-${serviceName}`) }); }); }) From dab5b6d343988c58c006cdc3cad671c4e128c0ff Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 3 Jan 2025 09:44:34 -0800 Subject: [PATCH 22/37] Change regex validation in utils.ts to use assert.ok --- src/services/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/utils.ts b/src/services/utils.ts index 7bcfb87d4..427cd4a57 100644 --- a/src/services/utils.ts +++ b/src/services/utils.ts @@ -58,7 +58,7 @@ export function regExprValidation( errorMessage: string ) { const re = new RegExp(rule); - assert.strictEqual(re.test(value), true, errorMessage); + assert.ok(re.test(value), errorMessage); } export async function fetchWithTimeout(resource: string, options: any = {}) { From ebf6f2bb78b5beb8eacba9cc143817f3694d3b0d Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 3 Jan 2025 10:02:47 -0800 Subject: [PATCH 23/37] Update error message for Gateway ID validation --- e2e/cypress/tests/19-api-v3/03-gateways.ts | 2 +- src/lists/extensions/Namespace.ts | 2 +- src/services/keycloak/namespace-details.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/cypress/tests/19-api-v3/03-gateways.ts b/e2e/cypress/tests/19-api-v3/03-gateways.ts index 09db841b3..a3620c29a 100644 --- a/e2e/cypress/tests/19-api-v3/03-gateways.ts +++ b/e2e/cypress/tests/19-api-v3/03-gateways.ts @@ -188,7 +188,7 @@ describe('Gateways', () => { details: { d0: { message: - 'Namespace name must be between 5 and 15 alpha-numeric lowercase characters and start and end with an alphabet.', + 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start and end with a letter.', }, }, } diff --git a/src/lists/extensions/Namespace.ts b/src/lists/extensions/Namespace.ts index 85b5565a7..773e9d294 100644 --- a/src/lists/extensions/Namespace.ts +++ b/src/lists/extensions/Namespace.ts @@ -251,7 +251,7 @@ module.exports = { assert.strictEqual( re.test(args.namespace), true, - 'Gateway name must be between 5 and 15 alpha-numeric lowercase characters and begin with an alphabet.' + 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start and end with a letter.' ); const noauthContext = context.createContext({ skipAccessControl: true, diff --git a/src/services/keycloak/namespace-details.ts b/src/services/keycloak/namespace-details.ts index 14cbdd831..021248c2e 100644 --- a/src/services/keycloak/namespace-details.ts +++ b/src/services/keycloak/namespace-details.ts @@ -195,7 +195,7 @@ export function validateNamespaceName(name: string) { regExprValidation( namespaceValidationRule, name, - 'Namespace name must be between 5 and 15 alpha-numeric lowercase characters and start and end with an alphabet.' + 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start and end with a letter.' ); } From 231a4cd7ca427dc13bb8968b2a1b12b058b7f6bb Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 3 Jan 2025 13:56:08 -0800 Subject: [PATCH 24/37] upgrade node-fetch --- src/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/package.json b/src/package.json index 14d3343ef..d238add76 100644 --- a/src/package.json +++ b/src/package.json @@ -110,6 +110,7 @@ "keycloak-connect": "^17.0.1", "lodash": "^4.17.21", "multer": "^1.4.2", + "node-fetch": "^2.7.0", "nodemailer": "^6.6.0", "npmlog": "^6.0.1", "numeral": "^2.0.6", From 406337b47fe02cfb96828b45caea716e86abaff6 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 3 Jan 2025 14:18:22 -0800 Subject: [PATCH 25/37] ensure subsequent steps are run in aps-cypress-e2e GHA --- .github/workflows/aps-cypress-e2e.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 68a8e809f..781b364d5 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -65,18 +65,21 @@ jobs: done - name: Upload E2E Test Results HTML Report + if: always() uses: actions/upload-artifact@v4 with: name: test-results-html path: ${{ github.workspace }}/e2e/results/report - name: Upload E2E Test Results JSON Report + if: always() uses: actions/upload-artifact@v4 with: name: test-results-json path: ${{ github.workspace }}/e2e/results/bcgov-aps-e2e-report.json - name: Upload E2E Code Coverage Report + if: always() uses: actions/upload-artifact@v4 with: name: code-coverage @@ -89,6 +92,7 @@ jobs: path: ${{ github.workspace }}/e2e/cypress/fixtures/state/scanResult.json - name: Instrument the code for coverage analysis + if: always() run: | # Rewrite the paths as the coverage starts with '../app'! sed -e 's/..\/app/./g' ./e2e/coverage/lcov.info > lcov.info @@ -98,6 +102,7 @@ jobs: #npx nyc instrument --compact=false . --in-place - name: SonarCloud Scan + if: always() uses: sonarsource/sonarcloud-github-action@master with: args: > @@ -113,6 +118,7 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - name: Check for failed tests and create Issue + if: always() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | From cb4b85d020a4c153546aa2c900738d12e2ef301b Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 3 Jan 2025 14:19:50 -0800 Subject: [PATCH 26/37] enable astra scan --- e2e/cypress.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/cypress.config.ts b/e2e/cypress.config.ts index 2789d860c..9e9a28add 100644 --- a/e2e/cypress.config.ts +++ b/e2e/cypress.config.ts @@ -59,7 +59,7 @@ export default defineConfig({ }, chromeWebSecurity: false, env: { - ASTRA_SCAN_ENABLED: false, + ASTRA_SCAN_ENABLED: true, CLIENT_ID: 'aps-portal', CLIENT_SECRET: '8e1a17ed-cb93-4806-ac32-e303d1c86018', OIDC_ISSUER: 'http://keycloak.localtest.me:9081/auth/realms/master', From cf0fc043d8be5bfd53e4d2783daf527809d9b684 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 3 Jan 2025 14:27:52 -0800 Subject: [PATCH 27/37] upgrade upload-sarif for trivy, try fixing output path for anchore --- .github/workflows/ci-anchore-img-scan.yaml | 3 ++- .github/workflows/ci-trivy-img-scan.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-anchore-img-scan.yaml b/.github/workflows/ci-anchore-img-scan.yaml index 8c60b6393..0764cf241 100644 --- a/.github/workflows/ci-anchore-img-scan.yaml +++ b/.github/workflows/ci-anchore-img-scan.yaml @@ -17,7 +17,8 @@ jobs: with: image: 'bcgov/api-services-portal:anchore-scan' fail-build: false + output-file: 'anchore-results.sarif' - name: Upload Anchore Scan Results uses: github/codeql-action/upload-sarif@v3 with: - sarif_file: results.sarif + sarif_file: anchore-results.sarif diff --git a/.github/workflows/ci-trivy-img-scan.yaml b/.github/workflows/ci-trivy-img-scan.yaml index bcea8fdba..0a2ced443 100644 --- a/.github/workflows/ci-trivy-img-scan.yaml +++ b/.github/workflows/ci-trivy-img-scan.yaml @@ -24,6 +24,6 @@ jobs: template: '@/contrib/sarif.tpl' output: 'trivy-results.sarif' - name: Upload Trivy Scan Results - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: 'trivy-results.sarif' From 0f1d3563b557e973273a9beee882d615dd7634cc Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Mon, 6 Jan 2025 08:39:23 -0800 Subject: [PATCH 28/37] Refactor GitHub Actions workflow for Cypress E2E tests - Removed redundant log process termination. - Reordered step to create a GitHub issue if failures are detected. - Updated the SonarCloud scan action to use the latest SonarQube GitHub action. --- .github/workflows/aps-cypress-e2e.yaml | 52 ++++++++++++-------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index 781b364d5..b6572d0d4 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -54,8 +54,6 @@ jobs: while true; do if [ "$(docker ps -aq -f status=exited -f name=cypress-e2e)" ]; then echo "Cypress tests completed." - # Kill the log following process - kill $LOG_PID # cleanup docker compose down break @@ -90,9 +88,31 @@ jobs: with: name: astra-scan-results path: ${{ github.workspace }}/e2e/cypress/fixtures/state/scanResult.json + + - name: Check for failed tests and create Issue + if: always() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + FAILURE_COUNT=$(cat ${{ github.workspace }}/e2e/results/bcgov-aps-e2e-report.json | jq '.stats.failures') + if [[ "$FAILURE_COUNT" -gt 0 ]]; then + FAILED_TESTS=$(jq -r ' + .results[] | + (.file | split("/") | .[2:] | join("/")) as $file | + .. | + .tests? // empty | + .[] | + select(.fail == true) | + "- " + $file + " - " + .title + ' ${{ github.workspace }}/e2e/results/bcgov-aps-e2e-report.json) + STATS=$(cat ${{ github.workspace }}/e2e/results/bcgov-aps-e2e-report.json | jq -r '.stats | to_entries | map("\(.key)\t\(.value)") | .[]' | column -t) + echo -e "Stats: $STATS\n\nFailed Tests:\n$FAILED_TESTS\n\nRun Link: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" > msg + export MSG=$(cat msg) + gh issue create --title "FAILED: Automated Tests($FAILURE_COUNT)" --body "$MSG" --label "automation" --assignee "${{ env.GIT_COMMIT_AUTHOR }}" + exit 1 + fi - name: Instrument the code for coverage analysis - if: always() run: | # Rewrite the paths as the coverage starts with '../app'! sed -e 's/..\/app/./g' ./e2e/coverage/lcov.info > lcov.info @@ -102,8 +122,7 @@ jobs: #npx nyc instrument --compact=false . --in-place - name: SonarCloud Scan - if: always() - uses: sonarsource/sonarcloud-github-action@master + uses: sonarsource/sonarqube-scan-action@master with: args: > -Dsonar.organization=bcgov-oss @@ -117,29 +136,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - - name: Check for failed tests and create Issue - if: always() - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - FAILURE_COUNT=$(cat ${{ github.workspace }}/e2e/results/bcgov-aps-e2e-report.json | jq '.stats.failures') - if [[ "$FAILURE_COUNT" -gt 0 ]]; then - FAILED_TESTS=$(jq -r ' - .results[] | - (.file | split("/") | .[2:] | join("/")) as $file | - .. | - .tests? // empty | - .[] | - select(.fail == true) | - "- " + $file + " - " + .title - ' ${{ github.workspace }}/e2e/results/bcgov-aps-e2e-report.json) - STATS=$(cat ${{ github.workspace }}/e2e/results/bcgov-aps-e2e-report.json | jq -r '.stats | to_entries | map("\(.key)\t\(.value)") | .[]' | column -t) - echo -e "Stats: $STATS\n\nFailed Tests:\n$FAILED_TESTS\n\nRun Link: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" > msg - export MSG=$(cat msg) - gh issue create --title "FAILED: Automated Tests($FAILURE_COUNT)" --body "$MSG" --label "automation" --assignee "${{ env.GIT_COMMIT_AUTHOR }}" - exit 1 - fi - - name: Set up Python 3.9 if: failure() uses: actions/setup-python@v2 From 47d3f0040cef36197fab451a37882e5c47f2c350 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Mon, 6 Jan 2025 08:44:10 -0800 Subject: [PATCH 29/37] Trigger E2E tests on PRs to `dev` --- .github/workflows/aps-cypress-e2e.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/aps-cypress-e2e.yaml b/.github/workflows/aps-cypress-e2e.yaml index b6572d0d4..5245af7bf 100644 --- a/.github/workflows/aps-cypress-e2e.yaml +++ b/.github/workflows/aps-cypress-e2e.yaml @@ -4,6 +4,8 @@ on: workflow_dispatch: {} push: branches: ['test', 'cypress/*'] + pull_request: + branches: ['dev'] env: DASHBOARD_PROJECT_ID: ${{ secrets.CY_DASHBOARD_PRJ_ID }} From 46e23ade4bb56acec4de00a16bb5b421ae875910 Mon Sep 17 00:00:00 2001 From: James Elson Date: Mon, 6 Jan 2025 13:41:14 -0800 Subject: [PATCH 30/37] Try different redirect to detail page from list page --- src/nextapp/pages/manager/gateways/list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nextapp/pages/manager/gateways/list.tsx b/src/nextapp/pages/manager/gateways/list.tsx index 43edcc43e..cd50c39c5 100644 --- a/src/nextapp/pages/manager/gateways/list.tsx +++ b/src/nextapp/pages/manager/gateways/list.tsx @@ -120,7 +120,7 @@ const MyGatewaysPage: React.FC = () => { status: 'success', isClosable: true, }); - await router.push('/manager/gateways/detail'); + window.location.assign('/manager/gateways/detail'); } catch (err) { toast.closeAll(); toast({ From ed30e1921f9b27d87025e0f759542ef46b4e7faa Mon Sep 17 00:00:00 2001 From: James Elson Date: Mon, 6 Jan 2025 13:59:08 -0800 Subject: [PATCH 31/37] Revert change --- src/nextapp/pages/manager/gateways/list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nextapp/pages/manager/gateways/list.tsx b/src/nextapp/pages/manager/gateways/list.tsx index cd50c39c5..43edcc43e 100644 --- a/src/nextapp/pages/manager/gateways/list.tsx +++ b/src/nextapp/pages/manager/gateways/list.tsx @@ -120,7 +120,7 @@ const MyGatewaysPage: React.FC = () => { status: 'success', isClosable: true, }); - window.location.assign('/manager/gateways/detail'); + await router.push('/manager/gateways/detail'); } catch (err) { toast.closeAll(); toast({ From 5e8d9c0856b1148c2b1b4c72b3548f45b120e79f Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 7 Jan 2025 08:25:12 -0800 Subject: [PATCH 32/37] update sonar scan action in sonar GHA workflow --- .github/workflows/ci-feat-sonar.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-feat-sonar.yaml b/.github/workflows/ci-feat-sonar.yaml index efcf4a03a..6c2644dec 100644 --- a/.github/workflows/ci-feat-sonar.yaml +++ b/.github/workflows/ci-feat-sonar.yaml @@ -42,7 +42,7 @@ jobs: docker compose down - name: SonarCloud Scan - uses: sonarsource/sonarcloud-github-action@master + uses: sonarsource/sonarqube-scan-action@master with: args: > -Dsonar.organization=bcgov-oss From 5fca87fe76ca757e43e1f646543debba05cb31d1 Mon Sep 17 00:00:00 2001 From: ike thecoder Date: Mon, 13 Jan 2025 11:04:23 -0800 Subject: [PATCH 33/37] fix for click on gateway error (#1217) * some console log for testing in dev * wait for finished fetching * tweak auth context * Remove unnecessary namespace.isLoading condition --------- Co-authored-by: Russell Vinegar --- src/nextapp/pages/devportal/api-directory/your-products.tsx | 2 +- src/nextapp/pages/manager/gateways/detail.tsx | 2 +- src/nextapp/shared/services/auth/auth-context.tsx | 3 ++- src/nextapp/shared/services/auth/use-session.ts | 4 +++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/nextapp/pages/devportal/api-directory/your-products.tsx b/src/nextapp/pages/devportal/api-directory/your-products.tsx index fb19b180f..875a3e09b 100644 --- a/src/nextapp/pages/devportal/api-directory/your-products.tsx +++ b/src/nextapp/pages/devportal/api-directory/your-products.tsx @@ -29,7 +29,7 @@ const ApiDiscoveryPage: React.FC = () => { const hasNamespace = !!user?.namespace; const title = ( <> - {(namespace.isFetching || namespace.isLoading) && ( + {(namespace.isFetching) && ( )} {namespace.isSuccess && !namespace.isFetching && ( diff --git a/src/nextapp/pages/manager/gateways/detail.tsx b/src/nextapp/pages/manager/gateways/detail.tsx index b63036fb8..87ea56439 100644 --- a/src/nextapp/pages/manager/gateways/detail.tsx +++ b/src/nextapp/pages/manager/gateways/detail.tsx @@ -187,7 +187,7 @@ const NamespacesPage: React.FC = () => { }, [client, mutate, router, toast, user]); const title = ( <> - {(namespace.isFetching || namespace.isLoading) && ( + {(namespace.isFetching) && ( )} {namespace.isSuccess && !namespace.isFetching && ( diff --git a/src/nextapp/shared/services/auth/auth-context.tsx b/src/nextapp/shared/services/auth/auth-context.tsx index d8b6776eb..6d246e030 100644 --- a/src/nextapp/shared/services/auth/auth-context.tsx +++ b/src/nextapp/shared/services/auth/auth-context.tsx @@ -10,6 +10,7 @@ import { useSession, UserSessionResult } from './use-session'; const authContext = React.createContext({ isLoading: false, + isFetching: false, ok: false, maintenance: false, status: 'idle', @@ -48,7 +49,7 @@ export const AuthProvider: React.FC = ({ children }) => { requiresNamespace && !session.user.namespace; - if (noNamespace) { + if (noNamespace && session.isFetching == false) { router?.push('/manager/gateways/list').then(() => { toast({ title: `First select a Gateway to view that page`, diff --git a/src/nextapp/shared/services/auth/use-session.ts b/src/nextapp/shared/services/auth/use-session.ts index 9d6524dae..90a6365e8 100644 --- a/src/nextapp/shared/services/auth/use-session.ts +++ b/src/nextapp/shared/services/auth/use-session.ts @@ -8,6 +8,7 @@ export interface AuthFailedResponse { export interface UserSessionResult { isLoading: boolean; + isFetching: boolean; ok: boolean; maintenance: boolean; user?: UserData; @@ -64,7 +65,7 @@ export const getSessionL = async (): Promise => { }; export const useSession = (): UserSessionResult => { - const { data, status, error, isLoading } = useQuery( + const { data, status, error, isLoading, isFetching } = useQuery( 'user', getSessionL, { @@ -75,6 +76,7 @@ export const useSession = (): UserSessionResult => { return { isLoading, + isFetching, ok: Boolean(data?.user), user: data?.user, maintenance: data?.maintenance, From 39c30d449608b6c6bb68ddebf2047cba399e7f59 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Tue, 14 Jan 2025 12:49:41 -0800 Subject: [PATCH 34/37] Revert "Avoid socket hangup: enhance Keycloak auth in group service with retry logic; improve error handling in namespace service login" This reverts commit e964a72059722ff5a11c832442a226ff0a0130b1. --- src/services/keycloak/group-service.ts | 62 ++++++++------------------ src/services/org-groups/namespace.ts | 7 +-- 2 files changed, 20 insertions(+), 49 deletions(-) diff --git a/src/services/keycloak/group-service.ts b/src/services/keycloak/group-service.ts index d6c23c896..d791d0a24 100644 --- a/src/services/keycloak/group-service.ts +++ b/src/services/keycloak/group-service.ts @@ -13,66 +13,43 @@ import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRep const logger = Logger('kc.group'); export class KeycloakGroupService { + private static instanceCount = 0; // Track total instances created + private instanceId: string; + private createdAt: Date; private allGroups: any = undefined; private kcAdminClient: KeycloakAdminClient; - private clientId: string; - private clientSecret: string; - private lastAuthTime: number = 0; - private readonly AUTH_TIMEOUT = 280 * 1000; // 280 seconds (slightly less than typical 5 min token lifetime) constructor(issuerUrl: string) { + this.instanceId = `kc-group-${++KeycloakGroupService.instanceCount}`; + this.createdAt = new Date(); + logger.info('[Instance Created] id=%s, created=%s', this.instanceId, this.createdAt); + const baseUrl = issuerUrl.substr(0, issuerUrl.indexOf('/realms')); const realmName = issuerUrl.substr(issuerUrl.lastIndexOf('/') + 1); logger.debug('%s %s', baseUrl, realmName); this.kcAdminClient = new KcAdminClient({ baseUrl, realmName }); } - private async ensureAuthenticated(): Promise { - if (this.clientId && (Date.now() - this.lastAuthTime > this.AUTH_TIMEOUT)) { - logger.debug('[ensureAuthenticated] Re-authenticating due to timeout'); - await this.login(this.clientId, this.clientSecret); - } - } - public async cacheGroups() { this.allGroups = await this.getAllGroups(); } public async login( clientId: string, - clientSecret: string, - retryAttempts: number = 3 + clientSecret: string ): Promise { - this.clientId = clientId; - this.clientSecret = clientSecret; - - const result = await this._login(retryAttempts); - this.lastAuthTime = Date.now(); - return result; - } - - private async _login(retryAttempts: number): Promise { - logger.debug('[login] %s', this.clientId); + logger.debug('[login] %s', clientId); - for (let attempt = 1; attempt <= retryAttempts; attempt++) { - try { - await this.kcAdminClient - .auth({ - grantType: 'client_credentials', - clientId: this.clientId, - clientSecret: this.clientSecret, - }); - return this; - } catch (err: any) { - if (attempt === retryAttempts) { - logger.error('[login] Login failed after %d attempts: %s', retryAttempts, err); - throw err; - } - logger.warn('[login] Attempt %d failed, retrying: %s', attempt, err); - // Add exponential backoff - await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100)); - } - } + await this.kcAdminClient + .auth({ + grantType: 'client_credentials', + clientId: clientId, + clientSecret: clientSecret, + }) + .catch((err: any) => { + logger.error('[login] Login failed %s', err); + throw err; + }); return this; } @@ -100,7 +77,6 @@ export class KeycloakGroupService { } public async updateGroup(group: GroupRepresentation): Promise { - await this.ensureAuthenticated(); logger.debug('[updateGroup] %j', group); await this.kcAdminClient.groups.update({ id: group.id }, group); } diff --git a/src/services/org-groups/namespace.ts b/src/services/org-groups/namespace.ts index 42c26f77a..ef321f51f 100644 --- a/src/services/org-groups/namespace.ts +++ b/src/services/org-groups/namespace.ts @@ -13,12 +13,7 @@ export class NamespaceService { } async login(clientId: string, clientSecret: string) { - try { - await this.groupService.login(clientId, clientSecret); - } catch (err) { - logger.error('[login] Failed to login to Keycloak: %s', err); - throw new Error('Failed to authenticate with Keycloak'); - } + await this.groupService.login(clientId, clientSecret); } async markNotification(ns: string, viewed: boolean): Promise { From 5055584a8fdabd68c7ac7151e4ce9607e0064007 Mon Sep 17 00:00:00 2001 From: Elson9 Date: Thu, 16 Jan 2025 09:35:18 -0800 Subject: [PATCH 35/37] Transform dataset contacts to string (#1218) --- feeds/testdata/dataset.json | 2 +- src/batch/data-rules.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/feeds/testdata/dataset.json b/feeds/testdata/dataset.json index 21792fc27..9ea415b3f 100644 --- a/feeds/testdata/dataset.json +++ b/feeds/testdata/dataset.json @@ -124,7 +124,7 @@ "name": "travel planning" } ], - "contacts": "[{\"name\":\"DataBC Operations\",\"email\":\"data@gov.bc.ca\",\"org\":\"d2e433a1-b785-4d03-8a2b-392069175eb4\",\"role\":\"pointOfContact\",\"displayed\":true}]", + "contacts": "[{\"name\":\"DataBC Operations\",\"email\":\"data@gov.bc.ca\",\"org\":\"d2e433a1-b785-4d03-8a2b-392069175eb4\",\"role\":\"pointOfContact\",\"displayed\":[\"displayed\"]}]", "resource_status": "completed", "tracking_summary": { "total": 917, diff --git a/src/batch/data-rules.js b/src/batch/data-rules.js index 08fc326af..7d91c6274 100644 --- a/src/batch/data-rules.js +++ b/src/batch/data-rules.js @@ -62,6 +62,7 @@ const metadata = { transformations: { tags: { name: 'toStringDefaultArray' }, resources: { name: 'toStringDefaultArray' }, + contacts: { name: 'toStringDefaultArray' }, organization: { name: 'connectOne', key: 'organization.id', From b8628d0f88c7f0bbe04868a0d961c1e7eb4d023b Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 24 Jan 2025 16:43:28 -0800 Subject: [PATCH 36/37] Update gateway ID validation error message --- e2e/cypress/tests/19-api-v3/03-gateways.ts | 2 +- src/lists/extensions/Namespace.ts | 2 +- src/services/keycloak/namespace-details.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/cypress/tests/19-api-v3/03-gateways.ts b/e2e/cypress/tests/19-api-v3/03-gateways.ts index a3620c29a..e0918bdbc 100644 --- a/e2e/cypress/tests/19-api-v3/03-gateways.ts +++ b/e2e/cypress/tests/19-api-v3/03-gateways.ts @@ -188,7 +188,7 @@ describe('Gateways', () => { details: { d0: { message: - 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start and end with a letter.', + 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start with a letter.', }, }, } diff --git a/src/lists/extensions/Namespace.ts b/src/lists/extensions/Namespace.ts index 773e9d294..48041f554 100644 --- a/src/lists/extensions/Namespace.ts +++ b/src/lists/extensions/Namespace.ts @@ -251,7 +251,7 @@ module.exports = { assert.strictEqual( re.test(args.namespace), true, - 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start and end with a letter.' + 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start with a letter.' ); const noauthContext = context.createContext({ skipAccessControl: true, diff --git a/src/services/keycloak/namespace-details.ts b/src/services/keycloak/namespace-details.ts index 021248c2e..63adf88b6 100644 --- a/src/services/keycloak/namespace-details.ts +++ b/src/services/keycloak/namespace-details.ts @@ -195,7 +195,7 @@ export function validateNamespaceName(name: string) { regExprValidation( namespaceValidationRule, name, - 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start and end with a letter.' + 'Gateway ID must be between 5 and 15 lowercase alpha-numeric characters and start with a letter.' ); } From 7fa55adab6cc24114de14eb6b26d27bec9e06076 Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 24 Jan 2025 16:48:26 -0800 Subject: [PATCH 37/37] remove additional logging in KeycloakGroupService --- src/services/keycloak/group-service.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/services/keycloak/group-service.ts b/src/services/keycloak/group-service.ts index d791d0a24..45a72b7ca 100644 --- a/src/services/keycloak/group-service.ts +++ b/src/services/keycloak/group-service.ts @@ -13,17 +13,10 @@ import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRep const logger = Logger('kc.group'); export class KeycloakGroupService { - private static instanceCount = 0; // Track total instances created - private instanceId: string; - private createdAt: Date; private allGroups: any = undefined; private kcAdminClient: KeycloakAdminClient; constructor(issuerUrl: string) { - this.instanceId = `kc-group-${++KeycloakGroupService.instanceCount}`; - this.createdAt = new Date(); - logger.info('[Instance Created] id=%s, created=%s', this.instanceId, this.createdAt); - const baseUrl = issuerUrl.substr(0, issuerUrl.indexOf('/realms')); const realmName = issuerUrl.substr(issuerUrl.lastIndexOf('/') + 1); logger.debug('%s %s', baseUrl, realmName);