Compare commits

...

169 Commits

Author SHA1 Message Date
dependabot[bot] 2c80f7c920
Bump @typescript-eslint/eslint-plugin from 7.10.0 to 7.11.0 in /internal-ui (#2758)
Bump @typescript-eslint/eslint-plugin in /internal-ui

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 7.10.0 to 7.11.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.11.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 13:32:23 +01:00
dependabot[bot] 1cad1aeb0c
Bump @typescript-eslint/parser from 7.10.0 to 7.11.0 in /internal-ui (#2759)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.10.0 to 7.11.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.11.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 12:40:11 +01:00
dependabot[bot] 76b1d21c86
Bump next-mdx-remote from 4.4.1 to 5.0.0 (#2737)
* Bump next-mdx-remote from 4.4.1 to 5.0.0

Bumps [next-mdx-remote](https://github.com/hashicorp/next-mdx-remote) from 4.4.1 to 5.0.0.
- [Release notes](https://github.com/hashicorp/next-mdx-remote/releases)
- [Changelog](https://github.com/hashicorp/next-mdx-remote/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/next-mdx-remote/compare/v4.4.1...v5.0.0)

---
updated-dependencies:
- dependency-name: next-mdx-remote
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* updated remark-gfm

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
2024-05-28 10:57:16 +01:00
Nitendra a1d2e2ac3d
Added tests for testing mdx generated source of setup link steps (#2756) 2024-05-27 20:19:18 +01:00
Deepak Prabhakara 0048671643 Release 1.26.1 2024-05-27 12:12:05 +01:00
Nitendra 73b1337f35
Added e2e tests for enterprise SSO setup link (#2728)
* Added e2e tests for enterprise SSO setup link
generic SAML 2.0 workflow

* Replaced useSWR with fetch api in setuplinks

* Addressed review comment
 - Refactored code to remove localor.all
 - removed extract awaits like page repload

* Refactored code
 - used fixtures to create setup link
 - removed unnecessary code
2024-05-27 12:07:10 +01:00
Deepak Prabhakara 654fdd4220
added npm prune to prepare script, this should dedupe @libsql/sqlite3… (#2755)
* added npm prune to prepare script, this should dedupe @libsql/sqlite3 package

* fixed path to typeorm (which is now only in root after prune)
2024-05-27 12:05:38 +01:00
dependabot[bot] 55df28b0c7
Bump mysql2 from 3.9.7 to 3.9.8 in /npm (#2753)
Bumps [mysql2](https://github.com/sidorares/node-mysql2) from 3.9.7 to 3.9.8.
- [Release notes](https://github.com/sidorares/node-mysql2/releases)
- [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md)
- [Commits](https://github.com/sidorares/node-mysql2/compare/v3.9.7...v3.9.8)

---
updated-dependencies:
- dependency-name: mysql2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 11:03:27 +01:00
Deepak Prabhakara f90da2bb8f Release 1.26.0 2024-05-26 22:28:24 +01:00
Deepak Prabhakara 2e75bb361a updated package-lock 2024-05-26 22:03:19 +01:00
dependabot[bot] bf8a79031b
Bump tap from 19.0.0 to 19.0.2 in /npm (#2751)
Bumps [tap](https://github.com/tapjs/tapjs) from 19.0.0 to 19.0.2.
- [Release notes](https://github.com/tapjs/tapjs/releases)
- [Commits](https://github.com/tapjs/tapjs/commits/tap@19.0.2)

---
updated-dependencies:
- dependency-name: tap
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 21:46:46 +01:00
dependabot[bot] 26c807d56a
Bump @aws-sdk/util-dynamodb from 3.582.0 to 3.584.0 in /npm (#2752)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.582.0 to 3.584.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.584.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 21:46:39 +01:00
dependabot[bot] 9fa12b471f
Bump @aws-sdk/credential-providers from 3.582.0 to 3.583.0 in /npm (#2747)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.582.0 to 3.583.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.583.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 21:36:44 +01:00
dependabot[bot] 37fddf8f11
Bump @aws-sdk/client-dynamodb from 3.582.0 to 3.584.0 in /npm (#2750)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.582.0 to 3.584.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.584.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 21:34:37 +01:00
dependabot[bot] 0800a92f13
Bump @aws-sdk/util-dynamodb from 3.577.0 to 3.582.0 in /npm (#2749)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.577.0 to 3.582.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.582.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 21:15:25 +01:00
nadilas 7d0c31f7bc
Feat: sqlite and turso support (#2729)
* feat: basic sqlite and turso setup

* chore: format code

* chore: explain turso flags

* fix: failing ttl tests for sqlite

* chore: increase key field length, even though sqlite doesn't care

* chore: remove sqlite logging

* fixed order by query (related to precision of current_timestamp which is seconds)

* delete record3 as well

* test: add turso to _dev docker compose and tests

* chore: remove temporary turso engine type

* removed sqlite3 from webpack ignore

* fixed format

* added turso image to ci/cd test

---------

Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
2024-05-26 21:15:05 +01:00
dependabot[bot] a64a5a0dbc
Bump @playwright/test from 1.44.0 to 1.44.1 (#2746)
Bumps [@playwright/test](https://github.com/microsoft/playwright) from 1.44.0 to 1.44.1.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.44.0...v1.44.1)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 18:54:01 +05:30
dependabot[bot] be768bc70b
Bump @types/react from 18.3.2 to 18.3.3 in /internal-ui (#2745)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.3.2 to 18.3.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 17:56:24 +05:30
Nitendra ce565c4e7e
Added scroll to top for created setups links (#2730)
in both SSO and Dsync flows

Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
2024-05-24 15:20:46 +05:30
Deepak Prabhakara 7ccd7b0e48 updated deployment 2024-05-23 21:52:36 +01:00
Aswin V 9f4dddad09
E2E for DSync (#2701)
* Fixture add DSync Page

* Tweak fixture, add delete connection method

* Label should be associated with the input

* WIP Test for Azure SCIM

* Tweak helper to work with Azure SCIM query param

* Fixture add switching to users view method and use instance property for tenant/product

* Include Jackson Api key header in SCIM endpoint request

* Simulate a user creation request to SCIM endpoint and assert it in view

* Update sample user to match type

* Fix flaky test by waiting for dom

* Export helpers from index

* Refactor scimOpEndpoint

* Add group and group member

* Add switching to group view in fixture

* Assert group in groups view

* Tweak userName

* Enable webhook events logging

* Refactor

* Add second user, parametrize azureUser

* Set webhook url/secret

* Assert webhook events

* Refactor view switching

* Refactor event inspection

* Delete webhook logs

* Tweak scimEndpoint creation

* Add `deleteGroup`

* Use util method in api helpers

* Add test for user/group deletion

* Bump up assertion timeout

* Try flakiness fix with waiting for api response

* `updateGroupName` e2e helper

* Assert updated group name

* Revert local changes

* Potential fix for failed test

* Try fix

* Add missing await for visibility checks

* Cleanup await inside expect

* Cleanup waiting for response

* Test user update, disabling webhook event logging

* Parametrize test for Okta/Azure

* Cleanup await

* Try removing assertion timeout

* Put back assetion timeout
2024-05-23 23:22:45 +05:30
Deepak Prabhakara 183e8fb1e1 Release 1.25.1 2024-05-23 12:24:10 +01:00
Deepak Prabhakara e008af5c90 updated package-lock 2024-05-23 12:23:50 +01:00
dependabot[bot] 5dfac0fc50
Bump @aws-sdk/client-dynamodb from 3.577.0 to 3.582.0 in /npm (#2740)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.577.0 to 3.582.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.582.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:21:47 +01:00
dependabot[bot] 69afafb8f8
Bump react-i18next from 14.1.1 to 14.1.2 (#2738)
Bumps [react-i18next](https://github.com/i18next/react-i18next) from 14.1.1 to 14.1.2.
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v14.1.1...v14.1.2)

---
updated-dependencies:
- dependency-name: react-i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:15:33 +01:00
dependabot[bot] cf1979d479
Bump @retracedhq/retraced from 0.7.11 to 0.7.12 (#2739)
* Bump @retracedhq/retraced from 0.7.11 to 0.7.12

Bumps [@retracedhq/retraced](https://github.com/retracedhq/retraced-js) from 0.7.11 to 0.7.12.
- [Release notes](https://github.com/retracedhq/retraced-js/releases)
- [Changelog](https://github.com/retracedhq/retraced-js/blob/main/CHANGELOG)
- [Commits](https://github.com/retracedhq/retraced-js/compare/v0.7.11...v0.7.12)

---
updated-dependencies:
- dependency-name: "@retracedhq/retraced"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* updated axios

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
2024-05-23 12:15:28 +01:00
dependabot[bot] 00d75a861e
Bump @aws-sdk/credential-providers from 3.577.0 to 3.582.0 in /npm (#2741)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.577.0 to 3.582.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.582.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:15:19 +01:00
dependabot[bot] 0fba606fe9
Bump @vitejs/plugin-react from 4.2.1 to 4.3.0 in /internal-ui (#2742)
Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 4.2.1 to 4.3.0.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/v4.3.0/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 12:15:16 +01:00
Chirag Gupta 937e69e5f9
fix: redis url does not come under socketOptions (#2743)
* fix: redis url does not come under socketOptions

* fix: prettier
2024-05-23 12:14:59 +01:00
Deepak Prabhakara 4330eeb530 updated package-lock 2024-05-23 00:14:13 +01:00
dependabot[bot] 7ef912c0ba
Bump axios from 1.7.1 to 1.7.2 in /npm (#2734)
---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 00:04:23 +01:00
dependabot[bot] c8e8abaaa8
Bump blockly from 10.4.3 to 11.0.0 (#2725)
* ---
updated-dependencies:
- dependency-name: blockly
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* updated blockly

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
2024-05-22 23:41:15 +01:00
dependabot[bot] ec9e5f285a
Bump @rollup/rollup-linux-x64-gnu from 4.17.2 to 4.18.0 in /internal-ui (#2735)
---
updated-dependencies:
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-22 23:40:48 +01:00
dependabot[bot] 9a2600e1ee
Bump tap from 18.8.0 to 19.0.0 in /npm (#2733)
---
updated-dependencies:
- dependency-name: tap
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-22 23:40:34 +01:00
dependabot[bot] 016b456b75
Bump @retracedhq/retraced from 0.7.10 to 0.7.11 (#2731)
---
updated-dependencies:
- dependency-name: "@retracedhq/retraced"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-22 22:35:08 +01:00
dependabot[bot] e11aa6e3fe
Bump micromatch from 4.0.5 to 4.0.7 (#2732)
---
updated-dependencies:
- dependency-name: micromatch
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-22 22:34:34 +01:00
Deepak Prabhakara c76791fabd turn off sboms 2024-05-21 21:07:28 +01:00
Deepak Prabhakara 93cbf30cfc turn off sboms 2024-05-21 20:04:10 +01:00
Deepak Prabhakara ac698864aa Release 1.25.0 2024-05-21 19:01:13 +01:00
Deepak Prabhakara 99f55485fc updated package-lock 2024-05-21 19:00:48 +01:00
Deepak Prabhakara 09c6777f9e
updated deps not picked up by dependabot (#2724)
* updated deps not picked up by dependabot

* updated package-lock
2024-05-21 17:49:33 +01:00
Aswin V 25b29d70ef
Size increase for namespace column (#2639)
* Increase size of namespace column

* MariaDB migration

* MySQL migration

* MSSQL migration

* Postgres migration

* Planetscale migration

* fixed indexNamespace

* Paginate

---------

Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
2024-05-21 17:48:48 +01:00
dependabot[bot] a30efd8e3c
Bump i18next from 23.11.4 to 23.11.5 (#2720)
---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:08:51 +01:00
dependabot[bot] caf4b75983
Bump @aws-sdk/util-dynamodb from 3.576.0 to 3.577.0 in /npm (#2721)
---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:08:48 +01:00
dependabot[bot] 76bf07aaaf
Bump axios from 1.7.0 to 1.7.1 in /npm (#2722)
---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:08:44 +01:00
dependabot[bot] c987444b04
Bump release-it from 17.2.1 to 17.3.0 (#2723)
---
updated-dependencies:
- dependency-name: release-it
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:08:40 +01:00
dependabot[bot] f4ea08cd0f
Bump @aws-sdk/credential-providers from 3.576.0 to 3.577.0 in /npm (#2713)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.576.0 to 3.577.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.577.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 19:57:43 +01:00
dependabot[bot] d3b68813a7
Bump @aws-sdk/client-dynamodb from 3.576.0 to 3.577.0 in /npm (#2715)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.576.0 to 3.577.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.577.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 13:58:14 +01:00
dependabot[bot] 2ca666ff3e
Bump axios from 1.6.8 to 1.7.0 in /npm (#2718)
Bumps [axios](https://github.com/axios/axios) from 1.6.8 to 1.7.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.6.8...v1.7.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 13:58:10 +01:00
dependabot[bot] bcd5c751bd
Bump @types/lodash from 4.17.1 to 4.17.4 in /npm (#2719)
Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.17.1 to 4.17.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

---
updated-dependencies:
- dependency-name: "@types/lodash"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 13:57:56 +01:00
dependabot[bot] dcd291d394
Bump sinon from 17.0.2 to 18.0.0 in /npm (#2712)
Bumps [sinon](https://github.com/sinonjs/sinon) from 17.0.2 to 18.0.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v17.0.2...v18.0.0)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:49:18 +01:00
dependabot[bot] 9786a9f8f4
Bump mongodb from 6.6.1 to 6.6.2 in /npm (#2714)
Bumps [mongodb](https://github.com/mongodb/node-mongodb-native) from 6.6.1 to 6.6.2.
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/main/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/compare/v6.6.1...v6.6.2)

---
updated-dependencies:
- dependency-name: mongodb
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:49:10 +01:00
dependabot[bot] 6163460947
Bump redis from 4.6.13 to 4.6.14 in /npm (#2716)
Bumps [redis](https://github.com/redis/node-redis) from 4.6.13 to 4.6.14.
- [Release notes](https://github.com/redis/node-redis/releases)
- [Changelog](https://github.com/redis/node-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/node-redis/compare/redis@4.6.13...redis@4.6.14)

---
updated-dependencies:
- dependency-name: redis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:49:00 +01:00
dependabot[bot] 22839cd2ee
Bump sharp from 0.33.3 to 0.33.4 (#2717)
Bumps [sharp](https://github.com/lovell/sharp) from 0.33.3 to 0.33.4.
- [Release notes](https://github.com/lovell/sharp/releases)
- [Changelog](https://github.com/lovell/sharp/blob/main/docs/changelog.md)
- [Commits](https://github.com/lovell/sharp/compare/v0.33.3...v0.33.4)

---
updated-dependencies:
- dependency-name: sharp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 11:48:56 +01:00
Deepak Prabhakara 2d5d723549 Release 1.24.2 2024-05-15 23:29:23 +01:00
Deepak Prabhakara 2907ce1e41 run swagger after bumping version 2024-05-15 23:28:51 +01:00
Deepak Prabhakara 10dd52cb54 Revert "update swagger file before releasing"
This reverts commit 83a5f4de6b.
2024-05-15 23:26:51 +01:00
Deepak Prabhakara 6f0eb99f03 updated swagger tag 2024-05-15 23:21:17 +01:00
Deepak Prabhakara 83a5f4de6b update swagger file before releasing 2024-05-15 23:18:22 +01:00
Deepak Prabhakara 7e8612c07b fixed typo 2024-05-15 12:06:12 +01:00
dependabot[bot] 34bf0a7c70
Bump @aws-sdk/util-dynamodb from 3.574.0 to 3.575.0 in /npm (#2711)
* Bump @aws-sdk/util-dynamodb from 3.574.0 to 3.575.0 in /npm

Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.574.0 to 3.575.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.575.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* updated deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
2024-05-15 12:04:59 +01:00
dependabot[bot] 643d54a2e5
Bump @aws-sdk/credential-providers from 3.575.0 to 3.576.0 in /npm (#2709)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.575.0 to 3.576.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.576.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 11:43:38 +01:00
dependabot[bot] 9a4bb57ce1
Bump @typescript-eslint/parser from 7.8.0 to 7.9.0 in /internal-ui (#2706)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 7.8.0 to 7.9.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.9.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 19:11:51 +01:00
Deepak Prabhakara 2035dbb42e updated node 2024-05-14 16:30:25 +01:00
dependabot[bot] 90496f267c
Bump @aws-sdk/credential-providers from 3.574.0 to 3.575.0 in /npm (#2703)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.574.0 to 3.575.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.575.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 14:28:18 +01:00
dependabot[bot] 02af9ac577
Bump @types/node from 20.12.11 to 20.12.12 in /internal-ui (#2707)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.11 to 20.12.12.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 14:28:08 +01:00
dependabot[bot] 02385162f8
Bump @typescript-eslint/eslint-plugin from 7.8.0 to 7.9.0 in /internal-ui (#2708)
Bump @typescript-eslint/eslint-plugin in /internal-ui

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 7.8.0 to 7.9.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.9.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 14:28:04 +01:00
dependabot[bot] cbd423baf4
Bump @types/node from 20.12.11 to 20.12.12 in /npm (#2702)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.11 to 20.12.12.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 11:24:03 +01:00
dependabot[bot] be5b9062b2
Bump @aws-sdk/client-dynamodb from 3.574.0 to 3.575.0 in /npm (#2704)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.574.0 to 3.575.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.575.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 11:23:56 +01:00
dependabot[bot] 5799729f0a
Bump @aws-sdk/util-dynamodb from 3.572.0 to 3.574.0 in /npm (#2705)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.572.0 to 3.574.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.574.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 11:23:44 +01:00
Deepak Prabhakara c703b9dfea
Terminus json model (#2612)
* WIP

* tweaks

* lint fix

* fixed roles casing

* cleanup
2024-05-13 23:49:44 +01:00
dependabot[bot] 2c80abb235
Bump @aws-sdk/client-dynamodb from 3.572.0 to 3.574.0 in /npm (#2694)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.572.0 to 3.574.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.574.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 10:52:51 +01:00
Aswin V f4c49173ef
E2E chores (#2692)
* Download mocksaml metadata and store it in env

* Test adding sso connection via rawMetadata
2024-05-13 09:40:00 +01:00
dependabot[bot] 1e8ebd239e
Bump tap from 18.7.3 to 18.8.0 in /npm (#2695)
Bumps [tap](https://github.com/tapjs/tapjs) from 18.7.3 to 18.8.0.
- [Release notes](https://github.com/tapjs/tapjs/releases)
- [Commits](https://github.com/tapjs/tapjs/compare/tap@18.7.3...tap@18.8.0)

---
updated-dependencies:
- dependency-name: tap
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 09:39:08 +01:00
dependabot[bot] 469cb6db8b
Bump @googleapis/admin from 18.0.0 to 19.0.0 in /npm (#2696)
Bumps [@googleapis/admin](https://github.com/googleapis/google-api-nodejs-client) from 18.0.0 to 19.0.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/release-please-config.json)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/iam-v18.0.0...chat-v19.0.0)

---
updated-dependencies:
- dependency-name: "@googleapis/admin"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 09:39:04 +01:00
dependabot[bot] a8e4a22547
Bump @aws-sdk/credential-providers from 3.572.0 to 3.574.0 in /npm (#2697)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.572.0 to 3.574.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.574.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 09:39:00 +01:00
dependabot[bot] ead31c603f
Bump jose from 5.2.4 to 5.3.0 in /npm (#2698)
Bumps [jose](https://github.com/panva/jose) from 5.2.4 to 5.3.0.
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/jose/compare/v5.2.4...v5.3.0)

---
updated-dependencies:
- dependency-name: jose
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 09:38:55 +01:00
dependabot[bot] f4871e246c
Bump i18next from 23.11.3 to 23.11.4 (#2699)
Bumps [i18next](https://github.com/i18next/i18next) from 23.11.3 to 23.11.4.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.11.3...v23.11.4)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 09:38:41 +01:00
dependabot[bot] b7471eb6e2
Bump @types/react from 18.3.1 to 18.3.2 in /internal-ui (#2700)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.3.1 to 18.3.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 09:38:26 +01:00
Deepak Prabhakara b00fbcc58b updated deployment 2024-05-12 19:47:24 +01:00
Deepak Prabhakara 7f12921f22 Release 1.24.1 2024-05-11 13:38:30 +01:00
Deepak Prabhakara dd29849ffb updated package-lock 2024-05-11 13:38:12 +01:00
Deepak Prabhakara 5eb106e5c4
Rename saml fed and sso tracer (#2693)
* rename

* more rename

* samlFed -> idFed
2024-05-11 13:35:32 +01:00
Deepak Prabhakara 3d543bc7ab Release 1.24.0 2024-05-10 16:25:37 +01:00
Deepak Prabhakara 6bfb89a74e
Renaming routes for Identity Federation (#2618)
* WIP

* updated swagger file

* renamed routes

* renamed test folder

* separate section for Identity Federation

* sso-tracer -> sso-traces

* don't change ACS url for SAML federation

* SAMLFederation -> IdentityFederation

* SAMLFederation -> IdentityFederation

* keep api/federated-saml but move to api/identity-federation

* test old route as well

* fixed test

* fixed test

* retry tests 3 times

* updated deployment

* WIP create SAML Fed app

(cherry picked from commit 3d15b20a2d)

* Add Admin Portal SSO via SAML Fed

* Minor tweaks

* Use fixture and login using federated connection

* Cleanup SAML fed connection after test, disable failing assertion for now

* Remove only

* Use MockSAML endpoint from env

* Cleanup SSO connections mapped to SAML Fed

* OIDC Fed spec

* Try with higher timeout

* Mutate on page load

* Put back assertion

* Remove assertion and mutate for now

* SAML Fed App + 2 SAML Providers

* Take in optional tenant/product for fixture method

* SAML Fed + 2 OIDC providers

* SAML Fed test cases for single provider

* Tweak title

* Replace swr with fetch

* Remove only

* Bump up timeout to 100s

* Add more test cases for OIDC Fed

* Refactor fetch with hooks

* locale tweaks

* Also try with the other provider

* Fixture support SAML add via raw metadata

* Add second SAML connection using raw metadata

* Revert "Add second SAML connection using raw metadata"

* Revert "Fixture support SAML add via raw metadata"

---------

Co-authored-by: ukrocks007 <ukrocks.mehta@gmail.com>
Co-authored-by: Aswin V <vaswin91@gmail.com>
2024-05-10 11:41:23 +01:00
Deepak Prabhakara 147fbaa9ec Release 1.23.10 2024-05-10 11:17:38 +01:00
dependabot[bot] d89cefcf87
Bump @aws-sdk/util-dynamodb from 3.569.0 to 3.572.0 in /npm (#2690)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.569.0 to 3.572.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.572.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-10 09:27:04 +01:00
dependabot[bot] cdf41e00d0
Bump eslint-plugin-react-refresh from 0.4.6 to 0.4.7 in /internal-ui (#2691)
Bumps [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh) from 0.4.6 to 0.4.7.
- [Release notes](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/releases)
- [Changelog](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/compare/v0.4.6...v0.4.7)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-refresh
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-10 09:27:00 +01:00
dependabot[bot] 37df8881ff
Bump @aws-sdk/credential-providers from 3.569.0 to 3.572.0 in /npm (#2685)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.569.0 to 3.572.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.572.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-09 20:23:26 +01:00
dependabot[bot] 1302254727
Bump @aws-sdk/client-dynamodb from 3.569.0 to 3.572.0 in /npm (#2686)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.569.0 to 3.572.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.572.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-09 20:05:58 +01:00
dependabot[bot] 526f3d0891
Bump @types/node from 20.12.10 to 20.12.11 in /npm (#2687)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.10 to 20.12.11.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-09 20:05:54 +01:00
dependabot[bot] 43fcf5b85f
Bump @types/node from 20.12.10 to 20.12.11 in /internal-ui (#2688)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.10 to 20.12.11.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-09 20:05:49 +01:00
Deepak Prabhakara def9239d1a
cleanup of preLoadedConfig (#2689) 2024-05-09 20:05:25 +01:00
Deepak Prabhakara a86efad2e0 updated node 2024-05-08 10:57:41 +01:00
dependabot[bot] 69be15c1fc
Bump sinon from 17.0.1 to 17.0.2 in /npm (#2683)
Bumps [sinon](https://github.com/sinonjs/sinon) from 17.0.1 to 17.0.2.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v17.0.1...v17.0.2)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-08 10:18:54 +01:00
dependabot[bot] 216b0c83d2
Bump daisyui from 4.10.5 to 4.11.1 (#2684)
Bumps [daisyui](https://github.com/saadeghi/daisyui) from 4.10.5 to 4.11.1.
- [Release notes](https://github.com/saadeghi/daisyui/releases)
- [Changelog](https://github.com/saadeghi/daisyui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/saadeghi/daisyui/compare/v4.10.5...v4.11.1)

---
updated-dependencies:
- dependency-name: daisyui
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-08 10:18:50 +01:00
Deepak Prabhakara 59a80772e0
use lib/api defaultHandler (#2640)
* use lib/api defaultHandler

* cleanup
2024-05-07 12:49:32 +01:00
dependabot[bot] 3a7da89593
Bump mongodb from 6.6.0 to 6.6.1 in /npm (#2677)
Bumps [mongodb](https://github.com/mongodb/node-mongodb-native) from 6.6.0 to 6.6.1.
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/main/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/compare/v6.6.0...v6.6.1)

---
updated-dependencies:
- dependency-name: mongodb
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-07 12:20:44 +01:00
dependabot[bot] 113ab82924
Bump @types/node from 20.12.8 to 20.12.10 in /npm (#2678)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.8 to 20.12.10.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-07 12:20:41 +01:00
dependabot[bot] c8ba0ecac6
Bump tap from 18.7.2 to 18.7.3 in /npm (#2679)
Bumps [tap](https://github.com/tapjs/tapjs) from 18.7.2 to 18.7.3.
- [Release notes](https://github.com/tapjs/tapjs/releases)
- [Commits](https://github.com/tapjs/tapjs/compare/tap@18.7.2...tap@18.7.3)

---
updated-dependencies:
- dependency-name: tap
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-07 12:20:36 +01:00
dependabot[bot] 0893a65d1c
Bump @playwright/test from 1.43.1 to 1.44.0 (#2680)
Bumps [@playwright/test](https://github.com/microsoft/playwright) from 1.43.1 to 1.44.0.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.43.1...v1.44.0)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-07 12:20:32 +01:00
dependabot[bot] b4d89d42bf
Bump @types/node from 20.12.8 to 20.12.10 in /internal-ui (#2681)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.8 to 20.12.10.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-07 12:20:07 +01:00
Utkarsh Mehta 48f9dd49b1
e2e tests for v1 apis (#2653)
* chore: Update test.use options in e2e tests

* chore: Update Authorization header in e2e tests

* feat: Add getConnectionByProduct function for retrieving SSO connections by product

* feat: Add test for retrieving empty array of SSO connections by product

* feat: Add OAuth helper functions for authorization

* chore: Remove unused import in oauth.ts file

* feat: Add getDirectoryByProduct function for retrieving a directory by product

* lint fixes

* feat: e2e tests

* lint fixes

* feat: Add getDirectoryEvents function for retrieving events from a directory

* feat: Add deleteAllEventsFromDirectory function for deleting all events from a directory

* feat: Refactor SSO trace API functions to remove unnecessary object destructuring

* refactor: Update webhook URL and secret to empty string in directoryPayload
2024-05-07 12:19:34 +01:00
Deepak Prabhakara dd1755b669 updated deployment 2024-05-07 12:11:43 +01:00
Deepak Prabhakara 235db3b024 Release 1.23.9 2024-05-06 19:42:02 +01:00
Aswin V f8e823f4b2
Fix property access in saml response path. (#2675)
Fix session access inside catch
2024-05-06 19:41:13 +01:00
Deepak Prabhakara ff988bb271 Release 1.23.8 2024-05-06 17:29:59 +01:00
Deepak Prabhakara 67d05e0ba1
fixes wrong EE check (#2674)
fixed wrong EE check
2024-05-06 17:28:28 +01:00
Aswin V 9943a06ace
Extend e2e (#2601)
* Not needed with standalone build in CI as well as local runs

* Start adding tests for main sections under Admin UI

* Add SAML SSO connection

* Remove only

* Debug failing test

* Cleanup debugging changes

* Update mocksaml docker

* Increase number of workers for playwright execution

* Disable multiple workers for now

* Align folder layout with sidebar features

* Enable stdout for webserver

* Try fixture

* Fixture WIP

* WIP fixture tweak and add more test cases

* Fix locator

* Rename test file

* Remove only

* Keep track of connections inside fixture, delete all method fix

* Fix sso naming

* Use portal fixture for common utils

* Make fixture generic for OIDC SSO

* Add OIDC porvider tests

* Comment tweak

* Make client id secret dynamic

* Spec for OAuth2 wrapper + 1 SAML and 1 OIDC providers

* Fixture method to update SSO connection

* Test case for wrong redirect url

* Refactor

* WIP Wrong redirect url test for OIDC provider plus
setup for toggle connection

* WIP inactive connection test

* Set env for credentials login

* Add credentials login to portal fixture

* Fixes
2024-05-06 12:37:12 +01:00
Deepak Prabhakara f08025cc31 updated deployment 2024-05-06 12:36:58 +01:00
Deepak Prabhakara 63baf12a38 Release 1.23.7 2024-05-06 09:16:09 +01:00
Deepak Prabhakara 668a1ba499
Stats for Identity Federation Apps (#2671)
rename
2024-05-06 00:13:25 +01:00
Deepak Prabhakara b6adc308f7 updated package-lock 2024-05-04 23:23:49 +01:00
dependabot[bot] bbcea282f8
Bump @aws-sdk/credential-providers from 3.568.0 to 3.569.0 in /npm (#2669)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.568.0 to 3.569.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.569.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 15:30:23 +01:00
dependabot[bot] 143ab81eea
Bump @googleapis/admin from 17.1.0 to 18.0.0 in /npm (#2667)
Bumps [@googleapis/admin](https://github.com/googleapis/google-api-nodejs-client) from 17.1.0 to 18.0.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/release-please-config.json)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/17.1.0...iam-v18.0.0)

---
updated-dependencies:
- dependency-name: "@googleapis/admin"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 15:30:16 +01:00
dependabot[bot] 14e222163c
Bump @boxyhq/saml20 from 1.5.0 to 1.5.1 in /npm (#2668)
Bumps [@boxyhq/saml20](https://github.com/boxyhq/saml20) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/boxyhq/saml20/releases)
- [Changelog](https://github.com/boxyhq/saml20/blob/main/.release-it.json)
- [Commits](https://github.com/boxyhq/saml20/compare/v1.5.0...v1.5.1)

---
updated-dependencies:
- dependency-name: "@boxyhq/saml20"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 15:01:33 +01:00
dependabot[bot] 571a2d1f0f
Bump @aws-sdk/util-dynamodb from 3.568.0 to 3.569.0 in /npm (#2670)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.568.0 to 3.569.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.569.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 15:01:09 +01:00
dependabot[bot] a6e993d1c8
Bump @retracedhq/logs-viewer from 2.7.3 to 2.7.4 (#2662)
Bumps [@retracedhq/logs-viewer](https://github.com/retracedhq/logs-viewer) from 2.7.3 to 2.7.4.
- [Release notes](https://github.com/retracedhq/logs-viewer/releases)
- [Changelog](https://github.com/retracedhq/logs-viewer/blob/main/.release-it.json)
- [Commits](https://github.com/retracedhq/logs-viewer/compare/v2.7.3...v2.7.4)

---
updated-dependencies:
- dependency-name: "@retracedhq/logs-viewer"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 15:01:00 +01:00
dependabot[bot] bd2dc3d382
Bump @boxyhq/metrics from 0.2.6 to 0.2.7 in /npm (#2666)
Bumps [@boxyhq/metrics](https://github.com/boxyhq/metrics) from 0.2.6 to 0.2.7.
- [Release notes](https://github.com/boxyhq/metrics/releases)
- [Changelog](https://github.com/boxyhq/metrics/blob/main/.release-it.json)
- [Commits](https://github.com/boxyhq/metrics/compare/v0.2.6...v0.2.7)

---
updated-dependencies:
- dependency-name: "@boxyhq/metrics"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 14:24:19 +01:00
dependabot[bot] de83010f93
Bump @aws-sdk/client-dynamodb from 3.568.0 to 3.569.0 in /npm (#2665)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.568.0 to 3.569.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.569.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 14:24:11 +01:00
dependabot[bot] 6f14494078
Bump mongodb from 6.5.0 to 6.6.0 in /npm (#2664)
Bumps [mongodb](https://github.com/mongodb/node-mongodb-native) from 6.5.0 to 6.6.0.
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/main/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/compare/v6.5.0...v6.6.0)

---
updated-dependencies:
- dependency-name: mongodb
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 14:15:12 +01:00
dependabot[bot] 71f5a31e0b
Bump @types/lodash from 4.17.0 to 4.17.1 in /npm (#2663)
Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.17.0 to 4.17.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

---
updated-dependencies:
- dependency-name: "@types/lodash"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 14:15:08 +01:00
dependabot[bot] 7fd15f5b7b
Bump @aws-sdk/util-dynamodb from 3.567.0 to 3.568.0 in /npm (#2661)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.567.0 to 3.568.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.568.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 14:14:50 +01:00
dependabot[bot] c0737a20bc
Bump @retracedhq/retraced from 0.7.9 to 0.7.10 (#2660)
Bumps [@retracedhq/retraced](https://github.com/retracedhq/retraced-js) from 0.7.9 to 0.7.10.
- [Release notes](https://github.com/retracedhq/retraced-js/releases)
- [Changelog](https://github.com/retracedhq/retraced-js/blob/main/CHANGELOG)
- [Commits](https://github.com/retracedhq/retraced-js/compare/v0.7.9...v0.7.10)

---
updated-dependencies:
- dependency-name: "@retracedhq/retraced"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-04 14:14:47 +01:00
dependabot[bot] f3efcdd2ce
Bump @aws-sdk/credential-providers from 3.567.0 to 3.568.0 in /npm (#2655)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.567.0 to 3.568.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.568.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-03 16:08:38 +01:00
dependabot[bot] 252c8cf775
Bump @aws-sdk/client-dynamodb from 3.567.0 to 3.568.0 in /npm (#2654)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.567.0 to 3.568.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.568.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-03 12:34:07 +01:00
dependabot[bot] db63d6309f
Bump @aws-sdk/util-dynamodb from 3.565.0 to 3.567.0 in /npm (#2656)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.565.0 to 3.567.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.567.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-03 12:33:59 +01:00
dependabot[bot] 08a70476db
Bump @googleapis/admin from 17.0.0 to 17.1.0 in /npm (#2657)
Bumps [@googleapis/admin](https://github.com/googleapis/google-api-nodejs-client) from 17.0.0 to 17.1.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/17.1.0/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/iam-v17.0.0...17.1.0)

---
updated-dependencies:
- dependency-name: "@googleapis/admin"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-03 12:33:55 +01:00
dependabot[bot] 9e1f149983
Bump vite from 5.2.10 to 5.2.11 in /internal-ui (#2658)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.2.10 to 5.2.11.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.2.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-03 12:33:52 +01:00
dependabot[bot] bedcba0fe5
Bump daisyui from 4.10.3 to 4.10.5 (#2659)
Bumps [daisyui](https://github.com/saadeghi/daisyui) from 4.10.3 to 4.10.5.
- [Release notes](https://github.com/saadeghi/daisyui/releases)
- [Changelog](https://github.com/saadeghi/daisyui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/saadeghi/daisyui/compare/v4.10.3...v4.10.5)

---
updated-dependencies:
- dependency-name: daisyui
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-03 12:33:48 +01:00
dependabot[bot] 7022aa68e1
Bump @types/node from 20.12.7 to 20.12.8 in /npm (#2648)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.7 to 20.12.8.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 09:16:19 +01:00
dependabot[bot] 49c611a09a
Bump @aws-sdk/client-dynamodb from 3.565.0 to 3.567.0 in /npm (#2649)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.565.0 to 3.567.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.567.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 09:16:14 +01:00
dependabot[bot] a8c14dec7a
Bump @aws-sdk/credential-providers from 3.565.0 to 3.567.0 in /npm (#2650)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.565.0 to 3.567.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.567.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 09:04:00 +01:00
dependabot[bot] 3ee670f057
Bump @types/node from 20.12.7 to 20.12.8 in /internal-ui (#2651)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.12.7 to 20.12.8.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 09:03:55 +01:00
dependabot[bot] 044f452945
Bump daisyui from 4.10.2 to 4.10.3 (#2652)
Bumps [daisyui](https://github.com/saadeghi/daisyui) from 4.10.2 to 4.10.3.
- [Release notes](https://github.com/saadeghi/daisyui/releases)
- [Changelog](https://github.com/saadeghi/daisyui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/saadeghi/daisyui/compare/v4.10.2...v4.10.3)

---
updated-dependencies:
- dependency-name: daisyui
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 09:03:51 +01:00
Deepak Prabhakara 5000983a36 Release 1.23.6 2024-04-30 22:32:49 +01:00
dependabot[bot] 886b855098
Bump @rollup/rollup-linux-x64-gnu from 4.17.1 to 4.17.2 in /internal-ui (#2647)
Bumps [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) from 4.17.1 to 4.17.2.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.17.1...v4.17.2)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-30 09:56:21 +01:00
Deepak Prabhakara 64d9b38ef7
updated deps (#2641) 2024-04-30 09:54:49 +01:00
Deepak Prabhakara 8fbc1e8db7
updated package-lock (#2629) 2024-04-29 16:14:39 +01:00
Utkarsh Mehta b98ccc68bc
feat: Stats route changes to return count of setup link & saml federations apps (#2627)
* feat: stats route updates to respond count of setup link & saml federations apps

* chore: Remove unused getCountByProductService method from SetupLinkController

* feat: Add validation for development mode connection limits

* chore: Update import path for validateDevelopmentModeLimits in directory-sync and sso-connection APIs

* refactor: update development mode limits validation in directory-sync and connections APIs

* feat: Update development mode limits validation in directory-sync and connections APIs
2024-04-29 14:40:01 +01:00
dependabot[bot] 1eb2147802
Bump @aws-sdk/credential-providers from 3.563.0 to 3.564.0 in /npm (#2631)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.563.0 to 3.564.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.564.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 12:26:35 +01:00
dependabot[bot] d18e92a20c
Bump @types/react from 18.3.0 to 18.3.1 in /internal-ui (#2636)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.3.0 to 18.3.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 12:26:24 +01:00
dependabot[bot] fcb746576f
Bump @aws-sdk/util-dynamodb from 3.563.0 to 3.564.0 in /npm (#2632)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.563.0 to 3.564.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.564.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 10:47:21 +01:00
dependabot[bot] 5cb196ea1d
Bump @tailwindcss/typography from 0.5.12 to 0.5.13 (#2633)
Bumps [@tailwindcss/typography](https://github.com/tailwindlabs/tailwindcss-typography) from 0.5.12 to 0.5.13.
- [Release notes](https://github.com/tailwindlabs/tailwindcss-typography/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss-typography/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.12...v0.5.13)

---
updated-dependencies:
- dependency-name: "@tailwindcss/typography"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 10:47:17 +01:00
dependabot[bot] 8d875ce14b
Bump @aws-sdk/client-dynamodb from 3.563.0 to 3.564.0 in /npm (#2630)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.563.0 to 3.564.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.564.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 10:46:45 +01:00
dependabot[bot] 2b491b67ba
Bump i18next from 23.11.2 to 23.11.3 (#2634)
Bumps [i18next](https://github.com/i18next/i18next) from 23.11.2 to 23.11.3.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.11.2...v23.11.3)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 10:46:39 +01:00
dependabot[bot] 61d8b0c2b0
Bump react from 18.3.0 to 18.3.1 (#2635)
Bumps [react](https://github.com/facebook/react/tree/HEAD/packages/react) from 18.3.0 to 18.3.1.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v18.3.1/packages/react)

---
updated-dependencies:
- dependency-name: react
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 10:46:35 +01:00
dependabot[bot] ade4466d26
Bump eslint-plugin-react-hooks from 4.6.1 to 4.6.2 in /internal-ui (#2637)
Bumps [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/HEAD/packages/eslint-plugin-react-hooks) from 4.6.1 to 4.6.2.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/HEAD/packages/eslint-plugin-react-hooks)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-hooks
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 10:46:26 +01:00
dependabot[bot] f3290bb0f7
Bump @rollup/rollup-linux-x64-gnu from 4.16.4 to 4.17.1 in /internal-ui (#2638)
Bumps [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) from 4.16.4 to 4.17.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.16.4...v4.17.1)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 10:46:22 +01:00
Deepak Prabhakara 12d6742dce
updated react (#2628)
* updated react

* updated logs-viewer
2024-04-28 00:05:55 +01:00
Deepak Prabhakara cdd984c64a updated node 2024-04-27 23:15:13 +01:00
Deepak Prabhakara 0be094d76d fixed default primaryColor 2024-04-27 23:13:27 +01:00
dependabot[bot] 413f68e45e
Bump eslint-plugin-react-hooks from 4.6.0 to 4.6.1 in /internal-ui (#2621)
Bumps [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/HEAD/packages/eslint-plugin-react-hooks) from 4.6.0 to 4.6.1.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/HEAD/packages/eslint-plugin-react-hooks)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-hooks
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-26 15:12:02 +01:00
dependabot[bot] 6e57c6f906
Bump @aws-sdk/util-dynamodb from 3.556.0 to 3.563.0 in /npm (#2623)
Bumps [@aws-sdk/util-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/util-dynamodb) from 3.556.0 to 3.563.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/util-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.563.0/packages/util-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/util-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-26 15:11:53 +01:00
dependabot[bot] fbd77b47e7
Bump @aws-sdk/client-dynamodb from 3.556.0 to 3.563.0 in /npm (#2624)
Bumps [@aws-sdk/client-dynamodb](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-dynamodb) from 3.556.0 to 3.563.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-dynamodb/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.563.0/clients/client-dynamodb)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-dynamodb"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-26 15:11:46 +01:00
dependabot[bot] 75c5637b3f
Bump release-it from 17.2.0 to 17.2.1 (#2620)
Bumps [release-it](https://github.com/release-it/release-it) from 17.2.0 to 17.2.1.
- [Release notes](https://github.com/release-it/release-it/releases)
- [Changelog](https://github.com/release-it/release-it/blob/main/CHANGELOG.md)
- [Commits](https://github.com/release-it/release-it/compare/17.2.0...17.2.1)

---
updated-dependencies:
- dependency-name: release-it
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-26 12:18:17 +01:00
dependabot[bot] 8559abfe34
Bump @types/react from 18.2.79 to 18.3.0 in /internal-ui (#2622)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.79 to 18.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-26 12:18:07 +01:00
dependabot[bot] 7dd0104471
Bump @googleapis/admin from 16.0.0 to 17.0.0 in /npm (#2625)
Bumps [@googleapis/admin](https://github.com/googleapis/google-api-nodejs-client) from 16.0.0 to 17.0.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/chat-v17.0.0/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/16.0.0...chat-v17.0.0)

---
updated-dependencies:
- dependency-name: "@googleapis/admin"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-26 12:17:52 +01:00
dependabot[bot] 52f5ea9b5d
Bump @aws-sdk/credential-providers from 3.556.0 to 3.563.0 in /npm (#2626)
Bumps [@aws-sdk/credential-providers](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/credential-providers) from 3.556.0 to 3.563.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-providers/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.563.0/packages/credential-providers)

---
updated-dependencies:
- dependency-name: "@aws-sdk/credential-providers"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-26 12:17:48 +01:00
Deepak Prabhakara 19d5671457 updated deployment 2024-04-25 18:10:56 +01:00
Deepak Prabhakara f10a8b91f1 Release 1.23.5 2024-04-25 17:44:11 +01:00
Deepak Prabhakara 663eca577f
fixed wrong response in dsync events (#2619) 2024-04-25 17:40:30 +01:00
Utkarsh Mehta 50aa00aec2
feat: Add deleteTracesByProduct method to AdminController (#2617)
* feat: Add deleteTracesByProduct method to AdminController

This commit adds a new method, deleteTracesByProduct, to the AdminController class in the npm/src/controller/admin.ts file. This method allows for the deletion of traces by product. It uses the getTracesByProduct method to retrieve traces in batches of 50 and deletes them using the tracerStore. The method is also implemented in the pages/api/v1/sso-traces/product.ts file as a DELETE handler.

* chore: Add DELETE handler for product API endpoint in product.ts file

* chore: Add DELETE handler for product API endpoint in product.ts file

* feat: Add countByProduct method to SSOTracer

This commit adds a new method, countByProduct, to the SSOTracer class in the npm/src/sso-tracer/index.ts file. This method allows for counting the number of traces by product. It uses the tracerStore's getCount method to retrieve the count based on the product name. The method is also implemented in the pages/api/v1/sso-traces/product/count.ts file as a GET handler.
2024-04-25 14:59:39 +01:00
Deepak Prabhakara b756388657 updated package-lock 2024-04-25 12:46:10 +01:00
Deepak Prabhakara c28011590d updated deployment 2024-04-25 09:50:15 +01:00
dependabot[bot] ad9aaab63b
Bump eslint-config-next from 14.2.2 to 14.2.3 (#2614)
Bumps [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) from 14.2.2 to 14.2.3.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v14.2.3/packages/eslint-config-next)

---
updated-dependencies:
- dependency-name: eslint-config-next
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-25 09:47:39 +01:00
dependabot[bot] d3c3c8727b
Bump formik from 2.4.5 to 2.4.6 (#2615)
Bumps [formik](https://github.com/jaredpalmer/formik) from 2.4.5 to 2.4.6.
- [Release notes](https://github.com/jaredpalmer/formik/releases)
- [Commits](https://github.com/jaredpalmer/formik/compare/formik@2.4.5...formik@2.4.6)

---
updated-dependencies:
- dependency-name: formik
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-25 09:47:34 +01:00
dependabot[bot] df35d3684d
Bump next from 14.2.2 to 14.2.3 (#2616)
Bumps [next](https://github.com/vercel/next.js) from 14.2.2 to 14.2.3.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v14.2.2...v14.2.3)

---
updated-dependencies:
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-25 09:47:30 +01:00
dependabot[bot] 6836859a5a
Bump @rollup/rollup-linux-x64-gnu from 4.16.3 to 4.16.4 in /internal-ui (#2613)
Bumps [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) from 4.16.3 to 4.16.4.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.16.3...v4.16.4)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-24 09:31:35 +01:00
185 changed files with 15887 additions and 9913 deletions

View File

@ -110,8 +110,12 @@ jobs:
image: 'amazon/dynamodb-local:latest'
ports:
- '8000:8000'
turso:
image: ghcr.io/tursodatabase/libsql-server:latest
ports:
- '8080:8080'
mocksaml:
image: boxyhq/mock-saml:1.2.0
image: boxyhq/mock-saml:1.3.9
ports:
- 4000:4000
env:
@ -266,7 +270,7 @@ jobs:
uses: anchore/sbom-action/publish-sbom@v0
with:
sbom-artifact-match: ".*\\.spdx$"
- name: Create NPM Pacakge SBOM Report [CycloneDx]
- name: Create NPM Package SBOM Report [CycloneDx]
uses: anchore/sbom-action@v0
with:
format: cyclonedx
@ -277,23 +281,23 @@ jobs:
with:
sbom-artifact-match: ".*\\.cyclonedx$"
- name: Download artifact for SPDX Report
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: actions/download-artifact@v3
with:
name: npm_sbom.spdx
- name: Download artifact for CycloneDx Report
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: actions/download-artifact@v3
with:
name: npm_sbom.cyclonedx
- name: Remove older SBOMs
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: rm -rf ./npm/sbom*.* || true
- name: Move SPDX Report
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: mv npm_sbom.spdx "./npm/sbom.spdx"
- name: Move CycloneDx Report
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: mv npm_sbom.cyclonedx "./npm/sbom.cyclonedx"
- name: Next Js Project SBOM Report [SPDX]
@ -317,21 +321,21 @@ jobs:
with:
sbom-artifact-match: ".*\\.cyclonedx$"
- name: Remove older SBOMs
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: rm -rf sbom*.* || true
- name: Download artifact for SPDX Report
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: actions/download-artifact@v3
with:
name: sbom.spdx
- name: Download artifact for CycloneDx Report
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: actions/download-artifact@v3
with:
name: sbom.cyclonedx
- name: Create SBOM Report [Docker][SPDX]
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: anchore/sbom-action@v0
with:
image: ${{ needs.ci.outputs.IMAGE_PATH }}:${{ needs.ci.outputs.PUBLISH_TAG }}
@ -339,12 +343,12 @@ jobs:
artifact-name: docker_sbom.spdx
upload-artifact-retention: 1
- name: Publish report [Docker][SPDX]
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: anchore/sbom-action/publish-sbom@v0
with:
sbom-artifact-match: ".*\\.spdx$"
- name: Create SBOM Report [Docker][CycloneDx]
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: anchore/sbom-action@v0
with:
image: ${{ needs.ci.outputs.IMAGE_PATH }}:${{ needs.ci.outputs.PUBLISH_TAG }}
@ -352,32 +356,32 @@ jobs:
artifact-name: docker_sbom.cyclonedx
upload-artifact-retention: 1
- name: Publish report [Docker][CycloneDx]
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: anchore/sbom-action/publish-sbom@v0
with:
sbom-artifact-match: ".*\\.cyclonedx$"
- name: Download artifact for SPDX Report [Docker]
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: actions/download-artifact@v3
with:
name: docker_sbom.spdx
- name: Download artifact for CycloneDx Report [Docker]
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
uses: actions/download-artifact@v3
with:
name: docker_sbom.cyclonedx
- name: Create/Clear folder [Docker]
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: mkdir -p ./_docker/ && rm -rf ./_docker/*.* || true
- name: Move Report & cleanup
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: |
mv docker_sbom.spdx "./_docker/sbom.spdx" || true
mv docker_sbom.cyclonedx "./_docker/sbom.cyclonedx" || true
- name: ORAS Setup
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: |
ORAS_VERSION="v0.8.1"
ORAS_FILENAME="oras_0.8.1_linux_amd64.tar.gz"
@ -386,7 +390,7 @@ jobs:
tar -xvf "${ORAS_FILENAME}" -C oras_install
- name: Push SBOM reports to GitHub Container Registry & Sign the sbom images
if: github.ref == 'refs/heads/release'
if: github.ref == 'refs/heads/release-disabled'
run: |
result=$(./oras_install/oras push ghcr.io/${{github.repository}}/sbom${{ needs.ci.outputs.IMAGE_SUFFIX }}:service-${{ needs.ci.outputs.NPM_VERSION }} ./sbom.*)
ORAS_DIGEST=$(echo $result | grep -oE 'sha256:[a-f0-9]{64}')

3
.gitignore vendored
View File

@ -47,4 +47,5 @@ _dev/docker/dynamodb/shared-local-instance.db
public/terminus/sprites.png
**/.tap/**
internal-ui/dist
internal-ui/dist
_dev/docker/libsql/iku.db

View File

@ -15,5 +15,4 @@ module.exports = {
},
},
],
// importOrderSeparation: true,
};

View File

@ -1,5 +1,7 @@
{
"hooks": {},
"hooks": {
"after:bump": "npm run swagger-jsdoc"
},
"git": {
"changelog": "git log --pretty=format:\"* %s (%h)\" ${from}...${to}",
"requireCleanWorkingDir": true,

View File

@ -1,4 +1,4 @@
ARG NODEJS_IMAGE=node:20.12.1-alpine3.19
ARG NODEJS_IMAGE=node:20.13.1-alpine3.19
FROM --platform=$BUILDPLATFORM $NODEJS_IMAGE AS base
# Install dependencies only when needed

View File

@ -51,3 +51,14 @@ services:
volumes:
- './docker/dynamodb:/home/dynamodblocal/data'
working_dir: /home/dynamodblocal
turso:
image: ghcr.io/tursodatabase/libsql-server:latest
platform: linux/amd64
ports:
- '8080:8080'
- '5001:5001'
# environment:
# - SQLD_NODE=primary
command: '/bin/sqld --enable-http-console'
volumes:
- ./docker/libsql:/var/lib/sqld

View File

@ -40,7 +40,7 @@ export const Sidebar = ({ isOpen, setIsOpen }: SidebarProps) => {
href: '/admin/sso-connection',
text: t('enterprise_sso'),
icon: SSOLogo,
active: asPath.includes('/admin/sso-connection') || asPath.includes('/admin/federated-saml'),
active: asPath.includes('/admin/sso-connection'),
items: [
{
href: '/admin/sso-connection',
@ -54,14 +54,22 @@ export const Sidebar = ({ isOpen, setIsOpen }: SidebarProps) => {
active: asPath.includes('/admin/sso-connection/setup-link'),
},
{
href: '/admin/federated-saml',
text: t('saml_federation'),
active: asPath.includes('/admin/federated-saml'),
href: '/admin/sso-traces',
text: t('bui-traces-title'),
active: asPath.includes('/admin/sso-traces'),
},
],
},
{
href: '/admin/identity-federation',
text: t('identity_federation'),
icon: SSOLogo,
active: asPath.includes('/admin/identity-federation'),
items: [
{
href: '/admin/sso-tracer',
text: t('bui-tracer-title'),
active: asPath.includes('/admin/sso-tracer'),
href: '/admin/identity-federation',
text: t('apps'),
active: asPath.includes('/admin/identity-federation'),
},
],
},

View File

@ -3,7 +3,7 @@ import styles from './BlocklyComponent.module.css';
import { useEffect, useRef, createRef } from 'react';
import { useTranslation } from 'next-i18next';
import Blockly from 'blockly/core';
import * as Blockly from 'blockly/core';
import 'blockly/blocks';
import { maskSetup } from '@components/terminus/blocks/customblocks';
import locale from 'blockly/msg/en';
@ -35,11 +35,11 @@ function BlocklyComponent(props) {
const uploadModel = async () => {
const domToPretty = modelToXML();
const cueModel = generateModel(primaryWorkspace.current, roles);
const model = generateModel(primaryWorkspace.current, roles);
const body = {
cue_schema: cueModel,
blockly_schema: domToPretty,
model: model,
blockly_model: domToPretty,
};
const requestOptions = {

View File

@ -1,45 +1,46 @@
import Blockly from 'blockly/core';
import * as Blockly from 'blockly/core';
// TODO wire with CUE configuration files
// TODO extract prefixes
function getEncryption() {
return [
['AES_256', 'crypto.#EnAES_256'],
['FPE_FF1', 'crypto.#EnFPE_FF1'],
['FPE_FF3_1', 'crypto.#EnFPE_FF3_1'],
['NoEncryption', 'crypto.#EnNoEncryption'],
// ['RSA_2048', 'crypto.#EnRSA_2048'],
// ['Blowfish_448', 'crypto.#EnBlowfish_448'],
// ['FPE', 'crypto.#EnFPE'],
// ['B64', 'crypto.#EnB64'],
['AES_256', 'AES_256'],
['FPE_FF1', 'FPE_FF1'],
['FPE_FF3_1', 'FPE_FF3_1'],
['NoEncryption', 'NoEncryption'],
// ['RSA_2048', 'RSA_2048'],
// ['Blowfish_448', 'Blowfish_448'],
// ['FPE', 'FPE'],
// ['B64', 'B64'],
];
}
function getMasks() {
return [
['Clear', 'masking.#MClear'],
['Generic', 'masking.#MGeneric'],
['Redact', 'masking.#MRedact'],
['Password', 'masking.#MPassword'],
['Name', 'masking.#MName'],
['Address', 'masking.#MAddress'],
['Email', 'masking.#MEmail'],
['Mobile', 'masking.#MMobile'],
['Telephone', 'masking.#MTelephone'],
['ID', 'masking.#MID'],
['CreditCard', 'masking.#MCreditCard'],
['Struct', 'masking.#MStruct'],
['URL', 'masking.#MURL'],
['Clear', 'Clear'],
['Redact', 'Redact'],
['Generic', 'Generic'],
['Password', 'Password'],
['Name', 'Name'],
['Address', 'Address'],
['Email', 'Email'],
['Mobile', 'Mobile'],
['Telephone', 'Telephone'],
['ID', 'ID'],
['CreditCard', 'CreditCard'],
['Struct', 'Struct'],
['URL', 'URL'],
];
}
function getPredefinedDataTypes() {
return [
['Letters', 'defs.#Letters'],
['LettersWithSpaces', 'defs.#LettersWithSpaces'],
['Alphanumerical', 'defs.#Alphanumerical'],
['AlphanumericalWithSpaces', 'defs.#AlphanumericalWithSpaces'],
['AlphanumericalNotAccented', 'defs.#AlphanumericalNotAccented'],
['AlphanumericalNotAccentedWithSpaces', 'defs.#AlphanumericalNotAccentedWithSpaces'],
['SimpleDate (2006-11-24)', 'defs.#SimpleDateFormat'],
['String', 'String'],
['Letters', 'Letters'],
['LettersWithSpaces', 'LettersWithSpaces'],
['Alphanumerical', 'Alphanumerical'],
['AlphanumericalWithSpaces', 'AlphanumericalWithSpaces'],
['AlphanumericalNotAccented', 'AlphanumericalNotAccented'],
['AlphanumericalNotAccentedWithSpaces', 'AlphanumericalNotAccentedWithSpaces'],
['SimpleDate (2006-11-24)', 'Date'],
];
}
@ -132,32 +133,6 @@ Blockly.Blocks['data_object_field_type'] = {
this.jsonInit({
type: 'data_object_field_type',
message0: 'type %1 %2',
args0: [
{
type: 'field_input',
name: 'object_type',
text: 'string',
},
{
type: 'input_value',
name: 'input',
check: ['Boolean', 'String'],
},
],
output: null,
colour: 230,
tooltip: '',
helpUrl: '',
});
// this.setStyle('loop_blocks');
},
};
Blockly.Blocks['data_object_field_default_types'] = {
init: function () {
this.jsonInit({
type: 'data_object_field_default_types',
message0: 'type %1 %2',
args0: [
{
type: 'field_dropdown',
@ -167,7 +142,7 @@ Blockly.Blocks['data_object_field_default_types'] = {
{
type: 'input_value',
name: 'input',
check: ['Boolean', 'String'],
check: 'String',
},
],
output: null,
@ -193,7 +168,7 @@ Blockly.Blocks['data_object_field_encryption'] = {
{
type: 'input_value',
name: 'input',
check: ['Boolean', 'String'],
check: 'String',
},
],
output: null,
@ -204,26 +179,27 @@ Blockly.Blocks['data_object_field_encryption'] = {
// this.setStyle('loop_blocks');
},
};
Blockly.Blocks['data_object_field_mask'] = {
init: function () {
this.jsonInit({
type: 'data_object_field_mask',
message0: 'mask (Admin:%1) (Member:%2) %3',
message0: 'mask (admin:%1) (member:%2) %3',
args0: [
{
type: 'field_dropdown',
name: 'object_type_ADMIN',
name: 'object_type_admin',
options: getMasks(),
},
{
type: 'field_dropdown',
name: 'object_type_MEMBER',
name: 'object_type_member',
options: getMasks(),
},
{
type: 'input_value',
name: 'object_type',
check: ['Boolean', 'String'],
check: 'String',
},
],
output: null,
@ -234,16 +210,11 @@ Blockly.Blocks['data_object_field_mask'] = {
},
};
const capitalize = (s: string) => {
if (typeof s !== 'string') return '';
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
};
export const maskSetup = (roles: string[]) => {
let maskMessage = 'mask (';
const args: any[] = [];
for (let i = 0; i < roles.length; i++) {
maskMessage += `${capitalize(roles[i])}:%${i + 1}`;
maskMessage += `${roles[i]}:%${i + 1}`;
if (i < roles.length - 1) {
maskMessage += ') (';
}
@ -263,7 +234,7 @@ export const maskSetup = (roles: string[]) => {
{
type: 'input_value',
name: 'object_type',
check: ['Boolean', 'String'],
check: 'String',
},
],
output: null,

View File

@ -7,18 +7,6 @@ let currentObject, currentField;
const IGNORE_FIELDS = [CONST_OBJ_GLB_ENCR];
// TODO this must come from CUE and the regexp are hacked here for generation
const simpleRegex = '^[a-zA-Z]+$';
const regexMap = {
'defs.#Letters': simpleRegex,
'defs.#LettersWithSpaces': simpleRegex,
'defs.#Alphanumerical': simpleRegex,
'defs.#AlphanumericalWithSpaces': simpleRegex,
'defs.#AlphanumericalNotAccented': simpleRegex,
'defs.#AlphanumericalNotAccentedWithSpaces': simpleRegex,
'defs.#SimpleDateFormat': '^20[0-9]{2}-[0-1][1-2]-[0-2][1-8]$', // regex restricted.
};
export const generateModel = (workspace, roles: string[]) => {
ObjectMap.clear();
@ -28,79 +16,45 @@ export const generateModel = (workspace, roles: string[]) => {
currentField[2 + i] = objName; // mask
}
javascriptGenerator.statementToCode(block, 'input', javascriptGenerator.ORDER_NONE);
javascriptGenerator.statementToCode(block, 'input');
return '';
};
// trigger the BLOCKLY processing which will run our custom code generation
javascriptGenerator.workspaceToCode(workspace);
const ret = generateCUEStructure(roles);
const ret = generateStructure(roles);
// add specific BoxyHQ imports
return `
EncryptedDefinitions: ${JSON.stringify(ret[1])}
${ret[0]}
`;
return JSON.stringify(ret);
};
// Rudimentary way of generating a CUE file
const generateCUEStructure = (roles: string[]) => {
let defs = ``;
const encrObjects = [];
const generateStructure = (roles: string[]) => {
const model: any = {};
for (const [key, value] of Object.entries(Object.fromEntries(ObjectMap))) {
encrObjects.push(key as never);
model.name = key;
model.attributes = {};
const valuesMap = Object.fromEntries(value as any);
// DEFINITIONS
let definitions = ``;
for (const [field, values] of Object.entries(valuesMap)) {
const rolesMap = {};
for (let i = 0; i < roles.length; i++) {
rolesMap[roles[i]] = values[i + 2];
}
model.attributes[field] = {
type: values[0],
encryption: values[1],
masking: {
roles: rolesMap,
},
};
if (IGNORE_FIELDS.includes(field)) {
continue;
}
definitions += `\n\t\t\t${field}: ${values[0]}`;
let pattern = regexMap[values[0]];
if (pattern == null) {
pattern = '.*';
}
}
// ENCRYPTION
let encryption = ``;
if (valuesMap[CONST_OBJ_GLB_ENCR] != null) {
encryption += `${valuesMap[CONST_OBJ_GLB_ENCR]}`;
} else {
for (const [field, values] of Object.entries(valuesMap)) {
encryption += `\n\t\t\t${field}: ${values[1]}`;
}
encryption = `{ ${encryption}
}`;
}
// MASKS
let maskString = '';
for (const [field, values] of Object.entries(valuesMap)) {
if (IGNORE_FIELDS.includes(field)) {
continue;
}
let index = 2;
for (const role of roles) {
const maskKey = `#Mask_${role.toLowerCase()}`;
const maskVal = `\n\t\t\t${field}: ${values.length > index ? values[index++] : 'masking.#MRedact'}`;
maskString += `\n${maskKey}: { ${maskVal}
}`;
}
}
const objectOutput = `\n#${key}: {
#Definition: { ${definitions}
}
#Encryption: ${encryption}${maskString}
}`;
defs += objectOutput;
}
return [defs, encrObjects];
return model;
};
javascriptGenerator['data_object_wrapper'] = function (block) {
@ -130,7 +84,7 @@ javascriptGenerator['data_object_field_wrapper'] = function (block) {
currentField = new Array(3);
currentObject.set(objectName, currentField);
javascriptGenerator.statementToCode(block, 'input', javascriptGenerator.ORDER_NONE);
javascriptGenerator.statementToCode(block, 'input');
return '';
};
@ -138,21 +92,19 @@ javascriptGenerator['data_object_field_wrapper'] = function (block) {
javascriptGenerator['data_object_field_type'] = function (block) {
const objectName = block.getFieldValue('object_type');
currentField[0] = objectName; // type
currentField[2] = 'masking.#MRedact'; // mask
currentField[3] = 'masking.#MRedact'; // mask
currentField[2] = 'Redact'; // mask
currentField[3] = 'Redact'; // mask
javascriptGenerator.statementToCode(block, 'input', javascriptGenerator.ORDER_NONE);
javascriptGenerator.statementToCode(block, 'input');
return '';
};
javascriptGenerator['data_object_field_default_types'] = javascriptGenerator['data_object_field_type'];
javascriptGenerator['data_object_field_encryption'] = function (block) {
const objectName = block.getFieldValue('object_type');
currentField[1] = objectName; // encryption
javascriptGenerator.statementToCode(block, 'input', javascriptGenerator.ORDER_NONE);
javascriptGenerator.statementToCode(block, 'input');
return '';
};

6
e2e/api/helpers/api.ts Normal file
View File

@ -0,0 +1,6 @@
export const options = {
extraHTTPHeaders: {
Authorization: `Api-Key ${process.env.JACKSON_API_KEYS}`,
'Content-Type': 'application/json',
},
};

View File

@ -1,4 +1,5 @@
import { expect, type APIRequestContext } from '@playwright/test';
import { Directory } from 'npm/src';
const directoryBase = {
tenant: 'api-boxyhq',
@ -9,8 +10,8 @@ const directoryBase = {
export const directoryPayload = {
...directoryBase,
webhook_url: 'https://example.com',
webhook_secret: 'secret',
webhook_url: '',
webhook_secret: '',
};
export const directoryExpected = {
@ -22,7 +23,19 @@ export const directoryExpected = {
secret: expect.any(String),
endpoint: expect.any(String),
},
webhook: { endpoint: 'https://example.com', secret: 'secret' },
webhook: { endpoint: '', secret: '' },
};
export const updateDirectory = async (request: APIRequestContext, directory: Directory, data: any) => {
const response = await request.patch(`/api/v1/dsync/${directory.id}`, {
data,
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
const { data: updatedDirectory } = await response.json();
return updatedDirectory;
};
export const createDirectory = async (request: APIRequestContext, payload: typeof directoryPayload) => {
@ -59,9 +72,43 @@ export const getDirectory = async (
return data;
};
export const getDirectoryByProduct = async (request: APIRequestContext, { product }: { product: string }) => {
const response = await request.get('/api/v1/dsync/product', {
params: {
product,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
const { data } = await response.json();
return data;
};
export const deleteDirectory = async (request: APIRequestContext, directoryId: string) => {
const response = await request.delete(`/api/v1/dsync/${directoryId}`);
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
};
export const getDirectoryEvents = async (
request: APIRequestContext,
params: {
tenant?: string;
product?: string;
directoryId: string;
}
) => {
const response = await request.get(`/api/v1/dsync/events`, {
params,
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
const { data } = await response.json();
return data;
};

View File

@ -1,8 +1,10 @@
import { expect, type APIRequestContext } from '@playwright/test';
import type { Directory } from '@boxyhq/saml-jackson';
import type { Directory, Group } from '@boxyhq/saml-jackson';
import { scimOpUrl } from './utils';
export const createGroup = async (request: APIRequestContext, directory: Directory, group: any) => {
const response = await request.post(`${directory.scim.path}/Groups`, {
const scimOpEndpoint = scimOpUrl(directory, 'Groups');
const response = await request.post(scimOpEndpoint, {
data: group,
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
@ -15,6 +17,39 @@ export const createGroup = async (request: APIRequestContext, directory: Directo
return await response.json();
};
export const addGroupMember = async (
request: APIRequestContext,
directory: Directory,
group: Group,
member: string
) => {
const scimOpEndpoint = scimOpUrl(directory, `Groups/${group.id}`);
const response = await request.patch(scimOpEndpoint, {
data: {
Operations: [
{
action: 'addGroupMember',
op: 'add',
path: 'members',
value: [
{
value: member,
},
],
},
],
},
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
return await response.json();
};
export const getGroupByDisplayName = async (
request: APIRequestContext,
directory: Directory,
@ -47,3 +82,57 @@ export const getGroupById = async (request: APIRequestContext, directory: Direct
return await response.json();
};
export const getGroupsByDirectoryId = async (request: APIRequestContext, directory: Directory) => {
const response = await request.get(`${directory.scim.path}/Groups`, {
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
const data = await response.json();
return data.Resources;
};
export const deleteGroup = async (request: APIRequestContext, directory: Directory, groupId: string) => {
const scimOpEndpoint = scimOpUrl(directory, `Groups/${groupId}`);
const response = await request.delete(scimOpEndpoint, {
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
return await response.json();
};
export const updateGroupName = async (
request: APIRequestContext,
directory: Directory,
groupId: string,
newName: string
) => {
const scimOpEndpoint = scimOpUrl(directory, `Groups/${groupId}`);
const response = await request.patch(scimOpEndpoint, {
data: {
Operations: [
{
op: 'replace',
path: 'displayName',
value: newName,
},
],
},
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
};

2
e2e/api/helpers/index.ts Normal file
View File

@ -0,0 +1,2 @@
export * from './users';
export * from './groups';

22
e2e/api/helpers/oauth.ts Normal file
View File

@ -0,0 +1,22 @@
import { type APIRequestContext, expect } from '@playwright/test';
import { OAuthReq } from 'npm/src';
// Make oauth autorize request
export const oauthAuthorize = async (request: APIRequestContext, data: OAuthReq, isFailure = false) => {
try {
const response = await request.post('/api/oauth/authorize', {
data,
});
expect(response.ok()).toBe(true);
if (!isFailure) {
expect(response.status()).toBe(302);
}
} catch (ex: any) {
if (isFailure) {
expect(ex.message).toBeDefined();
} else {
throw ex;
}
}
};

View File

@ -71,6 +71,20 @@ export const getConnection = async (
return await response.json();
};
// Get connections by product
export const getConnectionByProduct = async (request: APIRequestContext, product: string) => {
const response = await request.get('/api/v1/sso/product', {
params: {
product,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
return await response.json();
};
// Delete a connection
export const deleteConnection = async (
request: APIRequestContext,
@ -86,3 +100,57 @@ export const deleteConnection = async (
expect(response.ok()).toBe(true);
expect(response.status()).toBe(204);
};
// get a sso trace by id
export const getSSOTraceById = async (request: APIRequestContext, id: string) => {
const response = await request.get('/api/v1/sso-traces', {
params: {
id,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
return await response.json();
};
// get sso traces by product
export const getSSOTracesByProduct = async (request: APIRequestContext, product: string) => {
const response = await request.get('/api/v1/sso-traces/product', {
params: {
product,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
return await response.json();
};
// Delete sso traces by product
export const deleteSSOTraces = async (request: APIRequestContext, product: string) => {
const response = await request.delete('/api/v1/sso-traces/product', {
params: {
product,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(204);
};
// Count sso traces by product
export const countSSOTracesByProduct = async (request: APIRequestContext, product: string) => {
const response = await request.get('/api/v1/sso-traces/product/count', {
params: {
product,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
return await response.json();
};

View File

@ -1,11 +1,14 @@
import { expect, type APIRequestContext } from '@playwright/test';
import type { Directory } from '@boxyhq/saml-jackson';
import users from '../../../npm/test/dsync/data/users';
import { scimOpUrl } from './utils';
type User = (typeof users)[0];
type User = Partial<(typeof users)[0]>;
export const createUser = async (request: APIRequestContext, directory: Directory, user: User) => {
const response = await request.post(`${directory.scim.endpoint}/Users`, {
const scimOpEndpoint = scimOpUrl(directory, 'Users');
const response = await request.post(scimOpEndpoint, {
data: user,
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
@ -18,8 +21,38 @@ export const createUser = async (request: APIRequestContext, directory: Director
return await response.json();
};
export const updateUser = async (
request: APIRequestContext,
directory: Directory,
userId: string,
updatedUser: any,
isPatch: boolean
) => {
const scimOpEndpoint = scimOpUrl(directory, `Users/${userId}`);
const response = isPatch
? await request.patch(scimOpEndpoint, {
data: updatedUser,
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},
})
: await request.put(scimOpEndpoint, {
data: updatedUser,
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
return await response.json();
};
export const getUser = async (request: APIRequestContext, directory: Directory, userName: string) => {
const response = await request.get(`${directory.scim.path}/Users`, {
const scimOpEndpoint = scimOpUrl(directory, 'Users');
const response = await request.get(scimOpEndpoint, {
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},
@ -35,7 +68,9 @@ export const getUser = async (request: APIRequestContext, directory: Directory,
};
export const deleteUser = async (request: APIRequestContext, directory: Directory, userId: string) => {
const response = await request.delete(`${directory.scim.path}/Users/${userId}`, {
const scimOpEndpoint = scimOpUrl(directory, `Users/${userId}`);
const response = await request.delete(scimOpEndpoint, {
headers: {
Authorization: `Bearer ${directory.scim.secret}`,
},

10
e2e/api/helpers/utils.ts Normal file
View File

@ -0,0 +1,10 @@
import type { Directory } from '@boxyhq/saml-jackson';
export function scimOpUrl(directory: Directory, opPath: string) {
let endpoint = `${directory.scim.endpoint}/${opPath}`;
if (directory.type === 'azure-scim-v2') {
const [_main, aadOpts] = directory.scim.endpoint!.split('?');
endpoint = `${_main}${opPath}?${aadOpts}`;
}
return endpoint;
}

View File

@ -4,13 +4,9 @@ import { createUser, getUser } from '../../helpers/users';
import { createGroup, getGroupByDisplayName, getGroupById } from '../../helpers/groups';
import groups from '../../../../npm/test/dsync/data/groups';
import users from '../../../../npm/test/dsync/data/users';
import { options } from '../../helpers/api';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
const { tenant, product } = { ...directoryPayload, tenant: 'api-boxyhq-1' };

View File

@ -2,13 +2,9 @@ import { test, expect } from '@playwright/test';
import users from '../../../../npm/test/dsync/data/users';
import { createDirectory, deleteDirectory, directoryPayload, getDirectory } from '../../helpers/directories';
import { createUser, getUser } from '../../helpers/users';
import { options } from '../../helpers/api';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
const { tenant, product } = { ...directoryPayload, tenant: 'api-boxyhq-2' };

View File

@ -5,14 +5,11 @@ import {
directoryExpected,
directoryPayload,
getDirectory,
getDirectoryByProduct,
} from '../../helpers/directories';
import { options } from '../../helpers/api';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
const { tenant, product } = directoryPayload;
@ -25,6 +22,9 @@ test.beforeAll(async ({ request }) => {
test.afterAll(async ({ request }) => {
const [directory] = await getDirectory(request, { tenant, product });
if (!directory) {
return;
}
await deleteDirectory(request, directory.id);
});
@ -157,3 +157,15 @@ test.describe('PATCH /api/v1/dsync/{directoryId}', () => {
});
});
});
test.describe('GET /api/v1/dsync/product', () => {
test('should be able to get a directory by product', async ({ request }) => {
let directories = await getDirectoryByProduct(request, { product });
expect(directories.length).toBe(1);
await deleteDirectory(request, directories[0].id);
directories = await getDirectoryByProduct(request, { product });
expect(directories.length).toBe(0);
});
});

View File

@ -0,0 +1,97 @@
import { test, expect } from '@playwright/test';
import {
createDirectory,
deleteDirectory,
directoryPayload,
getDirectory,
getDirectoryEvents,
updateDirectory,
} from '../../helpers/directories';
import groups from '@boxyhq/saml-jackson/test/dsync/data/groups';
import { addGroupMember, createGroup } from '../../helpers/groups';
import { options } from '../../helpers/api';
test.use(options);
const { tenant, product } = { ...directoryPayload, tenant: 'api-boxyhq-3' };
const memberId = 'member1';
test.beforeAll(async ({ request }) => {
let directory = await createDirectory(request, {
...directoryPayload,
webhook_url: 'https://example.com',
webhook_secret: 'secret',
tenant,
});
directory = await updateDirectory(request, directory, {
log_webhook_events: true,
});
const group = await createGroup(request, directory, groups[0]);
await addGroupMember(request, directory, group, memberId);
});
test.afterAll(async ({ request }) => {
const [directory] = await getDirectory(request, { tenant, product });
await deleteDirectory(request, directory.id);
});
test.describe('GET /api/v1/dsync/events', () => {
test('should be able to get list of events from a directory', async ({ request }) => {
const [directory] = await getDirectory(request, { tenant, product });
// Get events using tenant, product & directoryId
const data = await getDirectoryEvents(request, { tenant, product, directoryId: directory.id });
expect(data.length).toBe(2);
});
});
test.describe('GET /api/v1/dsync/events/:event', () => {
test('should be able to delete all the events from directory', async ({ request }) => {
const [directory] = await getDirectory(request, { tenant, product });
// Get events using directoryId
const events = await getDirectoryEvents(request, {
directoryId: directory.id,
});
const response = await request.get(`/api/v1/dsync/events/${events[0].id}`, {
params: {
tenant,
product,
directoryId: directory.id,
},
});
const { data: event } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(event.status_code).toBe(200);
});
});
test.describe('DELETE /api/v1/dsync/events', () => {
test('should be able to delete all the events from directory', async ({ request }) => {
const [directory] = await getDirectory(request, { tenant, product });
const response = await request.delete(`/api/v1/dsync/events`, {
params: {
directoryId: directory.id,
},
});
const events = await getDirectoryEvents(request, {
tenant,
product,
directoryId: directory.id,
});
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(events.length).toBe(0);
});
});

View File

@ -0,0 +1,51 @@
import { test, expect } from '@playwright/test';
import { createDirectory, deleteDirectory, directoryPayload, getDirectory } from '../../helpers/directories';
import groups from '@boxyhq/saml-jackson/test/dsync/data/groups';
import { addGroupMember, createGroup, getGroupsByDirectoryId } from '../../helpers/groups';
import { options } from '../../helpers/api';
test.use(options);
const { tenant, product } = { ...directoryPayload, tenant: 'api-boxyhq-3' };
const memberId = 'member1';
test.beforeAll(async ({ request }) => {
const directory = await createDirectory(request, {
...directoryPayload,
tenant,
});
const group = await createGroup(request, directory, groups[0]);
await addGroupMember(request, directory, group, memberId);
});
test.afterAll(async ({ request }) => {
const [directory] = await getDirectory(request, { tenant, product });
await deleteDirectory(request, directory.id);
});
test.describe('GET /api/v1/dsync/groups/:id/members', () => {
test('should be able to get a group members from a directory', async ({ request }) => {
const [directory] = await getDirectory(request, { tenant, product });
const groups = await getGroupsByDirectoryId(request, directory);
const response = await request.get(`/api/v1/dsync/groups/${groups[0].id}/members`, {
params: {
tenant,
product,
},
});
const { data: directoryMembers } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(directoryMembers.length).toBe(1);
expect(directoryMembers).toMatchObject([
{
user_id: memberId,
},
]);
});
});

View File

@ -2,13 +2,9 @@ import { test, expect } from '@playwright/test';
import { createDirectory, deleteDirectory, directoryPayload, getDirectory } from '../../helpers/directories';
import groups from '@boxyhq/saml-jackson/test/dsync/data/groups';
import { createGroup } from '../../helpers/groups';
import { options } from '../../helpers/api';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
const { tenant, product } = { ...directoryPayload, tenant: 'api-boxyhq-3' };

View File

@ -1,14 +1,10 @@
import { test, expect } from '@playwright/test';
import { options } from '../../helpers/api';
const tenant = 'tenant-1';
const product = 'product-1';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
// POST /api/v1/dsync/setuplinks
test('create the setup link', async ({ request }) => {

View File

@ -2,13 +2,9 @@ import { test, expect } from '@playwright/test';
import users from '../../../../npm/test/dsync/data/users';
import { createDirectory, deleteDirectory, directoryPayload, getDirectory } from '../../helpers/directories';
import { createUser } from '../../helpers/users';
import { options } from '../../helpers/api';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
const { tenant, product } = { ...directoryPayload, tenant: 'api-boxyhq-4' };

View File

@ -1,123 +0,0 @@
import { test, expect } from '@playwright/test';
import { SAMLFederationApp } from '@boxyhq/saml-jackson';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
const expectedApp = {
name: 'Test App',
tenant: 'api-boxyhq',
product: 'api-saml-jackson',
id: expect.any(String),
entityId: 'https://boxyhq.com/entity-id',
acsUrl: 'https://boxyhq.com/acs',
};
let app = {} as SAMLFederationApp;
test.beforeAll(async ({ request }) => {
const response = await request.post('/api/v1/federated-saml', {
data: {
...expectedApp,
},
});
app = (await response.json()).data;
expect(response.ok()).toBe(true);
expect(response.status()).toBe(201);
});
test.describe('GET /api/v1/federated-saml', () => {
test('Fetch app by id', async ({ request }) => {
const response = await request.get(`/api/v1/federated-saml?id=${app?.id}`);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject(app);
});
test('Fetch app by tenant and product', async ({ request }) => {
const response = await request.get(
`/api/v1/federated-saml?tenant=${app?.tenant}&product=${app?.product}`
);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject(app);
});
test('Fetch app by product', async ({ request }) => {
const response = await request.get(`/api/v1/federated-saml/product?product=${app?.product}`);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject([app]);
});
});
test.describe('PATCH /api/v1/federated-saml', () => {
test('Update app by id', async ({ request }) => {
const response = await request.patch(`/api/v1/federated-saml`, {
data: {
id: app?.id,
name: 'Updated App',
},
});
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject({
...app,
name: 'Updated App',
});
});
test('Update app by tenant and product', async ({ request }) => {
const response = await request.patch(`/api/v1/federated-saml`, {
data: {
id: app?.id,
name: 'Updated App 2',
},
});
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject({
...app,
name: 'Updated App 2',
});
});
});
test.describe('DELETE /api/v1/federated-saml', () => {
test('Delete app by id', async ({ request }) => {
const response = await request.delete(`/api/v1/federated-saml?id=${app?.id}`);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject({});
// Confirm app is deleted
const response2 = await request.get(`/api/v1/federated-saml?id=${app?.id}`);
expect(response2.ok()).toBe(false);
expect(response2.status()).toBe(404);
});
});

View File

@ -0,0 +1,175 @@
import { test, expect } from '@playwright/test';
import { IdentityFederationApp } from '@boxyhq/saml-jackson';
import { options } from '../../helpers/api';
test.use(options);
const expectedApp = {
name: 'Test App',
tenant: 'api-boxyhq',
product: 'api-saml-jackson',
id: expect.any(String),
entityId: 'https://boxyhq.com/entity-id',
acsUrl: 'https://boxyhq.com/acs',
};
const expectedApp1 = {
name: 'Test App1',
tenant: 'api-boxyhq-1',
product: 'api-saml-jackson-1',
id: expect.any(String),
entityId: 'https://boxyhq.com/entity-id-1',
acsUrl: 'https://boxyhq.com/acs-1',
};
const newUrlPath = 'identity-federation';
const oldUrlPath = 'federated-saml';
let app = {} as IdentityFederationApp;
let app1 = {} as IdentityFederationApp;
const beforeAll = async (urlPath, request) => {
const currApp = urlPath === oldUrlPath ? expectedApp : expectedApp1;
const response = await request.post(`/api/v1/${urlPath}`, {
data: {
...currApp,
},
});
const localApp = (await response.json()).data;
expect(response.ok()).toBe(true);
expect(response.status()).toBe(201);
return localApp;
};
test.beforeAll(async ({ request }) => {
app = await beforeAll(oldUrlPath, request);
app1 = await beforeAll(newUrlPath, request);
});
const testGETById = async (urlPath, request) => {
const currApp = urlPath === oldUrlPath ? app : app1;
const response = await request.get(`/api/v1/${urlPath}?id=${currApp?.id}`);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject(currApp);
};
const testGETByTenantProduct = async (urlPath, request) => {
const currApp = urlPath === oldUrlPath ? app : app1;
const response = await request.get(
`/api/v1/${urlPath}?tenant=${currApp?.tenant}&product=${currApp?.product}`
);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject(currApp);
};
const testGETByProduct = async (urlPath, request) => {
const currApp = urlPath === oldUrlPath ? app : app1;
const response = await request.get(`/api/v1/${urlPath}/product?product=${currApp?.product}`);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject([currApp]);
};
test.describe('GET /api/v1/identity-federation', () => {
test('Fetch app by id', async ({ request }) => {
await testGETById(oldUrlPath, request);
await testGETById(newUrlPath, request);
});
test('Fetch app by tenant and product', async ({ request }) => {
await testGETByTenantProduct(oldUrlPath, request);
await testGETByTenantProduct(newUrlPath, request);
});
test('Fetch app by product', async ({ request }) => {
await testGETByProduct(oldUrlPath, request);
await testGETByProduct(newUrlPath, request);
});
});
const testPATCHById = async (urlPath, request) => {
const currApp = urlPath === oldUrlPath ? app : app1;
const response = await request.patch(`/api/v1/${urlPath}`, {
data: {
id: currApp?.id,
name: 'Updated App',
},
});
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject({
...currApp,
name: 'Updated App',
});
};
const testPATCHByTenantProduct = async (urlPath, request) => {
const currApp = urlPath === oldUrlPath ? app : app1;
const response = await request.patch(`/api/v1/${urlPath}`, {
data: {
tenant: currApp?.tenant,
product: currApp?.product,
name: 'Updated App 2',
},
});
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject({
...currApp,
name: 'Updated App 2',
});
};
test.describe('PATCH /api/v1/identity-federation', () => {
test('Update app by id', async ({ request }) => {
await testPATCHById(oldUrlPath, request);
await testPATCHById(newUrlPath, request);
});
test('Update app by tenant and product', async ({ request }) => {
await testPATCHByTenantProduct(oldUrlPath, request);
await testPATCHByTenantProduct(newUrlPath, request);
});
});
const testDELETEById = async (urlPath, request) => {
const currApp = urlPath === oldUrlPath ? app : app1;
const response = await request.delete(`/api/v1/${urlPath}?id=${currApp?.id}`);
const { data } = await response.json();
expect(response.ok()).toBe(true);
expect(response.status()).toBe(200);
expect(data).toMatchObject({});
// Confirm app is deleted
const response2 = await request.get(`/api/v1/${urlPath}?id=${currApp?.id}`);
expect(response2.ok()).toBe(false);
expect(response2.status()).toBe(404);
};
test.describe('DELETE /api/v1/identity-federation', () => {
test('Delete app by id', async ({ request }) => {
await testDELETEById(oldUrlPath, request);
await testDELETEById(newUrlPath, request);
});
});

View File

@ -1,11 +1,7 @@
import { test } from '@playwright/test';
import { options } from '../../helpers/api';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
test.describe('OIDC SSO Connection', () => {
//

View File

@ -6,14 +6,11 @@ import {
getRawMetadata,
newConnection,
expectedConnection,
getConnectionByProduct,
} from '../../helpers/sso';
import { options } from '../../helpers/api';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
test.afterEach(async ({ request }) => {
const { tenant, product } = newConnection;
@ -210,3 +207,23 @@ test.describe('GET /api/v1/sso/exists', () => {
expect(response.status()).toBe(404);
});
});
test.describe('GET /api/v1/sso/product', () => {
const { product } = newConnection;
test('should get empty array for SSO connection by product', async ({ request }) => {
const response = await getConnectionByProduct(request, product);
expect(response).toMatchObject([]);
expect(response.length).toBe(0);
});
test('should be able to get SSO Connections by product', async ({ request }) => {
await createConnection(request, newConnection);
const response = await getConnectionByProduct(request, product);
expect(response).toMatchObject([expectedConnection]);
expect(response.length).toBe(1);
});
});

View File

@ -1,14 +1,10 @@
import { test, expect } from '@playwright/test';
import { options } from '../../helpers/api';
const tenant = 'tenant-1';
const product = 'product-1';
test.use({
extraHTTPHeaders: {
Authorization: `Api-Key secret`,
'Content-Type': 'application/json',
},
});
test.use(options);
// POST /api/v1/sso/setuplinks
test('create the setup link', async ({ request }) => {

View File

@ -0,0 +1,109 @@
import { test, expect } from '@playwright/test';
import {
createConnection,
deleteConnection,
newConnection,
deleteSSOTraces,
getSSOTracesByProduct,
getSSOTraceById,
countSSOTracesByProduct,
} from '../../helpers/sso';
import { options } from '../../helpers/api';
import { oauthAuthorize } from '../../helpers/oauth';
test.use(options);
test.beforeEach(async ({ request }) => {
await createConnection(request, newConnection);
});
test.afterEach(async ({ request }) => {
const { tenant, product } = newConnection;
// Delete the connection & traces after each test
await deleteConnection(request, { tenant, product });
await deleteSSOTraces(request, product);
});
test.describe('GET /api/v1/sso-traces/product', () => {
test('should be able to get empty list of traces', async ({ request }) => {
const list = await getSSOTracesByProduct(request, newConnection.product);
expect(list.data.length).toBe(0);
});
});
test.describe('GET /api/v1/sso-traces/product/count', () => {
test('should be able to get non empty list of traces', async ({ request }) => {
await oauthAuthorize(
request,
{
client_id: 'dummy',
tenant: 'dummy',
product: newConnection.product,
state: 'Bb-w_AqDxZh90BBVz4PRhtRIRetOgo0AR0pmrhzyICU',
response_type: 'code',
redirect_uri: newConnection.redirectUrl[0].replaceAll('*', ''),
code_challenge: 'OcMni5eZvSrQ2ev7tPICbcE7q1piL8Abi8IfJtWbUtY',
code_challenge_method: 'S256',
},
true
);
const res = await countSSOTracesByProduct(request, newConnection.product);
expect(res.count).toBeGreaterThan(0);
});
});
test.describe('GET /api/v1/sso-traces', () => {
test('should be able to get sso trace by Id', async ({ request }) => {
await oauthAuthorize(
request,
{
client_id: 'dummy',
tenant: 'dummy',
product: newConnection.product,
state: 'Bb-w_AqDxZh90BBVz4PRhtRIRetOgo0AR0pmrhzyICU',
response_type: 'code',
redirect_uri: newConnection.redirectUrl[0].replaceAll('*', ''),
code_challenge: 'OcMni5eZvSrQ2ev7tPICbcE7q1piL8Abi8IfJtWbUtY',
code_challenge_method: 'S256',
},
true
);
const list = await getSSOTracesByProduct(request, newConnection.product);
expect(list.data.length).toBe(1);
const trace = await getSSOTraceById(request, list.data[0].traceId);
expect(trace.data).toMatchObject(list.data[0]);
});
});
test.describe('DELETE /api/v1/sso-traces/product', () => {
test('should be able to delete sso trace by product', async ({ request }) => {
await oauthAuthorize(
request,
{
client_id: 'dummy',
tenant: 'dummy',
product: newConnection.product,
state: 'Bb-w_AqDxZh90BBVz4PRhtRIRetOgo0AR0pmrhzyICU',
response_type: 'code',
redirect_uri: newConnection.redirectUrl[0].replaceAll('*', ''),
code_challenge: 'OcMni5eZvSrQ2ev7tPICbcE7q1piL8Abi8IfJtWbUtY',
code_challenge_method: 'S256',
},
true
);
let res = await countSSOTracesByProduct(request, newConnection.product);
expect(res.count).toBeGreaterThan(0);
await deleteSSOTraces(request, newConnection.product);
res = await countSSOTracesByProduct(request, newConnection.product);
expect(res.count).toBe(0);
});
});

View File

@ -0,0 +1,49 @@
// https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups#request
export const azureUser = (id: number) => ({
schemas: [
'urn:ietf:params:scim:schemas:core:2.0:User',
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User',
],
externalId: `jackson-${id}`,
userName: `jackson-${id}@boxyhq.onmicrosoft.com`,
active: true,
displayName: `Jackson-${id}`,
emails: [{ primary: true, type: 'work', value: `jackson-${id}@example.com` }],
meta: { resourceType: 'User' },
name: { formatted: `samuel-${id} jackson-${id}`, familyName: `jackson-${id}`, givenName: `samuel-${id}` },
title: 'Manager',
roles: [],
});
export const updatedAzureUser = (id: number) => ({
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
Operations: [
{
op: 'Replace',
path: 'name.givenName',
value: `samuel-${id}-updated`,
},
{
op: 'Replace',
path: 'name.familyName',
value: `jackson-${id}-updated`,
},
{
op: 'Replace',
path: 'emails[type eq "work"].value',
value: `jackson-${id}-updated@example.com`,
},
],
});
export const azureGroup = {
schemas: [
'urn:ietf:params:scim:schemas:core:2.0:Group',
'http://schemas.microsoft.com/2006/11/ResourceManagement/ADSCIM/2.0/Group',
],
externalId: '8aa1a0c0-c4c3-4bc0-b4a5-2ef676900159',
displayName: 'BoxyHQ',
meta: {
resourceType: 'Group',
},
};

View File

@ -0,0 +1,11 @@
export * from './azure';
export * from './okta';
export enum DirectorySyncProviders {
'azure-scim-v2' = 'Azure SCIM v2.0',
'onelogin-scim-v2' = 'OneLogin SCIM v2.0',
'okta-scim-v2' = 'Okta SCIM v2.0',
'jumpcloud-scim-v2' = 'JumpCloud v2.0',
'generic-scim-v2' = 'Generic SCIM v2.0',
'google' = 'Google',
}

View File

@ -0,0 +1,38 @@
// https://developer.okta.com/docs/reference/scim/scim-20/#create-the-user
export const oktaUser = (id: number) => ({
schemas: ['urn:ietf:params:scim:schemas:core:2.0:User'],
userName: `jackson-${id}@boxyhq.okta.local`,
name: { familyName: `jackson-${id}`, givenName: `samuel-${id}` },
emails: [{ primary: true, type: 'work', value: `jackson-${id}@okta.local` }],
displayName: `Jackson-${id}`,
locale: 'en-US',
externalId: `jackson-${id}`,
groups: [],
password: `jackson-password-${id}`,
active: true,
});
export const updatedOktaUser = (id: number) => ({
schemas: ['urn:ietf:params:scim:schemas:core:2.0:User'],
userName: `jackson-${id}@boxyhq.okta.local`,
name: { familyName: `jackson-${id}-updated`, givenName: `samuel-${id}-updated` },
emails: [{ primary: true, type: 'work', value: `jackson-${id}-updated@okta.local` }],
displayName: `Jackson-${id}`,
locale: 'en-US',
externalId: `jackson-${id}`,
groups: [],
password: `jackson-password-${id}`,
active: true,
});
export const oktaGroup = {
schemas: [
'urn:ietf:params:scim:schemas:core:2.0:Group',
'http://schemas.microsoft.com/2006/11/ResourceManagement/ADSCIM/2.0/Group',
],
externalId: '8aa1a0c0-c4c3-4bc0-b4a5-2ef676900159',
displayName: 'BoxyHQ',
meta: {
resourceType: 'Group',
},
};

View File

@ -0,0 +1,85 @@
import type { Page } from '@playwright/test';
import type { DirectorySyncProviders } from '../data/dsync';
export class DSyncPage {
tenant: string;
product: string;
constructor(public readonly page: Page) {
this.tenant = 'acme.com';
this.product = 'demo';
}
async gotoDSync() {
await this.page.goto(`/admin/directory-sync`);
}
async addDSyncConnection(provider: keyof typeof DirectorySyncProviders) {
await this.gotoDSync();
await this.page.getByRole('link', { name: 'New Directory' }).click();
await this.page.getByLabel('Directory name').fill('DS-1');
await this.page.getByLabel('Directory provider').selectOption({ value: provider });
await this.page.getByLabel('Tenant').fill(this.tenant);
await this.page.getByLabel('Product').fill(this.product);
await this.page.getByLabel('Webhook URL').fill('https://example.com');
await this.page.getByLabel('Webhook secret').fill('secret');
await this.page.getByRole('button', { name: 'Create Directory' }).click();
const scimUrl = await this.page.getByLabel('SCIM Endpoint').inputValue();
const scimToken = await this.page.getByLabel('SCIM Token').inputValue();
return { scimUrl, scimToken };
}
async deleteConnection() {
await this.gotoDSync();
await this.page.getByLabel('Loading').waitFor({ state: 'hidden' });
const editButton = await this.page.getByRole('button').and(this.page.getByLabel('Edit'));
await editButton.click();
await this.page.getByRole('button', { name: 'Delete' }).click();
await this.page.getByRole('button', { name: 'Confirm' }).click();
}
async switchToDSyncInfoView() {
await this.gotoDSync();
await this.page.getByLabel('View').click();
await this.page.waitForURL('/admin/directory-sync/**');
}
async switchToUsersView({ waitForData }: { waitForData?: boolean } = {}) {
await this.page.getByRole('listitem').and(this.page.getByText('Users')).click();
await this.page.waitForURL(/\/admin\/directory-sync\/.*\/users$/);
if (waitForData) {
await this.page.getByRole('table').waitFor();
}
}
// group events navigation done after users view, hence we can skip View click
async switchToGroupsView({ waitForData }: { waitForData?: boolean } = {}) {
await this.page.getByRole('listitem').and(this.page.getByText('Groups')).click();
await this.page.waitForURL(/\/admin\/directory-sync\/.*\/groups$/);
if (waitForData) {
await this.page.getByRole('table').waitFor();
}
}
async switchToEventsView({ waitForData }: { waitForData?: boolean } = {}) {
await this.page.getByRole('listitem').and(this.page.getByText('Webhook Events')).click();
await this.page.waitForURL(/\/admin\/directory-sync\/.*\/events$/);
if (waitForData) {
await this.page.getByRole('table').waitFor();
}
}
async inspectEventRow(id: number, webhookEndpoint: string) {
const webhookRowRegex = new RegExp(`${webhookEndpoint}.*View`);
await this.page.getByRole('row', { name: webhookRowRegex }).getByRole('button').nth(id).click();
await this.page.waitForURL(/\/admin\/directory-sync\/.*\/events\/.*/);
await this.page.locator('pre').waitFor();
}
async setWebHookEventsLogging({ enable }: { enable: boolean }) {
await this.gotoDSync();
await this.page.getByLabel('Edit').click();
const checkBox = this.page.getByLabel('Enable Webhook events logging');
if (enable) {
await checkBox.check();
} else {
await checkBox.uncheck();
}
await this.page.getByRole('button', { name: 'Save' }).click();
}
}

View File

@ -0,0 +1,4 @@
export * from './portal';
export * from './sso-page';
export * from './dsync-page';
export * from './setuplink-page';

View File

@ -0,0 +1,20 @@
import { Locator, Page, expect } from '@playwright/test';
export class Portal {
userAvatarLocator: Locator;
constructor(public readonly page: Page) {
this.userAvatarLocator = this.page.getByTestId('user-avatar');
}
async doCredentialsLogin() {
await this.page.goto('/admin/auth/login');
await this.page.getByPlaceholder('Email').fill('super@boxyhq.com');
await this.page.getByPlaceholder('Password').fill('999login');
await this.page.getByRole('button', { name: 'Sign In' }).click();
}
async isLoggedIn() {
// assert login state
await expect(this.userAvatarLocator).toBeVisible();
}
}

View File

@ -0,0 +1,82 @@
import { Page, expect } from '@playwright/test';
const TEST_SETUPLINK_REDIRECT_URL = 'http://localhost:3366';
const TEST_SETUPLINK_DEFAULT_REDIRECT_URL = 'http://localhost:3366/login/saml';
const TEST_SETUPLINK_ADMIN_URL = '/admin/sso-connection/setup-link';
const TEST_SETUPLINK_URL_LABEL_SELECTOR =
'Share this link with your customers to allow them to set up the integrationClose';
export class SetupLinkPage {
setupLinkUrl: string;
constructor(
public readonly page: Page,
public readonly product: string,
public readonly tenant: string,
public readonly adminPage: string = TEST_SETUPLINK_ADMIN_URL,
public readonly redirectUrl: string = TEST_SETUPLINK_REDIRECT_URL,
public readonly defaultRedirectUrl: string = TEST_SETUPLINK_DEFAULT_REDIRECT_URL
) {
this.page = page;
this.product = product;
this.tenant = tenant;
this.adminPage = adminPage;
this.redirectUrl = redirectUrl;
this.defaultRedirectUrl = defaultRedirectUrl;
this.setupLinkUrl = '';
}
async createSetupLink() {
// Go to admin/sso-connection/setup-link page and create setup link
await this.page.goto(this.adminPage);
await this.page.getByRole('button', { name: 'New Setup Link' }).click();
await this.page.getByPlaceholder('Acme SSO').fill('acme-test');
await this.page.getByLabel('Description (Optional)').fill('acme test');
await this.page.getByPlaceholder('acme', { exact: true }).fill(this.tenant);
await this.page.getByPlaceholder('MyApp').fill(this.product);
await this.page.getByPlaceholder('http://localhost:3366', { exact: true }).fill(this.redirectUrl);
await this.page.getByPlaceholder('http://localhost:3366/login/').fill(this.defaultRedirectUrl);
await this.page.getByRole('button', { name: 'Create Setup Link' }).click();
// Extract generated setup link
this.setupLinkUrl = await this.page
.getByText(TEST_SETUPLINK_URL_LABEL_SELECTOR)
.locator('input[type="text"]')
.first()
.inputValue();
}
async getSetupLinkUrl(): Promise<string> {
return this.setupLinkUrl;
}
async isSetupLinkCreated() {
// Go back to new connections page
await this.page.goto(TEST_SETUPLINK_ADMIN_URL);
// Await for rows loaded
await expect(this.page.getByRole('table')).toBeVisible();
// Check if setup link is created
await expect(
this.page.getByText(this.tenant, { exact: true }),
'Failed to create setup link'
).toBeVisible();
await expect(
this.page.getByText(this.product, { exact: true }),
'Failed to create setup link'
).toBeVisible();
}
async removeSetupLink() {
// Go back to setup link admin url
await this.page.goto(TEST_SETUPLINK_ADMIN_URL);
// Await for rows loaded
await expect(this.page.getByRole('table')).toBeVisible();
// Delete the created setuplink
await this.page.getByRole('button').nth(5).click();
await this.page.getByRole('button', { name: 'Delete' }).click();
}
}

View File

@ -0,0 +1,182 @@
import type { Page, Locator } from '@playwright/test';
import { adminPortalSSODefaults } from '@lib/env';
const ADMIN_PORTAL_TENANT = adminPortalSSODefaults.tenant;
const ADMIN_PORTAL_PRODUCT = adminPortalSSODefaults.product;
const MOCKSAML_ORIGIN = process.env.MOCKSAML_ORIGIN || 'https://mocksaml.com';
const MOCKSAML_SIGNIN_BUTTON_NAME = 'Sign In';
const MOCKLAB_ORIGIN = 'https://oauth.wiremockapi.cloud';
const MOCKLAB_CLIENT_ID = 'mocklab_oauth2';
const MOCKLAB_CLIENT_SECRET = 'mocklab_secret';
const MOCKLAB_SIGNIN_BUTTON_NAME = 'Login';
const MOCKLAB_DISCOVERY_ENDPOINT = 'https://oauth.wiremockapi.cloud/.well-known/openid-configuration';
export class SSOPage {
private readonly createConnection: Locator;
private readonly nameInput: Locator;
private readonly tenantInput: Locator;
private readonly productInput: Locator;
private readonly redirectURLSInput: Locator;
private readonly defaultRedirectURLInput: Locator;
private readonly metadataUrlInput: Locator;
private readonly oidcDiscoveryUrlInput: Locator;
private readonly oidcClientIdInput: Locator;
private readonly oidcClientSecretInput: Locator;
private readonly saveConnection: Locator;
private readonly deleteButton: Locator;
private readonly confirmButton: Locator;
private readonly toggleConnectionStatusCheckbox: Locator;
private readonly toggleConnectionStatusLabel: Locator;
private connections: string[];
constructor(public readonly page: Page) {
this.connections = [];
this.createConnection = this.page.getByTestId('create-connection');
this.nameInput = this.page.getByLabel('Connection name (Optional)');
this.tenantInput = this.page.getByLabel('Tenant');
this.productInput = this.page.getByLabel('Product');
this.redirectURLSInput = page
.getByRole('group')
.filter({ hasText: 'Allowed redirect URLs' })
.locator(page.getByRole('textbox').first());
this.defaultRedirectURLInput = this.page.getByLabel('Default redirect URL');
this.metadataUrlInput = this.page.getByLabel('Metadata URL');
this.oidcDiscoveryUrlInput = this.page.getByLabel('Well-known URL of OpenID Provider');
this.oidcClientIdInput = this.page.getByLabel('Client ID');
this.oidcClientSecretInput = this.page.getByLabel('Client Secret');
this.saveConnection = this.page.getByRole('button', { name: /save/i });
this.toggleConnectionStatusCheckbox = this.page.getByRole('checkbox', { name: 'Active' });
this.toggleConnectionStatusLabel = this.page.locator('label').filter({ hasText: 'Active' });
this.deleteButton = this.page.getByRole('button', { name: 'Delete' });
this.confirmButton = this.page.getByRole('button', { name: 'Confirm' });
}
async goto() {
const url = new URL(this.page.url());
if (url.pathname !== '/admin/sso-connection') {
await this.page.goto('/admin/sso-connection');
}
}
async addSSOConnection({
name,
type = 'saml',
tenant,
product,
baseURL,
}: {
name: string;
type: 'saml' | 'oidc';
tenant?: string;
product?: string;
baseURL: string;
}) {
const connectionIndex = this.connections.length + 1;
const ssoName = `${name}-${connectionIndex}`;
// Find the new connection button and click on it
await this.createConnection.click();
if (type === 'oidc') {
// Toggle connection type to OIDC
await this.page.getByLabel('OIDC').check();
}
// Fill the name for the connection
await this.nameInput.fill(ssoName);
// Fill the tenant for the connection
await this.tenantInput.fill(tenant || ADMIN_PORTAL_TENANT);
// Fill the product for the connection
await this.productInput.fill(product || ADMIN_PORTAL_PRODUCT);
// Fill the Allowed redirect URLs for the connection
await this.redirectURLSInput.fill(baseURL!);
// Fill the default redirect URLs for the connection
await this.defaultRedirectURLInput.fill(`${baseURL}/admin/auth/idp-login`);
if (type === 'saml') {
// Enter the metadata url for mocksaml in the form
await this.metadataUrlInput.fill(`${MOCKSAML_ORIGIN}/api/namespace/${ssoName}/saml/metadata`);
}
if (type === 'oidc') {
// Enter the OIDC client credentials for mocklab in the form
await this.oidcClientIdInput.fill(`${MOCKLAB_CLIENT_ID}-${connectionIndex}`);
await this.oidcClientSecretInput.fill(`${MOCKLAB_CLIENT_SECRET}-${connectionIndex}`);
// Enter the OIDC discovery url for mocklab in the form
await this.oidcDiscoveryUrlInput.fill(MOCKLAB_DISCOVERY_ENDPOINT);
}
// submit the form
await this.saveConnection.click();
this.connections = [...this.connections, ssoName];
}
async gotoEditView(name: string) {
await this.goto();
const editButton = this.page.getByText(name).locator('xpath=..').getByLabel('Edit');
await editButton.click();
}
async toggleConnectionStatus(newStatus: boolean) {
const isChecked = await this.toggleConnectionStatusCheckbox.isChecked();
if (isChecked && !newStatus) {
await this.toggleConnectionStatusLabel.click();
await this.confirmButton.click();
} else if (!isChecked && newStatus) {
await this.toggleConnectionStatusLabel.click();
await this.confirmButton.click();
}
}
async updateSSOConnection({ name, url, newStatus }: { name: string; url: string; newStatus?: boolean }) {
await this.gotoEditView(name);
await this.redirectURLSInput.fill(url);
await this.saveConnection.click();
if (typeof newStatus === 'boolean') {
await this.gotoEditView(name);
await this.toggleConnectionStatus(newStatus);
}
}
async deleteSSOConnection(name: string) {
await this.gotoEditView(name);
// click the delete and confirm deletion
await this.deleteButton.click();
await this.confirmButton.click();
}
async deleteAllSSOConnections() {
let _connection;
while ((_connection = this.connections.shift())) {
await this.deleteSSOConnection(_connection);
}
}
async logout() {
const userAvatarLocator = this.page.getByTestId('user-avatar');
// Logout from the magic link authentication
await userAvatarLocator.click();
await this.page.getByTestId('logout').click();
}
async signInWithSSO() {
await this.page.getByTestId('sso-login-button').click();
}
async selectIdP(name: string) {
const idpSelectionTitle = 'Select an Identity Provider to continue';
await this.page.getByText(idpSelectionTitle).waitFor();
await this.page.getByRole('button', { name }).click();
}
async signInWithMockSAML() {
// Perform sign in at mocksaml
await this.page.waitForURL((url) => url.origin === MOCKSAML_ORIGIN);
await this.page.getByPlaceholder('jackson').fill('bob');
await this.page.getByRole('button', { name: MOCKSAML_SIGNIN_BUTTON_NAME }).click();
}
async signInWithMockLab() {
// Perform sign in at mocklab
await this.page.waitForURL((url) => url.origin === MOCKLAB_ORIGIN);
await this.page.getByPlaceholder('yours@example.com').fill('bob@oidc.com');
await this.page.getByRole('button', { name: MOCKLAB_SIGNIN_BUTTON_NAME }).click();
}
}

View File

@ -2,6 +2,15 @@
import { chromium, FullConfig } from '@playwright/test';
import { IDENTIFIER, TOKEN } from './nextAuth.constants';
function streamToString(stream): Promise<string> {
const chunks: any[] = [];
return new Promise((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
stream.on('error', (err) => reject(err));
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
});
}
async function globalSetup(config: FullConfig) {
// Env init
process.env.MOCKSAML_ORIGIN = process.env.CI ? 'http://localhost:4000' : 'https://mocksaml.com';
@ -15,6 +24,17 @@ async function globalSetup(config: FullConfig) {
const page = await browser.newPage();
await page.goto(MAGIC_LINK);
await page.context().storageState({ path: storageState as string });
// Get MockSAML metadata
await page.goto(process.env.MOCKSAML_ORIGIN);
// Start waiting for download before clicking. Note no await.
const downloadPromise = page.waitForEvent('download');
await page.getByRole('link', { name: 'Download Metadata' }).click();
const download = await downloadPromise;
const _stream = await download.createReadStream();
const _metadata = await streamToString(_stream);
process.env.MOCKSAML_METADATA = _metadata;
await browser.close();
}

View File

@ -0,0 +1,140 @@
import { test as baseTest, expect } from '@playwright/test';
import { DSyncPage } from 'e2e/support/fixtures';
import { getDirectory } from 'e2e/api/helpers/directories';
import { options } from 'e2e/api/helpers/api';
import {
addGroupMember,
createGroup,
createUser,
deleteGroup,
deleteUser,
updateGroupName,
updateUser,
} from 'e2e/api/helpers';
import {
DirectorySyncProviders,
azureGroup,
azureUser,
updatedAzureUser,
oktaGroup,
oktaUser,
updatedOktaUser,
} from 'e2e/support/data/dsync';
type MyFixtures = {
dsyncPage: DSyncPage;
};
export const test = baseTest.extend<MyFixtures>({
dsyncPage: async ({ page }, use) => {
const dsyncPage = new DSyncPage(page);
await use(dsyncPage);
await dsyncPage.deleteConnection();
},
});
test.use(options);
const providers = [
{ type: 'azure-scim-v2', generators: { user: azureUser, group: azureGroup, updateUser: updatedAzureUser } },
{ type: 'okta-scim-v2', generators: { user: oktaUser, group: oktaGroup, updateUser: updatedOktaUser } },
];
for (const provider of providers) {
test(`${provider.type} SCIM connection`, async ({ dsyncPage, request, page }) => {
await dsyncPage.addDSyncConnection(provider.type as keyof typeof DirectorySyncProviders);
// Send API requests to user/groups endpoint
const [directory] = await getDirectory(request, { tenant: dsyncPage.tenant, product: dsyncPage.product });
const providerUser1 = provider.generators.user(1);
const user1 = await createUser(request, directory, providerUser1);
const group = await createGroup(request, directory, provider.generators.group);
await addGroupMember(request, directory, group, user1.id);
// Assert created user
await dsyncPage.switchToDSyncInfoView();
await dsyncPage.switchToUsersView({ waitForData: true });
await expect(page.getByRole('cell', { name: providerUser1.name.givenName, exact: true })).toBeVisible();
await expect(page.getByRole('cell', { name: providerUser1.name.familyName, exact: true })).toBeVisible();
await expect(page.getByRole('cell', { name: providerUser1.emails[0].value, exact: true })).toBeVisible();
// Assert created group
await dsyncPage.switchToGroupsView({ waitForData: true });
await expect(await page.getByRole('cell', { name: 'BoxyHQ' })).toBeVisible();
// Enable webhook logs
await dsyncPage.setWebHookEventsLogging({ enable: true });
const providerUser2 = provider.generators.user(2);
const user2 = await createUser(request, directory, providerUser2);
await addGroupMember(request, directory, group, user2.id);
// Assert created user
await dsyncPage.switchToDSyncInfoView();
await dsyncPage.switchToUsersView({ waitForData: true });
await expect(page.getByRole('cell', { name: providerUser2.name.givenName, exact: true })).toBeVisible();
await expect(page.getByRole('cell', { name: providerUser2.name.familyName, exact: true })).toBeVisible();
await expect(page.getByRole('cell', { name: providerUser2.emails[0].value, exact: true })).toBeVisible();
// Patch second user
const providerUser2Updated = provider.generators.updateUser(2);
await updateUser(
request,
directory,
user2.id,
providerUser2Updated,
providerUser2Updated.schemas[0] === 'urn:ietf:params:scim:api:messages:2.0:PatchOp'
);
await page.reload();
// Assert updated attributes for user
const { givenName, familyName, email } =
'Operations' in providerUser2Updated
? {
givenName: providerUser2Updated.Operations[0].value,
familyName: providerUser2Updated.Operations[1].value,
email: providerUser2Updated.Operations[2].value,
}
: {
givenName: providerUser2Updated.name.givenName,
familyName: providerUser2Updated.name.familyName,
email: providerUser2Updated.emails[0].value,
};
await expect(
page.getByRole('cell', {
name: givenName,
exact: true,
})
).toBeVisible();
await expect(page.getByRole('cell', { name: familyName, exact: true })).toBeVisible();
await expect(page.getByRole('cell', { name: email, exact: true })).toBeVisible();
// Assert webhook logs
await dsyncPage.switchToEventsView({ waitForData: true });
await dsyncPage.inspectEventRow(0, directory.webhook.endpoint);
await expect(page.getByText('"user.updated"')).toBeVisible();
await dsyncPage.switchToEventsView({ waitForData: true });
await dsyncPage.inspectEventRow(1, directory.webhook.endpoint);
await expect(page.getByText('"group.user_added"')).toBeVisible();
await dsyncPage.switchToEventsView({ waitForData: true });
await dsyncPage.inspectEventRow(2, directory.webhook.endpoint);
await expect(page.getByText('"user.created"')).toBeVisible();
// Delete webhook logs
await dsyncPage.switchToEventsView();
await page.getByRole('button', { name: 'Remove Events' }).click();
await page.getByTestId('confirm-delete').click();
await page.getByRole('table').waitFor({ state: 'detached' });
await expect(
await page.getByRole('heading', { name: 'No webhook events found for this directory.' })
).toBeVisible();
await dsyncPage.setWebHookEventsLogging({ enable: false });
// User deletion
await deleteUser(request, directory, user1.id);
await deleteUser(request, directory, user2.id);
await dsyncPage.switchToDSyncInfoView();
await dsyncPage.switchToUsersView();
await expect(page.getByRole('heading', { name: 'No users found for this directory.' })).toBeVisible();
await updateGroupName(request, directory, group.id, 'BoxyHQ-updated');
await dsyncPage.switchToGroupsView({ waitForData: true });
await expect(page.getByRole('cell', { name: 'BoxyHQ-updated' })).toBeVisible();
// Group deletion
await deleteGroup(request, directory, group.id);
await page.reload();
await expect(page.getByRole('heading', { name: 'No groups found for this directory.' })).toBeVisible();
await dsyncPage.switchToEventsView();
await expect(
page.getByRole('heading', { name: 'No webhook events found for this directory.' })
).toBeVisible();
});
}

View File

@ -0,0 +1,110 @@
import { test as baseTest, expect } from '@playwright/test';
import { Portal, SSOPage } from 'e2e/support/fixtures';
type MyFixtures = {
ssoPage: SSOPage;
portal: Portal;
};
export const test = baseTest.extend<MyFixtures>({
portal: async ({ page }, use) => {
const portal = new Portal(page);
await use(portal);
},
ssoPage: async ({ page, portal }, use) => {
const ssoPage = new SSOPage(page);
await ssoPage.goto();
await use(ssoPage);
await portal.doCredentialsLogin();
await portal.isLoggedIn();
await ssoPage.deleteAllSSOConnections();
},
});
test('OAuth2 wrapper + SAML provider + wrong redirectUrl', async ({ ssoPage, page, baseURL }, testInfo) => {
const ssoName = `saml-${testInfo.workerIndex}`;
await ssoPage.addSSOConnection({ name: ssoName, type: 'saml', baseURL: baseURL! });
// check if the first added connection appears in the connection list
await expect(page.getByText(`${ssoName}-1`)).toBeVisible();
await ssoPage.updateSSOConnection({
name: `${ssoName}-1`,
url: 'https://invalid-url.com',
});
// Logout of magic link login
await ssoPage.logout();
await ssoPage.signInWithSSO();
// Wait for browser to redirect to error page
await page.waitForURL((url) => url.origin === baseURL && url.pathname === '/error');
// Assert error text
await expect(page.getByText(`SSO error: Redirect URL is not allowed.`)).toBeVisible();
});
test('OAuth2 wrapper + SAML provider + inactive connection', async ({ ssoPage, page, baseURL }, testInfo) => {
const ssoName = `saml-${testInfo.workerIndex}`;
await ssoPage.addSSOConnection({ name: ssoName, type: 'saml', baseURL: baseURL! });
// check if the first added connection appears in the connection list
await expect(page.getByText(`${ssoName}-1`)).toBeVisible();
await ssoPage.updateSSOConnection({
name: `${ssoName}-1`,
url: baseURL!,
newStatus: false,
});
// Confirm connection label inactive is displayed
await expect(
page.getByText(`${ssoName}-1`).locator('xpath=..').getByRole('cell', { name: 'Inactive', exact: true })
).toBeVisible();
// Logout and try to sign in with connection
// Logout of magic link login
await ssoPage.logout();
await ssoPage.signInWithSSO();
// Wait for browser to redirect to error page
await page.waitForURL((url) => url.origin === baseURL && url.pathname === '/error');
// Assert error text
await expect(
page.getByText('SSO error: SSO connection is deactivated. Please contact your administrator.')
).toBeVisible();
});
test('OAuth2 wrapper + OIDC provider + wrong redirectUrl', async ({ ssoPage, page, baseURL }, testInfo) => {
const ssoName = `oidc-${testInfo.workerIndex}`;
await ssoPage.addSSOConnection({ name: ssoName, type: 'oidc', baseURL: baseURL! });
// check if the oidc connection appears in the connection list
await expect(page.getByText(`${ssoName}-1`)).toBeVisible();
await ssoPage.updateSSOConnection({
name: `${ssoName}-1`,
url: 'https://invalid-url.com',
});
// Logout of magic link login
await ssoPage.logout();
await ssoPage.signInWithSSO();
// Wait for browser to redirect to error page
await page.waitForURL((url) => url.origin === baseURL && url.pathname === '/error');
// Assert error text
await expect(page.getByText('SSO error: Redirect URL is not allowed.')).toBeVisible();
});
test('OAuth2 wrapper + OIDC provider + inactive connection', async ({ ssoPage, page, baseURL }, testInfo) => {
const ssoName = `oidc-${testInfo.workerIndex}`;
await ssoPage.addSSOConnection({ name: ssoName, type: 'oidc', baseURL: baseURL! });
// check if the oidc connection appears in the connection list
await expect(page.getByText(`${ssoName}-1`)).toBeVisible();
await ssoPage.updateSSOConnection({
name: `${ssoName}-1`,
url: baseURL!,
newStatus: false,
});
// Confirm connection label inactive is displayed
await expect(
page.getByText(`${ssoName}-1`).locator('xpath=..').getByRole('cell', { name: 'Inactive', exact: true })
).toBeVisible();
// Logout and try to sign in with connection
// Logout of magic link login
await ssoPage.logout();
await ssoPage.signInWithSSO();
// Wait for browser to redirect to error page
await page.waitForURL((url) => url.origin === baseURL && url.pathname === '/error');
// Assert error text
await expect(
page.getByText('SSO error: SSO connection is deactivated. Please contact your administrator.')
).toBeVisible();
});

View File

@ -0,0 +1,68 @@
import { test as baseTest, expect } from '@playwright/test';
import { Portal, SSOPage } from 'e2e/support/fixtures';
type MyFixtures = {
ssoPage: SSOPage;
portal: Portal;
};
export const test = baseTest.extend<MyFixtures>({
ssoPage: async ({ page, baseURL }, use, testInfo) => {
const ssoPage = new SSOPage(page);
const ssoName = `oidc-${testInfo.workerIndex}`;
await ssoPage.goto();
await ssoPage.addSSOConnection({ name: ssoName, type: 'oidc', baseURL: baseURL! });
await use(ssoPage);
await ssoPage.deleteAllSSOConnections();
},
portal: async ({ page }, use) => {
const portal = new Portal(page);
await use(portal);
},
});
test('OAuth2 wrapper + OIDC provider', async ({ ssoPage, portal, page, baseURL }, testInfo) => {
// check if the first added connection appears in the connection list
await expect(page.getByText(`oidc-${testInfo.workerIndex}-1`)).toBeVisible();
// Logout of magic link login
await ssoPage.logout();
await ssoPage.signInWithSSO();
// Login using MockLab
await ssoPage.signInWithMockLab();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
});
test('OAuth2 wrapper + 2 OIDC providers', async ({ ssoPage, portal, page, baseURL }, testInfo) => {
const ssoName = `oidc-${testInfo.workerIndex}`;
// check if the first added connection appears in the connection list
await expect(page.getByText(`${ssoName}-1`)).toBeVisible();
// Add second OIDC connection
await ssoPage.addSSOConnection({ name: ssoName, type: 'oidc', baseURL: baseURL! });
// check if the second added connection appears in the connection list
await expect(page.getByText(`${ssoName}-2`)).toBeVisible();
// Logout of magic link login
await ssoPage.logout();
// Login using MockLab
await ssoPage.signInWithSSO();
// Select IdP from selection screen
await ssoPage.selectIdP(`${ssoName}-1`);
await ssoPage.signInWithMockLab();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
// Logout of magic link login
await ssoPage.logout();
// Login using MockLab
await ssoPage.signInWithSSO();
// Select IdP from selection screen
await ssoPage.selectIdP(`${ssoName}-2`);
await ssoPage.signInWithMockLab();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
});

View File

@ -0,0 +1,62 @@
import { test as baseTest, expect } from '@playwright/test';
import { Portal, SSOPage } from 'e2e/support/fixtures';
type MyFixtures = {
ssoPage: SSOPage;
portal: Portal;
};
export const test = baseTest.extend<MyFixtures>({
ssoPage: async ({ page, baseURL }, use, testInfo) => {
const ssoPage = new SSOPage(page);
let ssoName = `saml-${testInfo.workerIndex}`;
await ssoPage.goto();
await ssoPage.addSSOConnection({ name: ssoName, type: 'saml', baseURL: baseURL! });
await ssoPage.goto();
ssoName = `oidc-${testInfo.workerIndex}`;
await ssoPage.addSSOConnection({ name: ssoName, type: 'oidc', baseURL: baseURL! });
await use(ssoPage);
await ssoPage.deleteAllSSOConnections();
},
portal: async ({ page }, use) => {
const portal = new Portal(page);
await use(portal);
},
});
test('OAuth2 wrapper + SAML provider + OIDC provider', async ({
ssoPage,
portal,
page,
baseURL,
}, testInfo) => {
// check if the first added connection appears in the connection list
await expect(page.getByText(`saml-${testInfo.workerIndex}-1`)).toBeVisible();
// check if the second added connection appears in the connection list
await expect(page.getByText(`oidc-${testInfo.workerIndex}-2`)).toBeVisible();
// Logout of magic link login
await ssoPage.logout();
// Login using MockSAML
await ssoPage.signInWithSSO();
// Select IdP from selection screen
await ssoPage.selectIdP(`saml-${testInfo.workerIndex}-1`);
// Login using MockSAML
await ssoPage.signInWithMockSAML();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
// Logout of SAML login
await ssoPage.logout();
// Login using MockLab
await ssoPage.signInWithSSO();
// Select IdP from selection screen
await ssoPage.selectIdP(`oidc-${testInfo.workerIndex}-2`);
// Login using MockLab
await ssoPage.signInWithMockLab();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
});

View File

@ -0,0 +1,68 @@
import { test as baseTest, expect } from '@playwright/test';
import { Portal, SSOPage } from 'e2e/support/fixtures';
type MyFixtures = {
ssoPage: SSOPage;
portal: Portal;
};
export const test = baseTest.extend<MyFixtures>({
ssoPage: async ({ page, baseURL }, use, testInfo) => {
const ssoPage = new SSOPage(page);
const ssoName = `saml-${testInfo.workerIndex}`;
await ssoPage.goto();
await ssoPage.addSSOConnection({ name: ssoName, type: 'saml', baseURL: baseURL! });
await use(ssoPage);
await ssoPage.deleteAllSSOConnections();
},
portal: async ({ page }, use) => {
const portal = new Portal(page);
await use(portal);
},
});
test('OAuth2 wrapper + SAML provider', async ({ ssoPage, portal, page, baseURL }, testInfo) => {
// check if the first added connection appears in the connection list
await expect(page.getByText(`saml-${testInfo.workerIndex}-1`)).toBeVisible();
// Logout of magic link login
await ssoPage.logout();
await ssoPage.signInWithSSO();
// Login using MockSAML
await ssoPage.signInWithMockSAML();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
});
test('OAuth2 wrapper + 2 SAML providers', async ({ ssoPage, portal, page, baseURL }, testInfo) => {
const ssoName = `saml-${testInfo.workerIndex}`;
// check if the first added connection appears in the connection list
await expect(page.getByText(`${ssoName}-1`)).toBeVisible();
// Add second SAML connection
await ssoPage.addSSOConnection({ name: ssoName, type: 'saml', baseURL: baseURL! });
// check if the second added connection appears in the connection list
await expect(page.getByText(`${ssoName}-2`)).toBeVisible();
// Logout of magic link login
await ssoPage.logout();
// Login using MockSAML
await ssoPage.signInWithSSO();
// Select IdP from selection screen
await ssoPage.selectIdP(`${ssoName}-1`);
await ssoPage.signInWithMockSAML();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
// Logout of magic link login
await ssoPage.logout();
// Login using MockSAML
await ssoPage.signInWithSSO();
// Select IdP from selection screen
await ssoPage.selectIdP(`${ssoName}-2`);
await ssoPage.signInWithMockSAML();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// Assert logged in state
await portal.isLoggedIn();
});

View File

@ -0,0 +1,116 @@
import { expect, test as baseTest } from '@playwright/test';
import { Portal, SetupLinkPage } from 'e2e/support/fixtures';
const TEST_SETUPLINK_MOCKSAML_ORIGIN = process.env.MOCKSAML_ORIGIN || 'https://mocksaml.com';
const TEST_SETUPLINK_MOCK_METADATA_URL = `${TEST_SETUPLINK_MOCKSAML_ORIGIN}/api/saml/metadata`;
const TEST_SETUPLINK_ADMIN_CONNECTION = '/admin/sso-connection';
const TENANT = 'acme-setuplink-test.com';
const PRODUCT = 'acme-setuplink-test';
type MyFixtures = {
portal: Portal;
setuplinkPage: SetupLinkPage;
};
export const test = baseTest.extend<MyFixtures>({
portal: async ({ page }, use) => {
const portal = new Portal(page);
await portal.doCredentialsLogin();
await use(portal);
},
setuplinkPage: async ({ page }, use) => {
const setuplinkPage = new SetupLinkPage(page, PRODUCT, TENANT);
await use(setuplinkPage);
},
});
test.describe('Admin Portal Enterprise SSO SetupLink using generic SAML 2.0', () => {
test('should be able to create setup link and sso connection using generic SAML 2.0', async ({
page,
setuplinkPage,
}) => {
// Create setup link
await setuplinkPage.createSetupLink();
// get setuplink url
const linkContent = await setuplinkPage.getSetupLinkUrl();
// Open new tab and go to setup link page
const context = page.context();
const setupLinkPage = await context.newPage();
await setupLinkPage.goto(linkContent);
// Create SSO connection using generic SAML 2.0 workflow
await setupLinkPage.getByRole('button', { name: 'Generic SAML 2.0' }).click();
// check mdx generated content using remart-gfm plugin for step1
await expect(setupLinkPage.getByRole('heading', { name: 'Step 1: Configuration SAML' })).toBeVisible();
let p1 = await setupLinkPage.getByText('Your Identity Provider (IdP)').textContent();
expect(
p1 ===
'Your Identity Provider (IdP) will ask for the following information while configuring the SAML application.'
).toBeTruthy();
let p2 = await setupLinkPage.getByText('Please do not add a trailing').textContent();
expect(p2 === 'Please do not add a trailing slash at the end of the URLs.').toBeTruthy();
const p3 = await setupLinkPage.getByText('Create them exactly as shown').textContent();
expect(p3 === 'Create them exactly as shown below:').toBeTruthy();
await setupLinkPage.getByRole('button', { name: 'Next Step' }).click();
// check mdx generated content using remart-gfm plugin for step2
await expect(setupLinkPage.getByRole('heading', { name: 'Step 2: SAML Profile/Claims/' })).toBeVisible();
p1 = await setupLinkPage.getByText('We try and support 4').textContent();
expect(p1 === 'We try and support 4 attributes in the SAML claims:').toBeTruthy();
p2 = await setupLinkPage.getByText('This is how the common SAML').textContent();
expect(
p2 ===
'This is how the common SAML attributes map over for most providers, but some providers have custom mappings. Please refer to the documentation on Identity Provider to understand the exact mapping.'
).toBeTruthy();
await setupLinkPage.getByRole('button', { name: 'Next Step' }).click();
// check mdx generated content using remart-gfm plugin for step3
await expect(
setupLinkPage.getByRole('heading', { name: 'Step 3: Create SAML Connection' })
).toBeVisible();
p1 = await setupLinkPage.getByText('Enter the Identity Provider').textContent();
expect(
p1 ===
'Enter the Identity Provider Metadata below. You can either enter the metadata URL or paste the XML file content directly.'
).toBeTruthy();
await setupLinkPage
.getByPlaceholder('Paste the Metadata URL here')
.fill(TEST_SETUPLINK_MOCK_METADATA_URL);
await setupLinkPage.getByRole('button', { name: 'Save' }).click();
await setupLinkPage.waitForURL(/\/setup\/.+\/sso-connection$/);
await expect(setupLinkPage.getByRole('cell', { name: 'saml.example.com' })).toBeVisible();
await setupLinkPage.close();
// Go to connections page
await page.goto(TEST_SETUPLINK_ADMIN_CONNECTION);
// Check if new SSO connection is created
await expect(
page.getByText(TENANT, { exact: true }),
'Failed to create new sso connection from setup-link'
).toBeVisible();
await expect(
page.getByText(PRODUCT, { exact: true }),
'Failed to create new sso connection from setup-link'
).toBeVisible();
// Delete the SSO connection
await page.getByLabel('Edit').click();
await page.getByRole('button', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// remove setup link
await setuplinkPage.removeSetupLink();
});
});

View File

@ -0,0 +1,199 @@
import { test as baseTest, expect } from '@playwright/test';
import { Portal, SSOPage } from 'e2e/support/fixtures';
type MyFixtures = {
ssoPage: SSOPage;
portal: Portal;
};
let oidcClientId;
let oidcClientSecret;
const test = baseTest.extend<MyFixtures>({
ssoPage: async ({ page }, use) => {
const ssoPage = new SSOPage(page);
await use(ssoPage);
// Delete SSO Connections mapped to OIDC federation
await ssoPage.deleteSSOConnection('SSO-via-OIDC-Fed');
await ssoPage.deleteAllSSOConnections();
},
portal: async ({ page }, use) => {
const portal = new Portal(page);
// Create OIDC Federated connection
await page.goto('/admin/settings');
await page.getByRole('link', { name: 'Apps' }).click();
await page.waitForURL(/.*admin\/identity-federation$/);
await page.getByRole('button', { name: 'New App' }).click();
await page.waitForURL(/.*admin\/identity-federation\/new$/);
// Toggle connection type to OIDC
await page.getByLabel('OIDC').check();
await page.getByPlaceholder('Your app').and(page.getByLabel('Name')).fill('OF-1');
await page.getByPlaceholder('example.com').and(page.getByLabel('Tenant')).fill('acme.com');
await page.getByLabel('Product').fill('_jackson_admin_portal');
await page.locator('input[name="item"]').fill('http://localhost:5225');
await page.getByRole('button', { name: 'Create App' }).click();
await page.waitForURL(/.*admin\/identity-federation\/.*\/edit$/);
oidcClientId = await page
.locator('label')
.filter({ hasText: 'Client ID' })
.getByRole('textbox')
.inputValue();
oidcClientSecret = await page
.locator('label')
.filter({ hasText: 'Client Secret' })
.getByRole('textbox')
.inputValue();
await page.getByRole('link', { name: 'Back' }).click();
await page.waitForURL(/.*admin\/identity-federation$/);
await expect(page.getByRole('cell', { name: 'OF-1' })).toBeVisible();
// Add OIDC Connection via OIDC Fed for Admin portal
await page.getByRole('link', { name: 'Single Sign-On' }).click();
await page.getByTestId('create-connection').click();
await page.getByLabel('OIDC').check();
await page.getByLabel('Connection name (Optional)').fill('SSO-via-OIDC-Fed');
await page.getByLabel('Client ID').fill(oidcClientId);
await page.getByLabel('Client Secret').fill(oidcClientSecret);
await page
.getByLabel('Well-known URL of OpenID Provider')
.fill('http://localhost:5225/.well-known/openid-configuration');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByRole('cell', { name: 'SSO-via-OIDC-Fed' })).toBeVisible();
await use(portal);
// Delete Saml Fed connection
await page.goto('/admin/settings');
await page.getByRole('link', { name: 'Apps' }).click();
await page.waitForURL(/.*admin\/identity-federation$/);
await page.getByRole('cell', { name: 'Edit' }).getByRole('button').click();
await page.getByLabel('Card').getByRole('button', { name: 'Delete' }).click();
await page.getByTestId('confirm-delete').click();
},
});
test('OIDC Federated app + 1 SAML & 1 OIDC providers', async ({ ssoPage, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'OF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
await ssoPage.addSSOConnection({
name: 'OF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockSAML
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('OF-SAML-1');
await ssoPage.signInWithMockSAML();
await portal.isLoggedIn();
// Login using MockLab
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('OF-OIDC-2');
await ssoPage.signInWithMockLab();
await portal.isLoggedIn();
});
test('OIDC Federated app + 2 SAML providers', async ({ ssoPage, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'OF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
await ssoPage.addSSOConnection({
name: 'OF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockSAML-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('OF-SAML-1');
await ssoPage.signInWithMockSAML();
await portal.isLoggedIn();
// Login using MockSAML-2
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('OF-SAML-2');
await ssoPage.signInWithMockSAML();
await portal.isLoggedIn();
});
test('OIDC Federated app + 2 OIDC providers', async ({ ssoPage, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'OF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
await ssoPage.addSSOConnection({
name: 'OF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockLab-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('OF-OIDC-1');
await ssoPage.signInWithMockLab();
await portal.isLoggedIn();
// Login using MockLab-2
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('OF-OIDC-2');
await ssoPage.signInWithMockLab();
await portal.isLoggedIn();
});
test('OIDC Federated app + 1 SAML provider', async ({ ssoPage, page, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'OF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockSAML-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.signInWithMockSAML();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
await portal.isLoggedIn();
});
test('OIDC Federated app + 1 OIDC provider', async ({ ssoPage, page, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'OF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockLab-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.signInWithMockLab();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
await portal.isLoggedIn();
});

View File

@ -0,0 +1,181 @@
import { test as baseTest, expect } from '@playwright/test';
import { Portal, SSOPage } from 'e2e/support/fixtures';
type MyFixtures = {
ssoPage: SSOPage;
portal: Portal;
};
const test = baseTest.extend<MyFixtures>({
ssoPage: async ({ page }, use) => {
const ssoPage = new SSOPage(page);
await use(ssoPage);
// Delete SSO Connections mapped to SAML federation
await ssoPage.deleteSSOConnection('SSO-via-SAML-Fed');
await ssoPage.deleteAllSSOConnections();
},
portal: async ({ page }, use) => {
const portal = new Portal(page);
// Create SAML Federated connection
await page.goto('/admin/settings');
await page.getByRole('link', { name: 'Apps' }).click();
await page.waitForURL(/.*admin\/identity-federation$/);
await page.getByRole('button', { name: 'New App' }).click();
await page.waitForURL(/.*admin\/identity-federation\/new$/);
await page.getByPlaceholder('Your app').and(page.getByLabel('Name')).fill('SF-1');
await page.getByPlaceholder('example.com').and(page.getByLabel('Tenant')).fill('acme.com');
await page.getByLabel('Product').fill('_jackson_admin_portal');
await page.getByLabel('ACS URL').fill('http://localhost:5225/api/oauth/saml');
await page.getByLabel('Entity ID / Audience URI / Audience Restriction').fill('https://saml.boxyhq.com');
await page.getByRole('button', { name: 'Create App' }).click();
await page.waitForURL(/.*admin\/identity-federation\/.*\/edit$/);
await page.getByRole('link', { name: 'Back' }).click();
await page.waitForURL(/.*admin\/identity-federation$/);
await expect(page.getByRole('cell', { name: 'SF-1' })).toBeVisible();
// Add SAML connection via SAML Fed for Admin portal
await page.getByRole('link', { name: 'Single Sign-On' }).click();
await page.getByTestId('create-connection').click();
await page.getByLabel('Connection name (Optional)').fill('SSO-via-SAML-Fed');
await page
.getByPlaceholder('Paste the Metadata URL here')
.fill('http://localhost:5225/.well-known/idp-metadata');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByRole('cell', { name: 'SSO-via-SAML-Fed' })).toBeVisible();
await use(portal);
// Delete Saml Fed connection
await page.goto('/admin/settings');
await page.getByRole('link', { name: 'Apps' }).click();
await page.waitForURL(/.*admin\/identity-federation$/);
await page.getByRole('cell', { name: 'Edit' }).getByRole('button').click();
await page.getByLabel('Card').getByRole('button', { name: 'Delete' }).click();
await page.getByTestId('confirm-delete').click();
},
});
test('SAML Federated app + 1 SAML & 1 OIDC providers', async ({ ssoPage, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'SF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
await ssoPage.addSSOConnection({
name: 'SF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockSAML
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('SF-SAML-1');
await ssoPage.signInWithMockSAML();
await portal.isLoggedIn();
// Login using MockLab
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('SF-OIDC-2');
await ssoPage.signInWithMockLab();
await portal.isLoggedIn();
});
test('SAML Federated app + 2 SAML providers', async ({ ssoPage, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'SF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
await ssoPage.addSSOConnection({
name: 'SF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockSAML-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('SF-SAML-1');
await ssoPage.signInWithMockSAML();
await portal.isLoggedIn();
// Login using MockSAML-2
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('SF-SAML-2');
await ssoPage.signInWithMockSAML();
await portal.isLoggedIn();
});
test('SAML Federated app + 2 OIDC providers', async ({ ssoPage, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'SF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
await ssoPage.addSSOConnection({
name: 'SF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockLab-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('SF-OIDC-1');
await ssoPage.signInWithMockLab();
await portal.isLoggedIn();
// Login using MockLab-2
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.selectIdP('SF-OIDC-2');
await ssoPage.signInWithMockLab();
await portal.isLoggedIn();
});
test('SAML Federated app + 1 SAML provider', async ({ ssoPage, page, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'SF-SAML',
type: 'saml',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockSAML-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.signInWithMockSAML();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
await portal.isLoggedIn();
});
test('SAML Federated app + 1 OIDC provider', async ({ ssoPage, page, portal, baseURL }) => {
// Add SSO connection for tenants
await ssoPage.addSSOConnection({
name: 'SF-OIDC',
type: 'oidc',
baseURL: baseURL!,
tenant: 'acme.com',
product: '_jackson_admin_portal',
});
// Login using MockLab-1
await ssoPage.logout();
await ssoPage.signInWithSSO();
await ssoPage.signInWithMockLab();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
await portal.isLoggedIn();
});

View File

@ -19,70 +19,86 @@ const MOCKLAB_CLIENT_SECRET = 'mocklab_secret';
const MOCKLAB_SIGNIN_BUTTON_NAME = 'Login';
test.describe('Admin Portal SSO - SAML', () => {
test('should be able to add SSO connection to mocksaml', async ({ page }) => {
await page.goto('/admin/settings');
// Find the new connection button and click on it
await page.getByTestId('create-connection').click();
// Fill the name for the connection
const nameInput = page.getByLabel('Connection name (Optional)');
await nameInput.fill(TEST_SAML_SSO_CONNECTION_NAME);
// Enter the metadata url for mocksaml in the form
const metadataUrlInput = page.getByLabel('Metadata URL');
await metadataUrlInput.fill(MOCKSAML_METADATA_URL);
// submit the form
await page.getByRole('button', { name: /save/i }).click();
// check if the added connection appears in the connection list
await expect(page.getByText(TEST_SAML_SSO_CONNECTION_NAME)).toBeVisible();
});
const samlMetadataMode = ['metadataUrl', 'rawMetadata'];
for (const mode of samlMetadataMode) {
test.describe(`SSO Connection via ${mode}`, () => {
test('should be able to add SSO connection to mocksaml', async ({ page }) => {
await page.goto('/admin/settings');
// Find the new connection button and click on it
await page.getByTestId('create-connection').click();
// Fill the name for the connection
const nameInput = page.getByLabel('Connection name (Optional)');
await nameInput.fill(TEST_SAML_SSO_CONNECTION_NAME);
if (mode === 'metadataUrl') {
// Enter the metadata url for mocksaml in the form
const metadataUrlInput = page.getByLabel('Metadata URL');
await metadataUrlInput.fill(MOCKSAML_METADATA_URL);
} else {
// Enter the raw metadata
const rawMetadataInput = page.getByLabel('Raw IdP XML');
await rawMetadataInput.fill(process.env.MOCKSAML_METADATA!);
}
// submit the form
await page.getByRole('button', { name: /save/i }).click();
// check if the added connection appears in the connection list
await expect(page.getByText(TEST_SAML_SSO_CONNECTION_NAME)).toBeVisible();
});
test('should be able to login with mocksaml via SP initiated SSO', async ({ page, baseURL }) => {
const userAvatarLocator = page.getByTestId('user-avatar');
// Logout from the magic link authentication
await page.goto('/');
await userAvatarLocator.click();
await page.getByTestId('logout').click();
// Click on login with sso button
await page.getByTestId('sso-login-button').click();
// Perform sign in at mocksaml
await page.waitForURL((url) => url.origin === MOCKSAML_ORIGIN);
await page.getByPlaceholder('jackson').fill('bob');
await page.getByRole('button', { name: MOCKSAML_SIGNIN_BUTTON_NAME }).click();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// assert login state
await expect(userAvatarLocator).toBeVisible();
});
test('should be able to login with mocksaml via SP initiated SSO', async ({ page, baseURL }) => {
const userAvatarLocator = page.getByTestId('user-avatar');
// Logout from the magic link authentication
await page.goto('/');
await userAvatarLocator.click();
await page.getByTestId('logout').click();
// Click on login with sso button
await page.getByTestId('sso-login-button').click();
// Perform sign in at mocksaml
await page.waitForURL((url) => url.origin === MOCKSAML_ORIGIN);
await page.getByPlaceholder('jackson').fill('bob');
await page.getByRole('button', { name: MOCKSAML_SIGNIN_BUTTON_NAME }).click();
// Wait for browser to redirect back to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// assert login state
await expect(userAvatarLocator).toBeVisible();
});
test('should be able to login with mocksaml via IdP initiated SSO', async ({ page, baseURL }) => {
const userAvatarLocator = page.getByTestId('user-avatar');
// Logout from the magic link authentication
await page.goto('/');
await userAvatarLocator.click();
await page.getByTestId('logout').click();
await expect(page.getByTestId('sso-login-button')).toBeVisible();
// Go directly to mocksaml hosting
await page.goto(MOCKSAML_ORIGIN);
await page.getByRole('link', { name: 'Test IdP Login' }).click();
await page.getByPlaceholder('https://sso.eu.boxyhq.com/api/oauth/saml').fill(`${baseURL}/api/oauth/saml`);
await page.getByRole('textbox', { name: 'Please provide a mock email address' }).fill('bob');
await page.getByRole('button', { name: MOCKSAML_SIGNIN_BUTTON_NAME }).click();
// Wait for browser to redirect to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// assert login state
await expect(userAvatarLocator).toBeVisible();
});
test('should be able to login with mocksaml via IdP initiated SSO', async ({ page, baseURL }) => {
const userAvatarLocator = page.getByTestId('user-avatar');
// Logout from the magic link authentication
await page.goto('/');
await userAvatarLocator.click();
await page.getByTestId('logout').click();
await expect(page.getByTestId('sso-login-button')).toBeVisible();
// Go directly to mocksaml hosting
await page.goto(MOCKSAML_ORIGIN);
await page.getByRole('link', { name: 'Test IdP Login' }).click();
await page
.getByPlaceholder('https://sso.eu.boxyhq.com/api/oauth/saml')
.fill(`${baseURL}/api/oauth/saml`);
await page.getByRole('textbox', { name: 'Please provide a mock email address' }).fill('bob');
await page.getByRole('button', { name: MOCKSAML_SIGNIN_BUTTON_NAME }).click();
// Wait for browser to redirect to admin portal
await page.waitForURL((url) => url.origin === baseURL);
// assert login state
await expect(userAvatarLocator).toBeVisible();
});
test('delete the SAML SSO connection', async ({ page }) => {
await page.goto('/admin/settings');
// select the row of the connection list table, then locate the edit button
const editButton = page.getByText(TEST_SAML_SSO_CONNECTION_NAME).locator('..').getByLabel('Edit');
await editButton.click();
// click the delete and confirm deletion
await page.getByRole('button', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// check that the SSO connection is deleted from the connection list
await expect(page.getByText(TEST_SAML_SSO_CONNECTION_NAME)).not.toBeVisible();
});
test('delete the SAML SSO connection', async ({ page }) => {
await page.goto('/admin/settings');
// select the row of the connection list table, then locate the edit button
const editButton = page
.getByText(TEST_SAML_SSO_CONNECTION_NAME)
.locator('xpath=..')
.getByLabel('Edit');
await editButton.click();
// click the delete and confirm deletion
await page.getByRole('button', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
// check that the SSO connection is deleted from the connection list
await expect(page.getByText(TEST_SAML_SSO_CONNECTION_NAME)).not.toBeVisible();
});
});
}
});
test.describe('Admin Portal SSO - OIDC', () => {
@ -138,7 +154,7 @@ test.describe('Admin Portal SSO - OIDC', () => {
await page.getByTestId('logout').click();
// Click on login with sso button
await page.getByTestId('sso-login-button').click();
// Perform sign in at mocksaml
// Perform sign in at mocklab
await page.waitForURL((url) => url.origin === MOCKLAB_ORIGIN);
await page.getByPlaceholder('yours@example.com').fill('bob@oidc.com');
await page.getByRole('button', { name: MOCKLAB_SIGNIN_BUTTON_NAME }).click();

View File

@ -136,7 +136,12 @@ const Branding = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
<label className='label'>
<span className='label-text'>{t('bui-shared-primary-color')}</span>
</label>
<input type='color' id='primaryColor' onChange={onChange} value={branding.primaryColor || ''} />
<input
type='color'
id='primaryColor'
onChange={onChange}
value={branding.primaryColor || '#25c2a0'}
/>
<label className='label'>
<span className='label-text-alt'>{t('bui-shared-primary-color-desc')}</span>
</label>

View File

@ -1,65 +0,0 @@
import { AppRequestParams } from '@boxyhq/saml-jackson';
import { NextApiRequest, NextApiResponse } from 'next';
import jackson from '@lib/jackson';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
switch (req.method) {
case 'POST':
await handlePOST(req, res);
break;
case 'GET':
await handleGET(req, res);
break;
case 'PATCH':
await handlePATCH(req, res);
break;
case 'DELETE':
await handleDELETE(req, res);
break;
default:
res.setHeader('Allow', 'POST, GET, PATCH, DELETE');
res.status(405).json({ error: { message: `Method ${req.method} Not Allowed` } });
}
} catch (error: any) {
const { message, statusCode = 500 } = error;
res.status(statusCode).json({ error: { message } });
}
}
// Create a SAML federated app
const handlePOST = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const app = await samlFederatedController.app.create(req.body);
res.status(201).json({ data: app });
};
// Get a SAML federated app by ID
const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const app = await samlFederatedController.app.get(req.query as AppRequestParams);
res.json({ data: app });
};
// Update a SAML federated app
const handlePATCH = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const app = await samlFederatedController.app.update(req.body);
res.json({ data: app });
};
// Delete a SAML federated app
const handleDELETE = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
await samlFederatedController.app.delete(req.query as AppRequestParams);
res.json({ data: {} });
};

View File

@ -13,12 +13,12 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
// Get Identity Federation app by id
const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const { id } = req.query as { id: string };
const app = await samlFederatedController.app.get({ id });
const metadata = await samlFederatedController.app.getMetadata();
const app = await identityFederationController.app.get({ id });
const metadata = await identityFederationController.app.getMetadata();
res.json({
data: {
@ -30,20 +30,20 @@ const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
// Update Identity Federation app
const handlePATCH = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const updatedApp = await samlFederatedController.app.update(req.body);
const updatedApp = await identityFederationController.app.update(req.body);
res.json({ data: updatedApp });
};
// Delete the Identity Federation app
const handleDELETE = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const { id } = req.query as { id: string };
await samlFederatedController.app.delete({ id });
await identityFederationController.app.delete({ id });
res.json({ data: null });
};

View File

@ -3,6 +3,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '@lib/jackson';
import { defaultHandler } from '@lib/api';
import { parsePaginateApiParams } from '@lib/utils';
import { validateDevelopmentModeLimits } from '@lib/development-mode';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
await defaultHandler(req, res, {
@ -13,20 +14,26 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
// Create new Identity Federation app
const handlePOST = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const app = await samlFederatedController.app.create(req.body);
await validateDevelopmentModeLimits(
req.body.product,
'identityFederation',
'Maximum number of federation apps reached'
);
const app = await identityFederationController.app.create(req.body);
res.status(201).json({ data: app });
};
// Get Identity Federation apps
const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const { pageOffset, pageLimit, pageToken } = parsePaginateApiParams(req.query);
const apps = await samlFederatedController.app.getAll({
const apps = await identityFederationController.app.getAll({
pageOffset,
pageLimit,
pageToken,

View File

@ -3,29 +3,24 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '@lib/jackson';
import stream from 'stream';
import { promisify } from 'util';
import { defaultHandler } from '@lib/api';
const pipeline = promisify(stream.pipeline);
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req;
switch (method) {
case 'GET':
return await handleGET(req, res);
default:
res.setHeader('Allow', 'GET');
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } });
}
await defaultHandler(req, res, {
GET: handleGET,
});
}
// Display the metadata for the SAML federation
const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const { download } = req.query as { download: any };
try {
const metadata = await samlFederatedController.app.getMetadata();
const metadata = await identityFederationController.app.getMetadata();
res.setHeader('Content-type', 'text/xml');

View File

@ -65,9 +65,9 @@ async function handleSAMLRequest(req: NextApiRequest, res: NextApiResponse, bind
throw new Error('SAMLRequest is required to proceed.');
}
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const response = await samlFederatedController.sso.getAuthorizeUrl({
const response = await identityFederationController.sso.getAuthorizeUrl({
request: samlRequest,
relayState,
idp_hint: idpHint,

View File

@ -0,0 +1,57 @@
import { AppRequestParams } from '@boxyhq/saml-jackson';
import { NextApiRequest, NextApiResponse } from 'next';
import jackson from '@lib/jackson';
import { validateDevelopmentModeLimits } from '@lib/development-mode';
import { defaultHandler } from '@lib/api';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await defaultHandler(req, res, {
POST: handlePOST,
GET: handleGET,
PATCH: handlePATCH,
DELETE: handleDELETE,
});
}
// Create a SAML federated app
const handlePOST = async (req: NextApiRequest, res: NextApiResponse) => {
const { identityFederationController } = await jackson();
await validateDevelopmentModeLimits(
req.body.product,
'identityFederation',
'Maximum number of federation apps reached'
);
const app = await identityFederationController.app.create(req.body);
res.status(201).json({ data: app });
};
// Get a SAML federated app by ID
const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { identityFederationController } = await jackson();
const app = await identityFederationController.app.get(req.query as AppRequestParams);
res.json({ data: app });
};
// Update a SAML federated app
const handlePATCH = async (req: NextApiRequest, res: NextApiResponse) => {
const { identityFederationController } = await jackson();
const app = await identityFederationController.app.update(req.body);
res.json({ data: app });
};
// Delete a SAML federated app
const handleDELETE = async (req: NextApiRequest, res: NextApiResponse) => {
const { identityFederationController } = await jackson();
await identityFederationController.app.delete(req.query as AppRequestParams);
res.json({ data: {} });
};

View File

@ -2,26 +2,17 @@ import { NextApiRequest, NextApiResponse } from 'next';
import jackson from '@lib/jackson';
import { parsePaginateApiParams } from '@lib/utils';
import { defaultHandler } from '@lib/api';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
switch (req.method) {
case 'GET':
await handleGET(req, res);
break;
default:
res.setHeader('Allow', 'GET');
res.status(405).json({ error: { message: `Method ${req.method} Not Allowed` } });
}
} catch (error: any) {
const { message, statusCode = 500 } = error;
res.status(statusCode).json({ error: { message } });
}
await defaultHandler(req, res, {
GET: handleGET,
});
}
// Get SAML federated apps filtered by the product
const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { samlFederatedController } = await jackson();
const { identityFederationController } = await jackson();
const { product } = req.query as {
product: string;
@ -29,7 +20,7 @@ const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { pageOffset, pageLimit, pageToken } = parsePaginateApiParams(req.query);
const apps = await samlFederatedController.app.getByProduct({
const apps = await identityFederationController.app.getByProduct({
product,
pageOffset,
pageLimit,

View File

@ -2,7 +2,7 @@ import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { errorToast, successToast } from '@components/Toaster';
import LicenseRequired from '@components/LicenseRequired';
import { EditFederatedSAMLApp, LinkBack } from '@boxyhq/internal-ui';
import { EditIdentityFederationApp, LinkBack } from '@boxyhq/internal-ui';
import 'react-tagsinput/react-tagsinput.css';
@ -18,19 +18,19 @@ const UpdateApp = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
return (
<div className='space-y-4'>
<LinkBack href='/admin/federated-saml' />
<EditFederatedSAMLApp
<LinkBack href='/admin/identity-federation' />
<EditIdentityFederationApp
urls={{
getApp: `/api/admin/federated-saml/${id}`,
updateApp: `/api/admin/federated-saml/${id}`,
deleteApp: `/api/admin/federated-saml/${id}`,
getApp: `/api/admin/identity-federation/${id}`,
updateApp: `/api/admin/identity-federation/${id}`,
deleteApp: `/api/admin/identity-federation/${id}`,
}}
onUpdate={() => {
successToast(t('saml_federation_update_success'));
successToast(t('identity_federation_update_success'));
}}
onDelete={() => {
successToast(t('saml_federation_delete_success'));
router.push('/admin/federated-saml');
successToast(t('identity_federation_delete_success'));
router.push('/admin/identity-federation');
}}
onError={(error) => {
errorToast(error.message);

View File

@ -1,6 +1,6 @@
import router from 'next/router';
import LicenseRequired from '@components/LicenseRequired';
import { FederatedSAMLApps } from '@boxyhq/internal-ui';
import { IdentityFederationApps } from '@boxyhq/internal-ui';
const AppsList = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
if (!hasValidLicense) {
@ -8,11 +8,11 @@ const AppsList = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
}
return (
<FederatedSAMLApps
urls={{ getApps: '/api/admin/federated-saml' }}
onEdit={(app) => router.push(`/admin/federated-saml/${app.id}/edit`)}
<IdentityFederationApps
urls={{ getApps: '/api/admin/identity-federation' }}
onEdit={(app) => router.push(`/admin/identity-federation/${app.id}/edit`)}
actions={{
newApp: '/admin/federated-saml/new',
newApp: '/admin/identity-federation/new',
samlConfiguration: '/.well-known/idp-configuration',
oidcConfiguration: '/.well-known/openid-configuration',
}}

View File

@ -1,12 +1,12 @@
import Link from 'next/link';
import { useTranslation } from 'next-i18next';
import type { SAMLFederationAppWithMetadata } from '@boxyhq/saml-jackson';
import type { IdentityFederationAppWithMetadata } from '@boxyhq/saml-jackson';
import { Toaster } from '@components/Toaster';
import { InputWithCopyButton, CopyToClipboardButton, LinkOutline } from '@boxyhq/internal-ui';
import LicenseRequired from '@components/LicenseRequired';
type MetadataProps = {
metadata: Pick<SAMLFederationAppWithMetadata, 'metadata'>['metadata'];
metadata: Pick<IdentityFederationAppWithMetadata, 'metadata'>['metadata'];
hasValidLicense: boolean;
};

View File

@ -2,7 +2,7 @@ import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { errorToast, successToast } from '@components/Toaster';
import LicenseRequired from '@components/LicenseRequired';
import { NewFederatedSAMLApp, LinkBack } from '@boxyhq/internal-ui';
import { NewIdentityFederationApp, LinkBack } from '@boxyhq/internal-ui';
import 'react-tagsinput/react-tagsinput.css';
@ -16,12 +16,12 @@ const NewApp = ({ hasValidLicense, samlAudience }: { hasValidLicense: boolean; s
return (
<div className='space-y-4'>
<LinkBack href='/admin/federated-saml' />
<NewFederatedSAMLApp
urls={{ createApp: '/api/admin/federated-saml' }}
<LinkBack href='/admin/identity-federation' />
<NewIdentityFederationApp
urls={{ createApp: '/api/admin/identity-federation' }}
onSuccess={(data) => {
successToast(t('saml_federation_new_success'));
router.replace(`/admin/federated-saml/${data.id}/edit`);
successToast(t('identity_federation_new_success'));
router.replace(`/admin/identity-federation/${data.id}/edit`);
}}
onError={(error) => {
errorToast(error.message);

File diff suppressed because it is too large Load Diff

View File

@ -26,21 +26,21 @@
},
"devDependencies": {
"@rollup/plugin-typescript": "11.1.6",
"@types/node": "20.12.7",
"@types/react": "18.2.79",
"@typescript-eslint/eslint-plugin": "7.7.1",
"@typescript-eslint/parser": "7.7.1",
"@vitejs/plugin-react": "4.2.1",
"@types/node": "20.12.12",
"@types/react": "18.3.3",
"@typescript-eslint/eslint-plugin": "7.11.0",
"@typescript-eslint/parser": "7.11.0",
"@vitejs/plugin-react": "4.3.0",
"eslint": "8.57.0",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-react-refresh": "0.4.6",
"eslint-plugin-react-hooks": "4.6.2",
"eslint-plugin-react-refresh": "0.4.7",
"prettier": "3.2.5",
"react-daisyui": "5.0.0",
"typescript": "5.4.5",
"vite": "5.2.10"
"vite": "5.2.11"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.16.3"
"@rollup/rollup-linux-x64-gnu": "4.18.0"
},
"peerDependencies": {
"@boxyhq/react-ui": ">=3.3.42",

View File

@ -1,3 +0,0 @@
export { NewFederatedSAMLApp } from './NewFederatedSAMLApp';
export { EditFederatedSAMLApp } from './EditFederatedSAMLApp';
export { FederatedSAMLApps } from './FederatedSAMLApps';

View File

@ -1,3 +1,4 @@
export { usePaginate } from './usePaginate';
export { useDirectory } from './useDirectory';
export { useRouter } from './useRouter';
export { useFetch } from './useFetch';

View File

@ -0,0 +1,50 @@
import { useEffect, useState } from 'react';
type RefetchFunction = () => void;
async function parseResponseContent(response: Response) {
const responseText = await response.text();
try {
return responseText.length ? JSON.parse(responseText) : '';
} catch (err) {
return responseText;
}
}
export function useFetch<T>({ url }: { url: string }): {
data?: T;
isLoading: boolean;
error: any;
refetch: RefetchFunction;
} {
const [data, setData] = useState<T>();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<any>(null);
const [refetchIndex, setRefetchIndex] = useState<number>(0);
const refetch = () => setRefetchIndex((prevRefetchIndex) => prevRefetchIndex + 1);
useEffect(() => {
async function fetchData() {
setIsLoading(true);
const res = await fetch(url);
setIsLoading(false);
const resContent = await parseResponseContent(res);
if (res.ok) {
const pageToken = res.headers.get('jackson-pagetoken');
if (pageToken !== null) {
setData({ ...resContent, pageToken });
} else {
setData(resContent);
}
} else {
setError(resContent.error);
}
}
fetchData();
}, [url, refetchIndex]);
return { data, isLoading, error, refetch };
}

View File

@ -1,6 +1,6 @@
import { useState } from 'react';
import { Button } from 'react-daisyui';
import type { SAMLFederationApp } from '../types';
import type { IdentityFederationApp } from '../types';
import TagsInput from 'react-tagsinput';
import { useTranslation } from 'next-i18next';
import { useFormik } from 'formik';
@ -13,7 +13,7 @@ import { ItemList } from '@boxyhq/react-ui/shared';
import { CopyToClipboardButton } from '../shared/InputWithCopyButton';
import { IconButton } from '../shared/IconButton';
type EditApp = Pick<SAMLFederationApp, 'name' | 'acsUrl' | 'tenants' | 'redirectUrl'>;
type EditApp = Pick<IdentityFederationApp, 'name' | 'acsUrl' | 'tenants' | 'redirectUrl'>;
export const Edit = ({
app,
@ -22,9 +22,9 @@ export const Edit = ({
onUpdate,
excludeFields,
}: {
app: SAMLFederationApp;
app: IdentityFederationApp;
urls: { patch: string };
onUpdate?: (data: SAMLFederationApp) => void;
onUpdate?: (data: IdentityFederationApp) => void;
onError?: (error: Error) => void;
excludeFields?: 'product'[];
}) => {

View File

@ -1,12 +1,12 @@
import { Button } from 'react-daisyui';
import { useTranslation } from 'next-i18next';
import type { SAMLFederationApp } from '../types';
import type { IdentityFederationApp } from '../types';
import { useFormik } from 'formik';
import { defaultHeaders } from '../utils';
import { Card } from '../shared';
import { AttributesMapping } from './AttributesMapping';
type Mappings = Pick<SAMLFederationApp, 'mappings'>;
type Mappings = Pick<IdentityFederationApp, 'mappings'>;
export const EditAttributesMapping = ({
app,
@ -14,9 +14,9 @@ export const EditAttributesMapping = ({
onUpdate,
onError,
}: {
app: SAMLFederationApp;
app: IdentityFederationApp;
urls: { patch: string };
onUpdate?: (data: SAMLFederationApp) => void;
onUpdate?: (data: IdentityFederationApp) => void;
onError?: (error: Error) => void;
}) => {
const { t } = useTranslation('common');

View File

@ -1,11 +1,11 @@
import { Button } from 'react-daisyui';
import { useTranslation } from 'next-i18next';
import type { SAMLFederationApp } from '../types';
import type { IdentityFederationApp } from '../types';
import { useFormik } from 'formik';
import { defaultHeaders } from '../utils';
import { Card } from '../shared';
type Branding = Pick<SAMLFederationApp, 'logoUrl' | 'faviconUrl' | 'primaryColor'>;
type Branding = Pick<IdentityFederationApp, 'logoUrl' | 'faviconUrl' | 'primaryColor'>;
export const EditBranding = ({
app,
@ -13,9 +13,9 @@ export const EditBranding = ({
onUpdate,
onError,
}: {
app: SAMLFederationApp;
app: IdentityFederationApp;
urls: { patch: string };
onUpdate?: (data: SAMLFederationApp) => void;
onUpdate?: (data: IdentityFederationApp) => void;
onError?: (error: Error) => void;
}) => {
const { t } = useTranslation('common');

View File

@ -1,5 +1,5 @@
import useSWR from 'swr';
import type { SAMLFederationApp } from '../types';
import type { IdentityFederationApp } from '../types';
import { EditBranding } from './EditBranding';
import { Edit } from './Edit';
import { EditAttributesMapping } from './EditAttributesMapping';
@ -9,7 +9,7 @@ import { useEffect, useState } from 'react';
import { defaultHeaders, fetcher } from '../utils';
import { PageHeader } from '../shared';
export const EditFederatedSAMLApp = ({
export const EditIdentityFederationApp = ({
urls,
onError,
onUpdate,
@ -17,7 +17,7 @@ export const EditFederatedSAMLApp = ({
excludeFields,
}: {
urls: { getApp: string; updateApp: string; deleteApp: string };
onUpdate?: (data: SAMLFederationApp) => void;
onUpdate?: (data: IdentityFederationApp) => void;
onError?: (error: Error) => void;
onDelete?: () => void;
excludeFields?: 'product'[];
@ -25,7 +25,7 @@ export const EditFederatedSAMLApp = ({
const { t } = useTranslation('common');
const [delModalVisible, setDelModalVisible] = useState(false);
const { data, isLoading, error, mutate } = useSWR<{ data: SAMLFederationApp }>(urls.getApp, fetcher);
const { data, isLoading, error, mutate } = useSWR<{ data: IdentityFederationApp }>(urls.getApp, fetcher);
useEffect(() => {
if (error) {

View File

@ -1,5 +1,3 @@
import useSWR from 'swr';
import { fetcher } from '../utils';
import {
Loading,
Table,
@ -11,17 +9,17 @@ import {
ButtonPrimary,
} from '../shared';
import { useTranslation } from 'next-i18next';
import type { SAMLFederationApp } from '../types';
import type { IdentityFederationApp } from '../types';
import PencilIcon from '@heroicons/react/24/outline/PencilIcon';
import { TableBodyType } from '../shared/Table';
import { pageLimit } from '../shared/Pagination';
import { usePaginate } from '../hooks';
import { useFetch, usePaginate } from '../hooks';
import { useRouter } from '../hooks';
import { useEffect } from 'react';
type ExcludeFields = keyof Pick<SAMLFederationApp, 'product'>;
type ExcludeFields = keyof Pick<IdentityFederationApp, 'product'>;
export const FederatedSAMLApps = ({
export const IdentityFederationApps = ({
urls,
excludeFields,
onEdit,
@ -30,9 +28,9 @@ export const FederatedSAMLApps = ({
}: {
urls: { getApps: string };
excludeFields?: ExcludeFields[];
onEdit?: (app: SAMLFederationApp) => void;
onEdit?: (app: IdentityFederationApp) => void;
actions: { newApp: string; samlConfiguration: string; oidcConfiguration: string };
actionCols?: { text: string; onClick: (app: SAMLFederationApp) => void; icon: JSX.Element }[];
actionCols?: { text: string; onClick: (app: IdentityFederationApp) => void; icon: JSX.Element }[];
}) => {
const { router } = useRouter();
const { t } = useTranslation('common');
@ -45,10 +43,9 @@ export const FederatedSAMLApps = ({
getAppsUrl += `&pageToken=${pageTokenMap[paginate.offset - pageLimit]}`;
}
const { data, isLoading, error } = useSWR<{ data: SAMLFederationApp[]; pageToken?: string }>(
getAppsUrl,
fetcher
);
const { data, isLoading, error } = useFetch<{ data: IdentityFederationApp[]; pageToken?: string }>({
url: getAppsUrl,
});
const nextPageToken = data?.pageToken;

View File

@ -2,19 +2,19 @@ import { useFormik } from 'formik';
import TagsInput from 'react-tagsinput';
import { Card, Button } from 'react-daisyui';
import { useTranslation } from 'next-i18next';
import type { SAMLFederationApp } from '../types';
import type { IdentityFederationApp } from '../types';
import QuestionMarkCircleIcon from '@heroicons/react/24/outline/QuestionMarkCircleIcon';
import { defaultHeaders } from '../utils';
import { AttributesMapping } from './AttributesMapping';
import { PageHeader } from '../shared';
import { ItemList } from '@boxyhq/react-ui/shared';
type NewSAMLFederationApp = Pick<
SAMLFederationApp,
type NewIdentityFederationApp = Pick<
IdentityFederationApp,
'name' | 'tenant' | 'product' | 'acsUrl' | 'entityId' | 'tenants' | 'mappings' | 'type' | 'redirectUrl'
>;
export const NewFederatedSAMLApp = ({
export const NewIdentityFederationApp = ({
samlAudience = 'https://saml.boxyhq.com',
urls,
onSuccess,
@ -24,14 +24,14 @@ export const NewFederatedSAMLApp = ({
}: {
samlAudience?: string;
urls: { createApp: string };
onSuccess?: (data: SAMLFederationApp) => void;
onSuccess?: (data: IdentityFederationApp) => void;
onError?: (error: Error) => void;
onEntityIdGenerated?: (entityId: string) => void;
excludeFields?: 'product'[];
}) => {
const { t } = useTranslation('common');
const initialValues: NewSAMLFederationApp = {
const initialValues: NewIdentityFederationApp = {
type: 'saml',
name: '',
tenant: '',
@ -44,11 +44,11 @@ export const NewFederatedSAMLApp = ({
if (excludeFields) {
excludeFields.forEach((key) => {
delete initialValues[key as keyof NewSAMLFederationApp];
delete initialValues[key as keyof NewIdentityFederationApp];
});
}
const formik = useFormik<NewSAMLFederationApp>({
const formik = useFormik<NewIdentityFederationApp>({
initialValues: initialValues,
onSubmit: async (values) => {
const rawResponse = await fetch(urls.createApp, {

View File

@ -0,0 +1,3 @@
export { NewIdentityFederationApp } from './NewIdentityFederationApp';
export { EditIdentityFederationApp } from './EditIdentityFederationApp';
export { IdentityFederationApps } from './IdentityFederationApps';

View File

@ -1,7 +1,7 @@
export * from './well-known';
export * from './federated-saml';
export * from './identity-federation';
export * from './shared';
export * from './dsync';
export * from './provider';
export * from './sso-tracer';
export * from './sso-traces';
export * from './setup-link';

View File

@ -13,7 +13,7 @@ export const SetupLinkInfo = ({ setupLink, onClose }: { setupLink: SetupLink; on
<Card className='border-primary'>
<Card.Body>
<div>
<InputWithCopyButton text={setupLink.url} label={t('bui-sl-share-info')} />
<InputWithCopyButton text={setupLink.url} label={t('bui-sl-share-info')} autofocus={true} />
</div>
<div>
<Button size='sm' color='primary' onClick={onClose}>

View File

@ -1,4 +1,3 @@
import useSWR from 'swr';
import { useEffect, useState } from 'react';
import { useTranslation } from 'next-i18next';
import EyeIcon from '@heroicons/react/24/outline/EyeIcon';
@ -6,11 +5,11 @@ import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
import ArrowPathIcon from '@heroicons/react/24/outline/ArrowPathIcon';
import ClipboardDocumentIcon from '@heroicons/react/24/outline/ClipboardDocumentIcon';
import { addQueryParamsToPath, copyToClipboard, fetcher } from '../utils';
import { addQueryParamsToPath, copyToClipboard } from '../utils';
import { TableBodyType } from '../shared/Table';
import { pageLimit } from '../shared/Pagination';
import { usePaginate, useRouter } from '../hooks';
import type { SAMLFederationApp, SetupLink, SetupLinkService } from '../types';
import { usePaginate, useRouter, useFetch } from '../hooks';
import type { IdentityFederationApp, SetupLink, SetupLinkService } from '../types';
import {
Loading,
Table,
@ -24,7 +23,7 @@ import {
} from '../shared';
import { SetupLinkInfoModal } from './SetupLinkInfoModal';
type ExcludeFields = keyof Pick<SAMLFederationApp, 'product'>;
type ExcludeFields = keyof Pick<IdentityFederationApp, 'product'>;
export const SetupLinks = ({
urls,
@ -65,10 +64,9 @@ export const SetupLinks = ({
}
const getLinksUrl = addQueryParamsToPath(urls.getLinks, params);
const { data, isLoading, error, mutate } = useSWR<{ data: SetupLink[]; pageToken?: string }>(
getLinksUrl,
fetcher
);
const { data, isLoading, error, refetch } = useFetch<{ data: SetupLink[]; pageToken?: string }>({
url: getLinksUrl,
});
const nextPageToken = data?.pageToken;
@ -201,7 +199,7 @@ export const SetupLinks = ({
setDelModal(false);
setSetupLink(null);
onDelete(setupLink);
await mutate();
refetch();
} else {
onError(response.error);
}
@ -229,7 +227,7 @@ export const SetupLinks = ({
if (rawResponse.ok) {
onRegenerate(response.data);
setShowRegenModal(false);
await mutate();
refetch();
setSetupLink(response.data);
setShowSetupLink(true);
} else {

View File

@ -19,19 +19,32 @@ export const CopyToClipboardButton = ({ text }: { text: string }) => {
);
};
export const InputWithCopyButton = ({ text, label }: { text: string; label: string }) => {
export const InputWithCopyButton = ({
text,
label,
autofocus = false,
}: {
text: string;
label: string;
autofocus?: boolean;
}) => {
const id = label.replace(/ /g, '');
return (
<>
<div className='flex justify-between'>
<label className='mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300'>{label}</label>
<label className='mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300' htmlFor={id}>
{label}
</label>
<CopyToClipboardButton text={text} />
</div>
<input
id={id}
type='text'
defaultValue={text}
key={text}
readOnly
className='input-bordered input w-full text-sm'
autoFocus={autofocus}
/>
</>
);

View File

@ -1,2 +0,0 @@
export { SSOTracers } from './SSOTracers';
export { SSOTracerInfo } from './SSOTracerInfo';

View File

@ -15,10 +15,10 @@ const ListItem = ({ term, value }: { term: string; value: string | JSX.Element }
</div>
);
export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
export const SSOTraceInfo = ({ urls }: { urls: { getTraces: string } }) => {
const { t } = useTranslation('common');
const { data, isLoading, error } = useSWR<{ data: SSOTrace & { traceId: string } }>(
urls.getTracer,
urls.getTraces,
fetcher
);
@ -42,81 +42,81 @@ export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
if (trace.context.requestedOIDCFlow) {
badgeText = t('bui-shared-oidc-federation');
} else {
badgeText = t('bui-tracer-oauth2-federation');
badgeText = t('bui-traces-oauth2-federation');
}
} else if (trace.context.isSAMLFederated) {
badgeText = t('bui-tracer-saml-federation');
badgeText = t('bui-traces-saml-federation');
} else if (trace.context.isIdPFlow) {
badgeText = t('bui-tracer-idp-login');
badgeText = t('bui-traces-idp-login');
} else if (trace.context.requestedOIDCFlow) {
badgeText = t('bui-shared-oidc');
} else {
badgeText = t('bui-tracer-oauth2');
badgeText = t('bui-traces-oauth2');
}
return (
<div className='space-y-3'>
<PageHeader title={t('bui-tracer-title')} />
<PageHeader title={t('bui-traces-title')} />
<dl className='divide-y'>
<ListItem term={t('bui-tracer-id')} value={trace.traceId} />
<ListItem term={t('bui-traces-id')} value={trace.traceId} />
<ListItem term={t('bui-tracer-assertion-type')} value={assertionType} />
<ListItem term={t('bui-traces-assertion-type')} value={assertionType} />
<ListItem
term={t('bui-tracer-sp-protocol')}
term={t('bui-traces-sp-protocol')}
value={
<Badge
color='primary'
size='md'
className='font-mono uppercase text-white'
aria-label={t('bui-tracer-sp-protocol')!}>
aria-label={t('bui-traces-sp-protocol')!}>
{badgeText}
</Badge>
}
/>
{typeof trace.timestamp === 'number' && (
<ListItem term={t('bui-tracer-timestamp')} value={new Date(trace.timestamp).toLocaleString()} />
<ListItem term={t('bui-traces-timestamp')} value={new Date(trace.timestamp).toLocaleString()} />
)}
<ListItem term={t('bui-tracer-error')} value={trace.error} />
<ListItem term={t('bui-traces-error')} value={trace.error} />
{trace.context.tenant && <ListItem term={t('bui-shared-tenant')} value={trace.context.tenant} />}
{trace.context.product && <ListItem term={t('bui-shared-product')} value={trace.context.product} />}
{trace.context.relayState && (
<ListItem term={t('bui-tracer-relay-state')} value={trace.context.relayState} />
<ListItem term={t('bui-traces-relay-state')} value={trace.context.relayState} />
)}
{trace.context.redirectUri && (
<ListItem
term={
trace.context.isIdPFlow ? t('bui-tracer-default-redirect-url') : t('bui-tracer-redirect-uri')
trace.context.isIdPFlow ? t('bui-traces-default-redirect-url') : t('bui-traces-redirect-uri')
}
value={trace.context.redirectUri}
/>
)}
{trace.context.clientID && (
<ListItem term={t('bui-tracer-sso-connection-client-id')} value={trace.context.clientID} />
<ListItem term={t('bui-traces-sso-connection-client-id')} value={trace.context.clientID} />
)}
{trace.context.issuer && <ListItem term={t('bui-tracer-issuer')} value={trace.context.issuer} />}
{trace.context.issuer && <ListItem term={t('bui-traces-issuer')} value={trace.context.issuer} />}
{trace.context.acsUrl && <ListItem term={t('bui-shared-acs-url')} value={trace.context.acsUrl} />}
{trace.context.entityId && (
<ListItem term={t('bui-tracer-entity-id')} value={trace.context.entityId} />
<ListItem term={t('bui-traces-entity-id')} value={trace.context.entityId} />
)}
{trace.context.providerName && (
<ListItem term={t('bui-tracer-provider')} value={trace.context.providerName} />
<ListItem term={t('bui-traces-provider')} value={trace.context.providerName} />
)}
{assertionType === 'Response' && trace.context.samlResponse && (
<ListItem
term={t('bui-tracer-saml-response')}
term={t('bui-traces-saml-response')}
value={
<>
<CopyToClipboardButton text={trace.context.samlResponse}></CopyToClipboardButton>
@ -130,7 +130,7 @@ export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
{assertionType === 'Request' && trace.context.samlRequest && (
<ListItem
term={t('bui-tracer-saml-request')}
term={t('bui-traces-saml-request')}
value={
<>
<CopyToClipboardButton text={trace.context.samlRequest}></CopyToClipboardButton>
@ -144,7 +144,7 @@ export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
{typeof trace.context.profile === 'object' && trace.context.profile && (
<ListItem
term={t('bui-tracer-profile')}
term={t('bui-traces-profile')}
value={
<SyntaxHighlighter language='json' style={materialOceanic}>
{JSON.stringify(trace.context.profile)}
@ -155,18 +155,18 @@ export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
{trace.context.error_description && (
<ListItem
term={t('bui-tracer-error-description-from-oidc-idp')}
term={t('bui-traces-error-description-from-oidc-idp')}
value={trace.context.error_description}
/>
)}
{trace.context.error_uri && (
<ListItem term={t('bui-tracer-error-uri')} value={trace.context.error_uri} />
<ListItem term={t('bui-traces-error-uri')} value={trace.context.error_uri} />
)}
{trace.context.oidcTokenSet?.id_token && (
<ListItem
term={t('bui-tracer-id-token-from-oidc-idp')}
term={t('bui-traces-id-token-from-oidc-idp')}
value={
<>
<CopyToClipboardButton text={trace.context.oidcTokenSet.id_token}></CopyToClipboardButton>
@ -180,7 +180,7 @@ export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
{trace.context.oidcTokenSet?.access_token && (
<ListItem
term={t('bui-tracer-access-token-from-oidc-idp')}
term={t('bui-traces-access-token-from-oidc-idp')}
value={
<>
<CopyToClipboardButton text={trace.context.oidcTokenSet.access_token}></CopyToClipboardButton>
@ -194,7 +194,7 @@ export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
{trace.context.stack && (
<ListItem
term={t('bui-tracer-stack-trace')}
term={t('bui-traces-stack-trace')}
value={
<SyntaxHighlighter language='shell' style={materialOceanic}>
{trace.context.stack}
@ -205,13 +205,13 @@ export const SSOTracerInfo = ({ urls }: { urls: { getTracer: string } }) => {
{trace.context.session_state_from_op_error && (
<ListItem
term={t('bui-tracer-session-state-from-oidc-idp')}
term={t('bui-traces-session-state-from-oidc-idp')}
value={trace.context.session_state_from_op_error}
/>
)}
{trace.context.scope_from_op_error && (
<ListItem term={t('bui-tracer-scope-from-op-error')} value={trace.context.scope_from_op_error} />
<ListItem term={t('bui-traces-scope-from-op-error')} value={trace.context.scope_from_op_error} />
)}
</dl>
</div>

View File

@ -8,11 +8,11 @@ import type { ApiError, ApiSuccess } from '../types';
import { addQueryParamsToPath, fetcher } from '../utils';
import { Loading, Table, EmptyState, Error, Pagination, PageHeader, pageLimit } from '../shared';
export const SSOTracers = ({
export const SSOTraces = ({
urls,
onView,
}: {
urls: { getTracers: string };
urls: { getTraces: string };
onView: (user: Trace) => void;
}) => {
const { router } = useRouter();
@ -29,7 +29,7 @@ export const SSOTracers = ({
params['pageToken'] = pageTokenMap[paginate.offset - pageLimit];
}
const getUrl = addQueryParamsToPath(urls.getTracers, params);
const getUrl = addQueryParamsToPath(urls.getTraces, params);
const { data, isLoading, error } = useSWR<ApiSuccess<Trace[]>, ApiError>(getUrl, fetcher);
const nextPageToken = data?.pageToken;
@ -57,10 +57,10 @@ export const SSOTracers = ({
const noMoreResults = traces.length === 0 && paginate.offset > 0;
const cols = [
t('bui-tracer-id'),
t('bui-tracer-description'),
t('bui-tracer-assertion-type'),
t('bui-tracer-timestamp'),
t('bui-traces-id'),
t('bui-traces-description'),
t('bui-traces-assertion-type'),
t('bui-traces-timestamp'),
];
const body = traces.map((trace) => {
@ -82,9 +82,9 @@ export const SSOTracers = ({
{
wrap: true,
text: trace.context?.samlResponse
? t('bui-tracer-response')
? t('bui-traces-response')
: trace?.context.samlRequest
? t('bui-tracer-request')
? t('bui-traces-request')
: '-',
},
{
@ -97,9 +97,9 @@ export const SSOTracers = ({
return (
<div className='space-y-3'>
<PageHeader title={t('bui-tracer-title')} />
<PageHeader title={t('bui-traces-title')} />
{noTraces ? (
<EmptyState title={t('bui-tracer-no-traces')} />
<EmptyState title={t('bui-traces-no-traces')} />
) : (
<>
<Table noMoreResults={noMoreResults} cols={cols} body={body} />

View File

@ -0,0 +1,2 @@
export { SSOTraces } from './SSOTraces';
export { SSOTraceInfo } from './SSOTraceInfo';

View File

@ -90,7 +90,7 @@ export type AttributeMapping = {
value: string;
};
export type SAMLFederationApp = {
export type IdentityFederationApp = {
id: string;
type?: string;
clientID?: string;

View File

@ -22,4 +22,4 @@ patches:
images:
- name: boxyhq/jackson
newTag: 1.22.1
newTag: 1.25.1

View File

@ -22,4 +22,4 @@ patches:
images:
- name: boxyhq/jackson
newTag: 1.22.1
newTag: 1.25.1

49
lib/development-mode.ts Normal file
View File

@ -0,0 +1,49 @@
import jackson from './jackson';
import { IndexNames } from 'npm/src/controller/utils';
import { jacksonOptions } from '@lib/env';
type Module = 'sso' | 'dsync' | 'identityFederation';
export const validateDevelopmentModeLimits = async (
productId: string,
type: Module,
message: string = 'Maximum number of connections reached'
) => {
if (productId && jacksonOptions.boxyhqHosted) {
const {
productController,
connectionAPIController,
directorySyncController,
identityFederationController,
} = await jackson();
const getController = async (type: Module) => {
switch (type) {
case 'sso':
return connectionAPIController;
case 'dsync':
return directorySyncController.directories;
case 'identityFederation':
return identityFederationController.app;
default:
return {
getCount: () => null,
};
}
};
const product = await productController.get(productId);
if (product?.development) {
const controller = await getController(type);
const count = await controller.getCount({
name: IndexNames.Product,
value: productId,
});
if (count) {
if (count >= 3) {
throw { message, statusCode: 400 };
}
}
}
}
};

View File

@ -1,4 +1,5 @@
{
"apps": "Apps",
"error_loading_page": "Unable to load this page. Maybe you don't have enough rights.",
"documentation": "Documentation",
"back": "Back",
@ -29,9 +30,9 @@
"send_magic_link": "Send Magic Link",
"setup_links": "Setup Links",
"edit_directory": "Edit Directory",
"saml_federation_new_success": "Identity Federation app created successfully.",
"saml_federation_update_success": "Identity Federation app updated successfully.",
"saml_federation_delete_success": "Identity federation app deleted successfully",
"identity_federation_new_success": "Identity Federation app created successfully.",
"identity_federation_update_success": "Identity Federation app updated successfully.",
"identity_federation_delete_success": "Identity Federation app deleted successfully",
"saml_federation_app_info": "SAML Federation App Information",
"saml_federation_app_info_details": "Choose from the following options to configure your SAML Federation on the service provider side",
"download_metadata": "Download Metadata",
@ -41,7 +42,7 @@
"directory_created_successfully": "Directory created successfully",
"directory_updated_successfully": "Directory updated successfully",
"dashboard": "Dashboard",
"saml_federation": "Identity Federation",
"identity_federation": "Identity Federation",
"settings": "Settings",
"admin_portal_sso": "SSO for Admin Portal",
"configuration": "Configuration",
@ -224,37 +225,37 @@
"bui-dsync-authorization-google": "Authorize Google Workspace",
"bui-dsync-authorization-google-desc": "You should authorize Google Workspace to sync your directory. Click the button below start the authorization process. Make sure you have the necessary permissions to authorize Google Workspace.",
"bui-dsync-google-domain": "Google Domain",
"bui-tracer-title": "SSO Tracer",
"bui-tracer-id": "Trace ID",
"bui-tracer-description": "Description",
"bui-tracer-assertion-type": "Assertion Type",
"bui-tracer-timestamp": "Timestamp",
"bui-tracer-response": "Response",
"bui-tracer-request": "Request",
"bui-tracer-no-traces": "No SSO Traces recorded yet.",
"bui-tracer-sp-protocol": "SP Protocol",
"bui-tracer-saml-federation": "SAML Federation",
"bui-tracer-oauth2-federation": "OAuth 2.0 Federation",
"bui-tracer-idp-login": "IdP Login",
"bui-tracer-oauth2": "OAuth 2.0",
"bui-tracer-error": "Error",
"bui-tracer-relay-state": "Relay State",
"bui-tracer-default-redirect-url": "Default Redirect URL",
"bui-tracer-redirect-uri": "Redirect URI",
"bui-tracer-sso-connection-client-id": "SSO Connection Client ID",
"bui-tracer-issuer": "Issuer",
"bui-tracer-entity-id": "Entity ID",
"bui-tracer-provider": "Provider",
"bui-tracer-saml-response": "SAML Response",
"bui-tracer-saml-request": "SAML Request",
"bui-tracer-profile": "Profile",
"bui-tracer-error-description-from-oidc-idp": "Error Description (from OIDC Provider)",
"bui-tracer-error-uri": "Error URI",
"bui-tracer-id-token-from-oidc-idp": "ID Token (from OIDC Provider)",
"bui-tracer-access-token-from-oidc-idp": "Access Token (from OIDC Provider)",
"bui-tracer-stack-trace": "Stack Trace",
"bui-tracer-session-state-from-oidc-idp": "Session State (from OIDC Provider)",
"bui-tracer-scope-from-op-error": "Scope (from OIDC Provider)",
"bui-traces-title": "SSO Traces",
"bui-traces-id": "Trace ID",
"bui-traces-description": "Description",
"bui-traces-assertion-type": "Assertion Type",
"bui-traces-timestamp": "Timestamp",
"bui-traces-response": "Response",
"bui-traces-request": "Request",
"bui-traces-no-traces": "No SSO Traces recorded yet.",
"bui-traces-sp-protocol": "SP Protocol",
"bui-traces-saml-federation": "SAML Federation",
"bui-traces-oauth2-federation": "OAuth 2.0 Federation",
"bui-traces-idp-login": "IdP Login",
"bui-traces-oauth2": "OAuth 2.0",
"bui-traces-error": "Error",
"bui-traces-relay-state": "Relay State",
"bui-traces-default-redirect-url": "Default Redirect URL",
"bui-traces-redirect-uri": "Redirect URI",
"bui-traces-sso-connection-client-id": "SSO Connection Client ID",
"bui-traces-issuer": "Issuer",
"bui-traces-entity-id": "Entity ID",
"bui-traces-provider": "Provider",
"bui-traces-saml-response": "SAML Response",
"bui-traces-saml-request": "SAML Request",
"bui-traces-profile": "Profile",
"bui-traces-error-description-from-oidc-idp": "Error Description (from OIDC Provider)",
"bui-traces-error-uri": "Error URI",
"bui-traces-id-token-from-oidc-idp": "ID Token (from OIDC Provider)",
"bui-traces-access-token-from-oidc-idp": "Access Token (from OIDC Provider)",
"bui-traces-stack-trace": "Stack Trace",
"bui-traces-session-state-from-oidc-idp": "Session State (from OIDC Provider)",
"bui-traces-scope-from-op-error": "Scope (from OIDC Provider)",
"bui-sl-name": "Name (Optional)",
"bui-sl-sso-description": "Description (Optional)",
"bui-sl-create-link": "Create Setup Link",

View File

@ -11,6 +11,7 @@ const unAuthenticatedApiRoutes = [
'/api/hello',
'/api/auth/**',
'/api/federated-saml/**',
'/api/identity-federation/**',
'/api/logout/**',
'/api/oauth/**',
'/api/scim/v2.0/**',

View File

@ -19,7 +19,7 @@ module.exports = {
config.plugins.push(
new webpack.IgnorePlugin({
resourceRegExp:
/(^@google-cloud\/spanner|^@mongodb-js\/zstd|^aws-crt|^aws4$|^pg-native$|^mongodb-client-encryption$|^@sap\/hana-client$|^@sap\/hana-client\/extension\/Stream$|^snappy$|^react-native-sqlite-storage$|^bson-ext$|^cardinal$|^kerberos$|^hdb-pool$|^sql.js$|^sqlite3$|^better-sqlite3$|^ioredis$|^typeorm-aurora-data-api-driver$|^pg-query-stream$|^oracledb$|^mysql$|^snappy\/package\.json$|^cloudflare:sockets$)/,
/(^@google-cloud\/spanner|^@mongodb-js\/zstd|^aws-crt|^aws4$|^pg-native$|^mongodb-client-encryption$|^@sap\/hana-client$|^@sap\/hana-client\/extension\/Stream$|^snappy$|^react-native-sqlite-storage$|^bson-ext$|^cardinal$|^kerberos$|^hdb-pool$|^sql.js$|^better-sqlite3$|^ioredis$|^typeorm-aurora-data-api-driver$|^pg-query-stream$|^oracledb$|^mysql$|^snappy\/package\.json$|^cloudflare:sockets$)/,
})
);
}
@ -101,6 +101,10 @@ module.exports = {
source: '/api/v1/saml-traces/:path*',
destination: '/api/v1/sso-traces/:path*',
},
{
source: '/api/v1/federated-saml/:path*',
destination: '/api/v1/identity-federation/:path*',
},
];
},
images: {

View File

@ -26,8 +26,8 @@ const map = {
'src/directory-sync/request.ts',
],
'test/dsync/events.test.ts': ['src/directory-sync/events.ts'],
'test/federated-saml/app.test.ts': ['src/ee/federated-saml/app.ts'],
'test/federated-saml/sso.test.ts': ['src/ee/federated-saml/sso.ts'],
'test/identity-federation/app.test.ts': ['src/ee/identity-federation/app.ts'],
'test/identity-federation/sso.test.ts': ['src/ee/identity-federation/sso.ts'],
'test/event/index.test.ts': ['src/event/*'],
'test/dsync/google_oauth.test.ts': [
'src/directory-sync/non-scim/google/oauth.ts',

View File

@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MdNamespace1714417013715 implements MigrationInterface {
name = 'MdNamespace1714417013715'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`jackson_store\` MODIFY \`namespace\` varchar(256) NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`jackson_store\` MODIFY \`namespace\` varchar(64) NULL`);
}
}

View File

@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MssNamespace1714421718208 implements MigrationInterface {
name = 'MssNamespace1714421718208'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_store" ALTER COLUMN "namespace" varchar(256)`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_store" ALTER COLUMN "namespace" varchar(64)`);
}
}

View File

@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MsNamespace1714419315556 implements MigrationInterface {
name = 'MsNamespace1714419315556'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`jackson_store\` MODIFY \`namespace\` varchar(256) NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`jackson_store\` MODIFY \`namespace\` varchar(64) NULL`);
}
}

View File

@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MsNamespace1714457285484 implements MigrationInterface {
name = 'MsNamespace1714457285484'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`jackson_store\` MODIFY \`namespace\` varchar(256) NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`jackson_store\` MODIFY \`namespace\` varchar(64) NULL`);
}
}

View File

@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class PgNamespace1714452929542 implements MigrationInterface {
name = 'PgNamespace1714452929542'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_store" ALTER COLUMN "namespace" TYPE VARCHAR(256)`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "jackson_store" ALTER COLUMN "namespace" TYPE VARCHAR(64)`);
}
}

View File

@ -0,0 +1,42 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class SqliteInitial1716476500487 implements MigrationInterface {
name = 'SqliteInitial1716476500487'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "jackson_ttl" ("key" varchar(250) PRIMARY KEY NOT NULL, "expiresAt" bigint NOT NULL)`);
await queryRunner.query(`CREATE INDEX "_jackson_ttl_expires_at" ON "jackson_ttl" ("expiresAt") `);
await queryRunner.query(`CREATE TABLE "jackson_store" ("key" varchar(1500) PRIMARY KEY NOT NULL, "value" text NOT NULL, "iv" varchar(64), "tag" varchar(64), "createdAt" datetime NOT NULL DEFAULT ((STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'))), "modifiedAt" datetime, "namespace" varchar(256))`);
await queryRunner.query(`CREATE INDEX "_jackson_store_namespace" ON "jackson_store" ("namespace") `);
await queryRunner.query(`CREATE TABLE "jackson_index" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar(250) NOT NULL, "storeKey" varchar(250) NOT NULL)`);
await queryRunner.query(`CREATE INDEX "_jackson_index_key" ON "jackson_index" ("key") `);
await queryRunner.query(`CREATE INDEX "_jackson_index_key_store" ON "jackson_index" ("key", "storeKey") `);
await queryRunner.query(`DROP INDEX "_jackson_index_key"`);
await queryRunner.query(`DROP INDEX "_jackson_index_key_store"`);
await queryRunner.query(`CREATE TABLE "temporary_jackson_index" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar(250) NOT NULL, "storeKey" varchar(250) NOT NULL, CONSTRAINT "FK_937b040fb2592b4671cbde09e83" FOREIGN KEY ("storeKey") REFERENCES "jackson_store" ("key") ON DELETE CASCADE ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_jackson_index"("id", "key", "storeKey") SELECT "id", "key", "storeKey" FROM "jackson_index"`);
await queryRunner.query(`DROP TABLE "jackson_index"`);
await queryRunner.query(`ALTER TABLE "temporary_jackson_index" RENAME TO "jackson_index"`);
await queryRunner.query(`CREATE INDEX "_jackson_index_key" ON "jackson_index" ("key") `);
await queryRunner.query(`CREATE INDEX "_jackson_index_key_store" ON "jackson_index" ("key", "storeKey") `);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "_jackson_index_key_store"`);
await queryRunner.query(`DROP INDEX "_jackson_index_key"`);
await queryRunner.query(`ALTER TABLE "jackson_index" RENAME TO "temporary_jackson_index"`);
await queryRunner.query(`CREATE TABLE "jackson_index" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar(250) NOT NULL, "storeKey" varchar(250) NOT NULL)`);
await queryRunner.query(`INSERT INTO "jackson_index"("id", "key", "storeKey") SELECT "id", "key", "storeKey" FROM "temporary_jackson_index"`);
await queryRunner.query(`DROP TABLE "temporary_jackson_index"`);
await queryRunner.query(`CREATE INDEX "_jackson_index_key_store" ON "jackson_index" ("key", "storeKey") `);
await queryRunner.query(`CREATE INDEX "_jackson_index_key" ON "jackson_index" ("key") `);
await queryRunner.query(`DROP INDEX "_jackson_index_key_store"`);
await queryRunner.query(`DROP INDEX "_jackson_index_key"`);
await queryRunner.query(`DROP TABLE "jackson_index"`);
await queryRunner.query(`DROP INDEX "_jackson_store_namespace"`);
await queryRunner.query(`DROP TABLE "jackson_store"`);
await queryRunner.query(`DROP INDEX "_jackson_ttl_expires_at"`);
await queryRunner.query(`DROP TABLE "jackson_ttl"`);
}
}

6117
npm/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -18,19 +18,21 @@
],
"scripts": {
"build": "tsc -p tsconfig.build.json",
"db:migration:generate:postgres": "ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/postgres/pg_${MIGRATION_NAME}",
"db:migration:generate:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mysql/ms_${MIGRATION_NAME}",
"db:migration:generate:planetscale": "cross-env DB_ENGINE=planetscale DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/planetscale/ms_${MIGRATION_NAME}",
"db:migration:generate:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mariadb/md_${MIGRATION_NAME}",
"db:migration:generate:postgres": "ts-node --transpile-only ../node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/postgres/pg_${MIGRATION_NAME}",
"db:migration:generate:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ../node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mysql/ms_${MIGRATION_NAME}",
"db:migration:generate:planetscale": "cross-env DB_ENGINE=planetscale DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ../node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/planetscale/ms_${MIGRATION_NAME}",
"db:migration:generate:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ../node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mariadb/md_${MIGRATION_NAME}",
"db:migration:generate:mongo": "migrate-mongo create ${MIGRATION_NAME}",
"db:migration:generate:mssql": "cross-env DB_TYPE=mssql DB_URL='sqlserver://localhost:1433;database=master;username=sa;password=123ABabc!' ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mssql/mss_${MIGRATION_NAME}",
"db:migration:run:postgres": "ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:planetscale": "cross-env DB_ENGINE=planetscale DB_URL=${PLANETSCALE_URL} ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:generate:mssql": "cross-env DB_TYPE=mssql DB_URL='sqlserver://localhost:1433;database=master;username=sa;password=123ABabc!' ts-node --transpile-only ../node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mssql/mss_${MIGRATION_NAME}",
"db:migration:generate:sqlite": "cross-env DB_TYPE=sqlite DB_URL='file:///tmp/migration-sqlite.db' ts-node --transpile-only ../node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/sqlite/sqlite_${MIGRATION_NAME}",
"db:migration:run:postgres": "ts-node --transpile-only ../node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ../node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:planetscale": "cross-env DB_ENGINE=planetscale DB_URL=${PLANETSCALE_URL} ts-node --transpile-only ../node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ../node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:mongo": "cross-env DB_URL='mongodb://localhost:27017/jackson' migrate-mongo up",
"db:migration:revert:mongo": "cross-env DB_URL='mongodb://localhost:27017/jackson migrate-mongo down",
"db:migration:run:mssql": "cross-env DB_TYPE=mssql DB_URL='sqlserver://localhost:1433;database=master;username=sa;password=123ABabc!' ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:mssql": "cross-env DB_TYPE=mssql DB_URL='sqlserver://localhost:1433;database=master;username=sa;password=123ABabc!' ts-node --transpile-only ../node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"db:migration:run:sqlite": "cross-env DB_TYPE=sqlite DB_URL='file:///tmp/migration-sqlite.db' ts-node --transpile-only ../node_modules/typeorm/cli.js migration:run -d typeorm.ts",
"prepublishOnly": "npm run build",
"test": "cross-env BOXYHQ_NO_ANALYTICS=1 tap --timeout=0 --allow-incomplete-coverage --allow-empty-coverage test/**/*.test.ts",
"sort": "npx sort-package-json"
@ -39,40 +41,42 @@
"coverage-map": "map.js"
},
"dependencies": {
"@aws-sdk/client-dynamodb": "3.556.0",
"@aws-sdk/credential-providers": "3.556.0",
"@aws-sdk/util-dynamodb": "3.556.0",
"@aws-sdk/client-dynamodb": "3.584.0",
"@aws-sdk/credential-providers": "3.583.0",
"@aws-sdk/util-dynamodb": "3.584.0",
"@boxyhq/error-code-mnemonic": "0.1.1",
"@boxyhq/metrics": "0.2.6",
"@boxyhq/saml20": "1.5.0",
"@googleapis/admin": "16.0.0",
"axios": "1.6.8",
"@boxyhq/metrics": "0.2.7",
"@boxyhq/saml20": "1.5.1",
"@googleapis/admin": "19.0.0",
"@libsql/sqlite3": "0.3.1",
"axios": "1.7.2",
"encoding": "0.1.13",
"jose": "5.2.4",
"jose": "5.3.0",
"lodash": "4.17.21",
"mixpanel": "0.18.0",
"mongodb": "6.5.0",
"mongodb": "6.6.2",
"mssql": "10.0.2",
"mysql2": "3.9.7",
"mysql2": "3.9.8",
"node-forge": "1.3.1",
"openid-client": "5.6.5",
"pg": "8.11.5",
"redis": "4.6.13",
"redis": "4.6.14",
"reflect-metadata": "0.2.2",
"ripemd160": "2.0.2",
"sqlite3": "5.1.7",
"typeorm": "0.3.20"
},
"devDependencies": {
"@faker-js/faker": "8.4.1",
"@types/lodash": "4.17.0",
"@types/node": "20.12.7",
"@types/lodash": "4.17.4",
"@types/node": "20.12.12",
"@types/sinon": "17.0.3",
"@types/tap": "15.0.11",
"cross-env": "7.0.3",
"migrate-mongo": "11.0.0",
"nock": "13.5.4",
"sinon": "17.0.1",
"tap": "18.7.2",
"sinon": "18.0.0",
"tap": "19.0.2",
"ts-node": "10.9.2",
"tsconfig-paths": "4.2.0",
"typescript": "5.4.5"

View File

@ -3,7 +3,7 @@ import {
Storable,
SAMLSSORecord,
OIDCSSORecord,
SSOTracerInstance,
SSOTracesInstance,
Records,
Trace,
} from '../typings';
@ -12,11 +12,11 @@ import { transformConnections } from './utils';
export class AdminController implements IAdminController {
private connectionStore: Storable;
private ssoTracer: SSOTracerInstance;
private ssoTraces: SSOTracesInstance;
constructor({ connectionStore, ssoTracer }) {
constructor({ connectionStore, ssoTraces }) {
this.connectionStore = connectionStore;
this.ssoTracer = ssoTracer;
this.ssoTraces = ssoTraces;
}
public async getAllConnection(pageOffset?: number, pageLimit?: number, pageToken?: string) {
@ -34,7 +34,7 @@ export class AdminController implements IAdminController {
}
public async getAllSSOTraces(pageOffset: number, pageLimit: number, pageToken?: string) {
const { data: traces, pageToken: nextPageToken } = (await this.ssoTracer.getAllTraces(
const { data: traces, pageToken: nextPageToken } = (await this.ssoTraces.getAllTraces(
pageOffset,
pageLimit,
pageToken
@ -48,7 +48,7 @@ export class AdminController implements IAdminController {
}
public async getSSOTraceById(traceId: string) {
const trace = await this.ssoTracer.getByTraceId(traceId);
const trace = await this.ssoTraces.getByTraceId(traceId);
if (!trace) {
throw new JacksonError(`Trace with id ${traceId} not found`, 404);
@ -63,6 +63,14 @@ export class AdminController implements IAdminController {
pageLimit: number,
pageToken?: string
) {
return await this.ssoTracer.getTracesByProduct({ product, pageOffset, pageLimit, pageToken });
return await this.ssoTraces.getTracesByProduct({ product, pageOffset, pageLimit, pageToken });
}
public async deleteTracesByProduct(product: string) {
return await this.ssoTraces.deleteTracesByProduct(product);
}
public async countByProduct(product: string) {
return await this.ssoTraces.countByProduct(product);
}
}

Some files were not shown because too many files have changed in this diff Show More