diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 37056e2f..065876e6 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -19,8 +19,9 @@ * Development ** [Development](/development.md) -** [MongoDB](/dev_mongodb.md) ** [Document Site](/dev_docsite.md) +** [MongoDB](/dev_mongodb.md) +** [Vault](/dev_vault.md) * Maintenance ** [Adding Internal Users](/operations_internal_user.md) diff --git a/docs/dev_env_vars.md b/docs/dev_env_vars.md index 81c40fa5..fbc3fcd5 100644 --- a/docs/dev_env_vars.md +++ b/docs/dev_env_vars.md @@ -8,6 +8,7 @@ A suggested deployment strategy is to use [envconsul](https://github.com/hashico | Env Var | Default | Secret | Description | | --- | --- | --- | --- | +| BROKER_URL | | | The external URL that this instance is running on. Used to create redirect urls. | | HOSTNAME | | | The hostname of the server this instance is running on. Used in logs. The instance with a hostname ending in '-0' is the primary node. It will cause issues if there is no primary node or there are multiple primary nodes'. | ## Audit file logging @@ -129,6 +130,24 @@ The Redis environment variables used to setup the connection. | REDIS_USER | '' | Yes | The Redis user | | REDIS_PASSWORD | '' | Yes | The Redis password | +## User Alias Services + +### GitHub + +| Env Var | Default | Secret | Description | +| --- | --- | --- | --- | +| GITHUB_OAUTH_CLIENT_ID | | | The client id of the GitHub OAuth App | +| GITHUB_OAUTH_CLIENT_SECRET | | | The client secret of the GitHub OAuth App | + +## Sync Services + +### GitHub + +| Env Var | Default | Secret | Description | +| --- | --- | --- | --- | +| GITHUB_SYNC_CLIENT_ID | | | The client id of the GitHub App | +| GITHUB_SYNC_PRIVATE_KEY | | | The private key of the GitHub App | + ## Temporary | Env Var | Default | Secret | Description | diff --git a/docs/dev_vault.md b/docs/dev_vault.md new file mode 100644 index 00000000..0cb82601 --- /dev/null +++ b/docs/dev_vault.md @@ -0,0 +1,35 @@ +# Hashicorp Vault + +## Local Development + +### Connecting to the local + +Link: http://localhost:8200/ui/vault/auth?with=token + +### Configure local Vault + +```bash +# Configure the local Vault with basic setup +$ ./scripts/vault-setup.sh +``` + +The setup script can be rerun to reset the local database. You may need to reindex the redis cache by calling the api `/v1/graph/reindex-cache`. + +## Vault Policies + +The local setup script inputs some basic policy configuration. These policies should not be used in production. It is suggested that a separate tool be used to keep your policies up-to-date. + +See: [Vault Sync Tool](https://github.com/bcgov-nr/vault-sync-app) + +### Vault Sync Tool + +The [Vault Sync Tool](https://github.com/bcgov-nr/vault-sync-app) configures HashiCorp Vault using NR Broker as a data source for applications and groups. NR Broker does not require the Vault Sync Tool to run for any of its own operations. + +#### Running + +The following will start the tool in monitoring mode to update the local Vault. + +``` +source ./scripts/setenv-curl-local.sh +podman run --rm -e=VAULT_ADDR=http://$(podman inspect -f "{{.NetworkSettings.IPAddress}}" broker-vault):8200 -e=VAULT_TOKEN=$VAULT_TOKEN -e=BROKER_API_URL=http://host.containers.internal:3000/ -e=BROKER_TOKEN=$BROKER_JWT ghcr.io/bcgov-nr/vault-sync-app:v2.1.0 +``` diff --git a/docs/development.md b/docs/development.md index af4f234a..9f5da0d6 100644 --- a/docs/development.md +++ b/docs/development.md @@ -84,20 +84,18 @@ See: [MongoDB Development](./dev_mongodb.md) ### Setup Vault ```bash -# Start up local vault +# Start up local Vault $ podman run -p 8200:8200 --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' -d --name=broker-vault hashicorp/vault ``` -Once started, you must run the vault setup script to bootstrap it. MongoDB must be running and setup before running this. +Once started, you must run the Vault setup script to bootstrap it. MongoDB must be running and setup before running this. ```bash -# Configure the local vault with basic setup +# Configure the local Vault with basic setup $ ./scripts/vault-setup.sh ``` -#### Github secret sync - -To setup a Github App to test secret syncing, set the values GITHUB_CLIENT_ID and GITHUB_PRIVATE_KEY at the Vault path `apps/prod/vault/vsync`. +See: [Vault Development](./dev_vault.md) ## Running Locally @@ -132,16 +130,6 @@ $ envconsul -config=env-prod.hcl npm run start:dev If Kinesis and AWS access is not setup then some APIs will return a 503 (service unavailable). -## Running Vault Sync Tool - -The [Vault Sync Tool](https://github.com/bcgov-nr/vault-sync-app) configures HashiCorp Vault using NR Broker as a data source for applications and groups. NR Broker does not require the Vault Sync Tool to run for any of its own operations. - -The following will start the tool in monitoring mode to update the local Vault. - -``` -source ./scripts/setenv-curl-local.sh -podman run --rm -e=VAULT_ADDR=http://$(podman inspect -f "{{.NetworkSettings.IPAddress}}" broker-vault):8200 -e=VAULT_TOKEN=$VAULT_TOKEN -e=BROKER_API_URL=http://host.containers.internal:3000/ -e=BROKER_TOKEN=$BROKER_JWT ghcr.io/bcgov-nr/vault-sync-app:v2.1.0 - ### Local MongoDB Disconnects The connection to MongoDB may time out if your machine goes to sleep. The easiest way to recover is to stop the backend, restart the containers and rerun the vault setup. The provided restart script will do the container and setup steps for you. @@ -193,6 +181,39 @@ The dockerfile can be built locally by running the following. podman build . -t nr-broker ``` +## Setup Sync Services + +Broker can be setup to sync secrets from Vault to other locations. This helps reduce secrets sprawl by ensuring Vault remains the source of truth for your secrets. + +### GitHub Sync + +GitHub sync requires a GitHub app. It is recommended that the GitHub app be registered under a GitHub organization in production. A GitHub app registered under a personal account can be used for testing. The app requires the following permissions: + +* Read and Write: Manage Actions repository secrets. + +The app must also be installed in an organization with access to your service repositories. + +See: + +* https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app +* https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app + +To locally setup a GitHub App syncing, set the values GITHUB_SYNC_CLIENT_ID and GITHUB_SYNC_PRIVATE_KEY at the Vault path `apps/prod/vault/vsync`. + +## Setup User Alias services + +Broker can be setup to allow users to alias their identity in other identity providers to their account. + +### GitHub Alias + +GitHub user alias requires a GitHub OAuth app. It is recommended that the GitHub OAuth app be registered under a GitHub organization in production. A GitHub OAuth app registered under a personal account can be used for testing. + +See: + +* https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app + +To locally setup a GitHub App syncing, set the values GITHUB_OAUTH_CLIENT_ID and GITHUB_OAUTH_CLIENT_SECRET at the Vault path `apps/prod/vault/vsync`. + ## Province of British Columbia Palette and Font The UI defaults to Material's indigo-pink styling. The Angular build configuration 'bcgov' can be combined with an environment configuration to create a build using the BC Government Colour palette and font. diff --git a/package-lock.json b/package-lock.json index 243b0b5b..f1a1ccee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "8.1.1", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-kinesis": "^3.658.1", + "@aws-sdk/client-kinesis": "^3.668.0", "@nestjs/axios": "^3.0.3", "@nestjs/common": "^10.4.4", "@nestjs/config": "^3.2.3", @@ -27,7 +27,7 @@ "connect-mongo": "^5.1.0", "deep-equal": "^2.2.3", "ejs": "^3.1.10", - "express-session": "^1.18.0", + "express-session": "^1.18.1", "file-stream-rotator": "^1.0.0", "helmet": "^8.0.0", "libsodium-wrappers": "^0.7.15", @@ -48,7 +48,7 @@ "uuid": "^10.0.0" }, "devDependencies": { - "@eslint/js": "^9.11.1", + "@eslint/js": "^9.12.0", "@golevelup/ts-jest": "^0.5.6", "@nestjs/cli": "^10.4.5", "@nestjs/schematics": "^10.1.4", @@ -62,15 +62,15 @@ "@types/jest": "^29.5.13", "@types/libsodium-wrappers": "^0.7.14", "@types/lodash.merge": "^4.6.9", - "@types/node": "^22.7.4", + "@types/node": "^22.7.5", "@types/passport": "^1.0.16", "@types/passport-http": "^0.3.11", "@types/passport-jwt": "^4.0.1", "@types/supertest": "^6.0.2", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "^8.8.0", - "@typescript-eslint/parser": "^8.8.0", - "eslint": "^9.11.1", + "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/parser": "^8.8.1", + "eslint": "^9.12.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "jest": "^29.7.0", @@ -81,8 +81,8 @@ "ts-loader": "^9.5.1", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "^5.6.2", - "typescript-eslint": "^8.8.0" + "typescript": "^5.6.3", + "typescript-eslint": "^8.8.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -403,55 +403,55 @@ } }, "node_modules/@aws-sdk/client-kinesis": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-kinesis/-/client-kinesis-3.658.1.tgz", - "integrity": "sha512-0Fy/Ffrtmp3flp1tQH0tUWntM8/pMNon2jvXYYi/5I2zvVk4JhCdPQd1YWhgPpaSkgVtmFNVqulc220xC/6OlQ==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kinesis/-/client-kinesis-3.668.0.tgz", + "integrity": "sha512-GE9fGV8kAfF66oRPqjcCzkxalsiZHhJWZl9o25lf1RPaI1z5lpEYGOUnGNFdxElA/ko7AUUGcg5dP0J89Ct85w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.658.1", - "@aws-sdk/client-sts": "3.658.1", - "@aws-sdk/core": "3.658.1", - "@aws-sdk/credential-provider-node": "3.658.1", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.6", - "@smithy/eventstream-serde-browser": "^3.0.9", - "@smithy/eventstream-serde-config-resolver": "^3.0.6", - "@smithy/eventstream-serde-node": "^3.0.8", - "@smithy/fetch-http-handler": "^3.2.8", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.21", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.3", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/client-sso-oidc": "3.668.0", + "@aws-sdk/client-sts": "3.668.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.668.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.668.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.668.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/eventstream-serde-browser": "^3.0.10", + "@smithy/eventstream-serde-config-resolver": "^3.0.7", + "@smithy/eventstream-serde-node": "^3.0.9", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.21", - "@smithy/util-defaults-mode-node": "^3.0.21", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.5", + "@smithy/util-waiter": "^3.1.6", "tslib": "^2.6.2" }, "engines": { @@ -459,47 +459,47 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.658.1.tgz", - "integrity": "sha512-lOuaBtqPTYGn6xpXlQF4LsNDsQ8Ij2kOdnk+i69Kp6yS76TYvtUuukyLL5kx8zE1c8WbYtxj9y8VNw9/6uKl7Q==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.668.0.tgz", + "integrity": "sha512-21YehzNmlaVbB6f4gAg9CTl6djExE7yxuWaRgbFugCtFhqZbmNhrh826B6cGvPVc5Dxx2rdMdI/SxTujtTJvag==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.658.1", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.6", - "@smithy/fetch-http-handler": "^3.2.8", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.21", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.3", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.668.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.668.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.21", - "@smithy/util-defaults-mode-node": "^3.0.21", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -508,48 +508,48 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.658.1.tgz", - "integrity": "sha512-RGcZAI3qEA05JszPKwa0cAyp8rnS1nUvs0Sqw4hqLNQ1kD7b7V6CPjRXe7EFQqCOMvM4kGqx0+cEEVTOmBsFLw==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.668.0.tgz", + "integrity": "sha512-b1Ib/92tcjOPXWYILfNuOOd2CYxmlr9lUfoZZBy/uwZCMObI6gtcpdUjfefyJohWfR+rk1WtsXi/sIXKxAhl/g==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.658.1", - "@aws-sdk/credential-provider-node": "3.658.1", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.6", - "@smithy/fetch-http-handler": "^3.2.8", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.21", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.3", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.668.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.668.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.668.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.21", - "@smithy/util-defaults-mode-node": "^3.0.21", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -557,53 +557,53 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.658.1" + "@aws-sdk/client-sts": "^3.668.0" } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.658.1.tgz", - "integrity": "sha512-yw9hc5blTnbT1V6mR7Cx9HGc9KQpcLQ1QXj8rntiJi6tIYu3aFNVEyy81JHL7NsuBSeQulJTvHO3y6r3O0sfRg==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.668.0.tgz", + "integrity": "sha512-Ele3N6WveoMsF2mZpN/1tM0jsu7qOUXWX7RKV1U4Dhe0TMbW1KdVIXz1oirWlc0BxCels7HX+CS1N7gg1axhwg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.658.1", - "@aws-sdk/core": "3.658.1", - "@aws-sdk/credential-provider-node": "3.658.1", - "@aws-sdk/middleware-host-header": "3.654.0", - "@aws-sdk/middleware-logger": "3.654.0", - "@aws-sdk/middleware-recursion-detection": "3.654.0", - "@aws-sdk/middleware-user-agent": "3.654.0", - "@aws-sdk/region-config-resolver": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@aws-sdk/util-user-agent-browser": "3.654.0", - "@aws-sdk/util-user-agent-node": "3.654.0", - "@smithy/config-resolver": "^3.0.8", - "@smithy/core": "^2.4.6", - "@smithy/fetch-http-handler": "^3.2.8", - "@smithy/hash-node": "^3.0.6", - "@smithy/invalid-dependency": "^3.0.6", - "@smithy/middleware-content-length": "^3.0.8", - "@smithy/middleware-endpoint": "^3.1.3", - "@smithy/middleware-retry": "^3.0.21", - "@smithy/middleware-serde": "^3.0.6", - "@smithy/middleware-stack": "^3.0.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/node-http-handler": "^3.2.3", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", - "@smithy/url-parser": "^3.0.6", + "@aws-sdk/client-sso-oidc": "3.668.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-node": "3.668.0", + "@aws-sdk/middleware-host-header": "3.667.0", + "@aws-sdk/middleware-logger": "3.667.0", + "@aws-sdk/middleware-recursion-detection": "3.667.0", + "@aws-sdk/middleware-user-agent": "3.668.0", + "@aws-sdk/region-config-resolver": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@aws-sdk/util-user-agent-browser": "3.667.0", + "@aws-sdk/util-user-agent-node": "3.668.0", + "@smithy/config-resolver": "^3.0.9", + "@smithy/core": "^2.4.8", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/hash-node": "^3.0.7", + "@smithy/invalid-dependency": "^3.0.7", + "@smithy/middleware-content-length": "^3.0.9", + "@smithy/middleware-endpoint": "^3.1.4", + "@smithy/middleware-retry": "^3.0.23", + "@smithy/middleware-serde": "^3.0.7", + "@smithy/middleware-stack": "^3.0.7", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/url-parser": "^3.0.7", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.21", - "@smithy/util-defaults-mode-node": "^3.0.21", - "@smithy/util-endpoints": "^2.1.2", - "@smithy/util-middleware": "^3.0.6", - "@smithy/util-retry": "^3.0.6", + "@smithy/util-defaults-mode-browser": "^3.0.23", + "@smithy/util-defaults-mode-node": "^3.0.23", + "@smithy/util-endpoints": "^2.1.3", + "@smithy/util-middleware": "^3.0.7", + "@smithy/util-retry": "^3.0.7", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -612,19 +612,20 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.658.1.tgz", - "integrity": "sha512-vJVMoMcSKXK2gBRSu9Ywwv6wQ7tXH8VL1fqB1uVxgCqBZ3IHfqNn4zvpMPWrwgO2/3wv7XFyikGQ5ypPTCw4jA==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.667.0.tgz", + "integrity": "sha512-pMcDVI7Tmdsc8R3sDv0Omj/4iRParGY+uJtAfF669WnZfDfaBQaix2Mq7+Mu08vdjqO9K3gicFvjk9S1VLmOKA==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^2.4.6", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/property-provider": "^3.1.6", - "@smithy/protocol-http": "^4.1.3", - "@smithy/signature-v4": "^4.1.4", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", - "@smithy/util-middleware": "^3.0.6", + "@aws-sdk/types": "3.667.0", + "@smithy/core": "^2.4.8", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/signature-v4": "^4.2.0", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-middleware": "^3.0.7", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, @@ -633,14 +634,15 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.654.0.tgz", - "integrity": "sha512-kogsx3Ql81JouHS7DkheCDU9MYAvK0AokxjcshDveGmf7BbgbWCA8Fnb9wjQyNDaOXNvkZu8Z8rgkX91z324/w==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.667.0.tgz", + "integrity": "sha512-zZbrkkaPc54WXm+QAnpuv0LPNfsts0HPPd+oCECGs7IQRaFsGj187cwvPg9RMWDFZqpm64MdBDoA8OQHsqzYCw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -648,19 +650,20 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.658.1.tgz", - "integrity": "sha512-4ubkJjEVCZflxkZnV1JDQv8P2pburxk1LrEp55telfJRzXrnowzBKwuV2ED0QMNC448g2B3VCaffS+Ct7c4IWQ==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.667.0.tgz", + "integrity": "sha512-sjtybFfERZWiqTY7fswBxKQLvUkiCucOWyqh3IaPo/4nE1PXRnaZCVG0+kRBPrYIxWqiVwytvZzMJy8sVZcG0A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/fetch-http-handler": "^3.2.8", - "@smithy/node-http-handler": "^3.2.3", - "@smithy/property-provider": "^3.1.6", - "@smithy/protocol-http": "^4.1.3", - "@smithy/smithy-client": "^3.3.5", - "@smithy/types": "^3.4.2", - "@smithy/util-stream": "^3.1.8", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/fetch-http-handler": "^3.2.9", + "@smithy/node-http-handler": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/protocol-http": "^4.1.4", + "@smithy/smithy-client": "^3.4.0", + "@smithy/types": "^3.5.0", + "@smithy/util-stream": "^3.1.9", "tslib": "^2.6.2" }, "engines": { @@ -668,47 +671,48 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.658.1.tgz", - "integrity": "sha512-2uwOamQg5ppwfegwen1ddPu5HM3/IBSnaGlaKLFhltkdtZ0jiqTZWUtX2V+4Q+buLnT0hQvLS/frQ+7QUam+0Q==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.668.0.tgz", + "integrity": "sha512-npu7qBM8Qu+BzRh+omBvcnA9Hxt/5HZ6ifACtLUqqkPLhCgINSpVruVqDXJHinl6DrcmTL12XM+60VW90fq2uA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.654.0", - "@aws-sdk/credential-provider-http": "3.658.1", - "@aws-sdk/credential-provider-process": "3.654.0", - "@aws-sdk/credential-provider-sso": "3.658.1", - "@aws-sdk/credential-provider-web-identity": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@smithy/credential-provider-imds": "^3.2.3", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/credential-provider-env": "3.667.0", + "@aws-sdk/credential-provider-http": "3.667.0", + "@aws-sdk/credential-provider-process": "3.667.0", + "@aws-sdk/credential-provider-sso": "3.668.0", + "@aws-sdk/credential-provider-web-identity": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.658.1" + "@aws-sdk/client-sts": "^3.668.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.658.1.tgz", - "integrity": "sha512-XwxW6N+uPXPYAuyq+GfOEdfL/MZGAlCSfB5gEWtLBFmFbikhmEuqfWtI6CD60OwudCUOh6argd21BsJf8o1SJA==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.668.0.tgz", + "integrity": "sha512-QHD6Y6xurKsHGQ7U2Az0UHu3R31mq7uokuMrWU9IIWB4Qa5t/Pkt4Od8TYXL/V4uAOthsLdchgfeCFSleOZMEA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.654.0", - "@aws-sdk/credential-provider-http": "3.658.1", - "@aws-sdk/credential-provider-ini": "3.658.1", - "@aws-sdk/credential-provider-process": "3.654.0", - "@aws-sdk/credential-provider-sso": "3.658.1", - "@aws-sdk/credential-provider-web-identity": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@smithy/credential-provider-imds": "^3.2.3", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/credential-provider-env": "3.667.0", + "@aws-sdk/credential-provider-http": "3.667.0", + "@aws-sdk/credential-provider-ini": "3.668.0", + "@aws-sdk/credential-provider-process": "3.667.0", + "@aws-sdk/credential-provider-sso": "3.668.0", + "@aws-sdk/credential-provider-web-identity": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/credential-provider-imds": "^3.2.4", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -716,15 +720,16 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.654.0.tgz", - "integrity": "sha512-PmQoo8sZ9Q2Ow8OMzK++Z9lI7MsRUG7sNq3E72DVA215dhtTICTDQwGlXH2AAmIp7n+G9LLRds+4wo2ehG4mkg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.667.0.tgz", + "integrity": "sha512-HZHnvop32fKgsNHkdhVaul7UzQ25sEc0j9yqA4bjhtbk0ECl42kj3f1pJ+ZU/YD9ut8lMJs/vVqiOdNThVdeBw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -732,17 +737,18 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.658.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.658.1.tgz", - "integrity": "sha512-YOagVEsZEk9DmgJEBg+4MBXrPcw/tYas0VQ5OVBqC5XHNbi2OBGJqgmjVPesuu393E7W0VQxtJFDS00O1ewQgA==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.668.0.tgz", + "integrity": "sha512-cO14tsL7Lmyq4HfRHBBjEmcBDhlXv4eVgY8DQ9e/ujPFU+b99xiZiV80JSkJ8Kz99+woFl6pFo9PYp36YaI+Pw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.658.1", - "@aws-sdk/token-providers": "3.654.0", - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/client-sso": "3.668.0", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/token-providers": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -750,32 +756,33 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.654.0.tgz", - "integrity": "sha512-6a2g9gMtZToqSu+CusjNK5zvbLJahQ9di7buO3iXgbizXpLXU1rnawCpWxwslMpT5fLgMSKDnKDrr6wdEk7jSw==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.667.0.tgz", + "integrity": "sha512-t8CFlZMD/1p/8Cli3rvRiTJpjr/8BO64gw166AHgFZYSN2h95L2l1tcW0jpsc3PprA32nLg1iQVKYt4WGM4ugw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.654.0" + "@aws-sdk/client-sts": "^3.667.0" } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.654.0.tgz", - "integrity": "sha512-rxGgVHWKp8U2ubMv+t+vlIk7QYUaRCHaVpmUlJv0Wv6Q0KeO9a42T9FxHphjOTlCGQOLcjCreL9CF8Qhtb4mdQ==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.667.0.tgz", + "integrity": "sha512-Z7fIAMQnPegs7JjAQvlOeWXwpMRfegh5eCoIP6VLJIeR6DLfYKbP35JBtt98R6DXslrN2RsbTogjbxPEDQfw1w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -783,13 +790,13 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.654.0.tgz", - "integrity": "sha512-OQYb+nWlmASyXfRb989pwkJ9EVUMP1CrKn2eyTk3usl20JZmKo2Vjis6I0tLUkMSxMhnBJJlQKyWkRpD/u1FVg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.667.0.tgz", + "integrity": "sha512-PtTRNpNm/5c746jRgZCNg4X9xEJIwggkGJrF0GP9AB1ANg4pc/sF2Fvn1NtqPe9wtQ2stunJprnm5WkCHN7QiA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -797,14 +804,14 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.654.0.tgz", - "integrity": "sha512-gKSomgltKVmsT8sC6W7CrADZ4GHwX9epk3GcH6QhebVO3LA9LRbkL3TwOPUXakxxOLLUTYdOZLIOtFf7iH00lg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.667.0.tgz", + "integrity": "sha512-U5glWD3ehFohzpUpopLtmqAlDurGWo2wRGPNgi4SwhWU7UDt6LS7E/UvJjqC0CUrjlzOw+my2A+Ncf+fisMhxQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -812,15 +819,17 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.654.0.tgz", - "integrity": "sha512-liCcqPAyRsr53cy2tYu4qeH4MMN0eh9g6k56XzI5xd4SghXH5YWh4qOYAlQ8T66ZV4nPMtD8GLtLXGzsH8moFg==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.668.0.tgz", + "integrity": "sha512-6WSCeN9AZZM/bM1kXJluLPFptd6z+tMBEZw3J7m1EvJSBTKEoSHiBrZBjc3gi83l/EKHCswITm2c8NcdgXAnLw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@aws-sdk/util-endpoints": "3.654.0", - "@smithy/protocol-http": "^4.1.3", - "@smithy/types": "^3.4.2", + "@aws-sdk/core": "3.667.0", + "@aws-sdk/types": "3.667.0", + "@aws-sdk/util-endpoints": "3.667.0", + "@smithy/core": "^2.4.8", + "@smithy/protocol-http": "^4.1.4", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -828,16 +837,16 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.654.0.tgz", - "integrity": "sha512-ydGOrXJxj3x0sJhsXyTmvJVLAE0xxuTWFJihTl67RtaO7VRNtd82I3P3bwoMMaDn5WpmV5mPo8fEUDRlBm3fPg==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.667.0.tgz", + "integrity": "sha512-iNr+JhhA902JMKHG9IwT9YdaEx6KGl6vjAL5BRNeOjfj4cZYMog6Lz/IlfOAltMtT0w88DAHDEFrBd2uO0l2eg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.6", + "@smithy/util-middleware": "^3.0.7", "tslib": "^2.6.2" }, "engines": { @@ -845,31 +854,31 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.654.0.tgz", - "integrity": "sha512-D8GeJYmvbfWkQDtTB4owmIobSMexZel0fOoetwvgCQ/7L8VPph3Q2bn1TRRIXvH7wdt6DcDxA3tKMHPBkT3GlA==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.667.0.tgz", + "integrity": "sha512-ZecJlG8p6D4UTYlBHwOWX6nknVtw/OBJ3yPXTSajBjhUlj9lE2xvejI8gl4rqkyLXk7z3bki+KR4tATbMaM9yg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/property-provider": "^3.1.6", - "@smithy/shared-ini-file-loader": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/property-provider": "^3.1.7", + "@smithy/shared-ini-file-loader": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.654.0" + "@aws-sdk/client-sso-oidc": "^3.667.0" } }, "node_modules/@aws-sdk/types": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.654.0.tgz", - "integrity": "sha512-VWvbED3SV+10QJIcmU/PKjsKilsTV16d1I7/on4bvD/jo1qGeMXqLDBSen3ks/tuvXZF/mFc7ZW/W2DiLVtO7A==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.667.0.tgz", + "integrity": "sha512-gYq0xCsqFfQaSL/yT1Gl1vIUjtsg7d7RhnUfsXaHt8xTxOKRTdH9GjbesBjXOzgOvB0W0vfssfreSNGFlOOMJg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -877,14 +886,14 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.654.0.tgz", - "integrity": "sha512-i902fcBknHs0Irgdpi62+QMvzxE+bczvILXigYrlHL4+PiEnlMVpni5L5W1qCkNZXf8AaMrSBuR1NZAGp6UOUw==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.667.0.tgz", + "integrity": "sha512-X22SYDAuQJWnkF1/q17pkX3nGw5XMD9YEUbmt87vUnRq7iyJ3JOpl6UKOBeUBaL838wA5yzdbinmCITJ/VZ1QA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/types": "^3.4.2", - "@smithy/util-endpoints": "^2.1.2", + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", + "@smithy/util-endpoints": "^2.1.3", "tslib": "^2.6.2" }, "engines": { @@ -904,26 +913,27 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.654.0.tgz", - "integrity": "sha512-ykYAJqvnxLt7wfrqya28wuH3/7NdrwzfiFd7NqEVQf7dXVxL5RPEpD7DxjcyQo3DsHvvdUvGZVaQhozycn1pzA==", + "version": "3.667.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.667.0.tgz", + "integrity": "sha512-y1pKlNzNpxzddM0QSnfIfIbi3Z9LTag1VDjYyZRbEGGSVip2J00qKsET+979nRezWMyJgw5GPBQR3Y+rN+jh0Q==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/types": "^3.4.2", + "@aws-sdk/types": "3.667.0", + "@smithy/types": "^3.5.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.654.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.654.0.tgz", - "integrity": "sha512-a0ojjdBN6pqv6gB4H/QPPSfhs7mFtlVwnmKCM/QrTaFzN0U810PJ1BST3lBx5sa23I5jWHGaoFY+5q65C3clLQ==", + "version": "3.668.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.668.0.tgz", + "integrity": "sha512-A27U+G/R5ekZhf6L2yVOX6/YQqmAxOiV61M+a9Jy1eG6YDOXueYUYXaHUkLWy15sNB0TPJNdsApn1rJdvHI0AQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.654.0", - "@smithy/node-config-provider": "^3.1.7", - "@smithy/types": "^3.4.2", + "@aws-sdk/middleware-user-agent": "3.668.0", + "@aws-sdk/types": "3.667.0", + "@smithy/node-config-provider": "^3.1.8", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -1605,9 +1615,9 @@ "dev": true }, "node_modules/@eslint/js": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz", - "integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==", + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, "license": "MIT", "engines": { @@ -1643,6 +1653,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "dev": true, @@ -1656,10 +1690,11 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -2683,6 +2718,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { @@ -2695,6 +2732,8 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", "engines": { @@ -2703,6 +2742,8 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { @@ -2851,16 +2892,16 @@ } }, "node_modules/@smithy/core": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.4.7.tgz", - "integrity": "sha512-goqMjX+IoVEnHZjYuzu8xwoZjoteMiLXsPHuXPBkWsGwu0o9c3nTjqkUlP1Ez/V8E501aOU7CJ3INk8mQcW2gw==", + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.4.8.tgz", + "integrity": "sha512-x4qWk7p/a4dcf7Vxb2MODIf4OIcqNbK182WxRvZ/3oKPrf/6Fdic5sSElhO1UtXpWKBazWfqg0ZEK9xN1DsuHA==", "license": "Apache-2.0", "dependencies": { "@smithy/middleware-endpoint": "^3.1.4", - "@smithy/middleware-retry": "^3.0.22", + "@smithy/middleware-retry": "^3.0.23", "@smithy/middleware-serde": "^3.0.7", "@smithy/protocol-http": "^4.1.4", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-middleware": "^3.0.7", @@ -2888,25 +2929,25 @@ } }, "node_modules/@smithy/eventstream-codec": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.5.tgz", - "integrity": "sha512-6pu+PT2r+5ZnWEV3vLV1DzyrpJ0TmehQlniIDCSpZg6+Ji2SfOI38EqUyQ+O8lotVElCrfVc9chKtSMe9cmCZQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.6.tgz", + "integrity": "sha512-SBiOYPBH+5wOyPS7lfI150ePfGLhnp/eTu5RnV9xvhGvRiKfnl6HzRK9wehBph+il8FxS9KTeadx7Rcmf1GLPQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "@smithy/util-hex-encoding": "^3.0.0", "tslib": "^2.6.2" } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.9.tgz", - "integrity": "sha512-PiQLo6OQmZAotJweIcObL1H44gkvuJACKMNqpBBe5Rf2Ax1DOcGi/28+feZI7yTe1ERHlQQaGnm8sSkyDUgsMg==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.10.tgz", + "integrity": "sha512-1i9aMY6Pl/SmA6NjvidxnfBLHMPzhKu2BP148pEt5VwhMdmXn36PE2kWKGa9Hj8b0XGtCTRucpCncylevCtI7g==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^3.0.8", - "@smithy/types": "^3.4.2", + "@smithy/eventstream-serde-universal": "^3.0.9", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2914,12 +2955,12 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.6.tgz", - "integrity": "sha512-iew15It+c7WfnVowWkt2a7cdPp533LFJnpjDQgfZQcxv2QiOcyEcea31mnrk5PVbgo0nNH3VbYGq7myw2q/F6A==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.7.tgz", + "integrity": "sha512-eVzhGQBPEqXXYHvIUku0jMTxd4gDvenRzUQPTmKVWdRvp9JUCKrbAXGQRYiGxUYq9+cqQckRm0wq3kTWnNtDhw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.4.2", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2927,13 +2968,13 @@ } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.8.tgz", - "integrity": "sha512-6m+wI+fT0na+6oao6UqALVA38fsScCpoG5UO/A8ZSyGLnPM2i4MS1cFUhpuALgvLMxfYoTCh7qSeJa0aG4IWpQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.9.tgz", + "integrity": "sha512-JE0Guqvt0xsmfQ5y1EI342/qtJqznBv8cJqkHZV10PwC8GWGU5KNgFbQnsVCcX+xF+qIqwwfRmeWoJCjuOLmng==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^3.0.8", - "@smithy/types": "^3.4.2", + "@smithy/eventstream-serde-universal": "^3.0.9", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -2941,13 +2982,13 @@ } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.8.tgz", - "integrity": "sha512-09tqzIQ6e+7jLqGvRji1yJoDbL/zob0OFhq75edgStWErGLf16+yI5hRc/o9/YAybOhUZs/swpW2SPn892G5Gg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.9.tgz", + "integrity": "sha512-bydfgSisfepCufw9kCEnWRxqxJFzX/o8ysXWv+W9F2FIyiaEwZ/D8bBKINbh4ONz3i05QJ1xE7A5OKYvgJsXaw==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-codec": "^3.1.5", - "@smithy/types": "^3.4.2", + "@smithy/eventstream-codec": "^3.1.6", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -3037,15 +3078,15 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.22.tgz", - "integrity": "sha512-svEN7O2Tf7BoaBkPzX/8AE2Bv7p16d9/ulFAD1Gmn5g19iMqNk1WIkMxAY7SpB9/tVtUwKx0NaIsBRl88gumZA==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.23.tgz", + "integrity": "sha512-x9PbGXxkcXIpm6L26qRSCC+eaYcHwybRmqU8LO/WM2RRlW0g8lz6FIiKbKgGvHuoK3dLZRiQVSQJveiCzwnA5A==", "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^3.1.8", "@smithy/protocol-http": "^4.1.4", "@smithy/service-error-classification": "^3.0.7", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "@smithy/util-middleware": "^3.0.7", "@smithy/util-retry": "^3.0.7", @@ -3224,9 +3265,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.3.6.tgz", - "integrity": "sha512-qdH+mvDHgq1ss6mocyIl2/VjlWXew7pGwZQydwYJczEc22HZyX3k8yVPV9aZsbYbssHPvMDRA5rfBDrjQUbIIw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.0.tgz", + "integrity": "sha512-nOfJ1nVQsxiP6srKt43r2My0Gp5PLWCW2ASqUioxIiGmu6d32v4Nekidiv5qOmmtzIrmaD+ADX5SKHUuhReeBQ==", "license": "Apache-2.0", "dependencies": { "@smithy/middleware-endpoint": "^3.1.4", @@ -3324,13 +3365,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.22.tgz", - "integrity": "sha512-WKzUxNsOun5ETwEOrvooXeI1mZ8tjDTOcN4oruELWHhEYDgQYWwxZupURVyovcv+h5DyQT/DzK5nm4ZoR/Tw5Q==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.23.tgz", + "integrity": "sha512-Y07qslyRtXDP/C5aWKqxTPBl4YxplEELG3xRrz2dnAQ6Lq/FgNrcKWmV561nNaZmFH+EzeGOX3ZRMbU8p1T6Nw==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^3.1.7", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -3340,16 +3381,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.22.tgz", - "integrity": "sha512-hUsciOmAq8fsGwqg4+pJfNRmrhfqMH4Y9UeGcgeUl88kPAoYANFATJqCND+O4nUvwp5TzsYwGpqpcBKyA8LUUg==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.23.tgz", + "integrity": "sha512-9Y4WH7f0vnDGuHUa4lGX9e2p+sMwODibsceSV6rfkZOvMC+BY3StB2LdO1NHafpsyHJLpwAgChxQ38tFyd6vkg==", "license": "Apache-2.0", "dependencies": { "@smithy/config-resolver": "^3.0.9", "@smithy/credential-provider-imds": "^3.2.4", "@smithy/node-config-provider": "^3.1.8", "@smithy/property-provider": "^3.1.7", - "@smithy/smithy-client": "^3.3.6", + "@smithy/smithy-client": "^3.4.0", "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, @@ -3455,13 +3496,13 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.5.tgz", - "integrity": "sha512-jYOSvM3H6sZe3CHjzD2VQNCjWBJs+4DbtwBMvUp9y5EnnwNa7NQxTeYeQw0CKCAdGGZ3QvVkyJmvbvs5M/B10A==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.6.tgz", + "integrity": "sha512-xs/KAwWOeCklq8aMlnpk25LgxEYHKOEodfjfKclDMLcBJEVEKzDLxZxBQyztcuPJ7F54213NJS8PxoiHNMdItQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^3.1.4", - "@smithy/types": "^3.4.2", + "@smithy/abort-controller": "^3.1.5", + "@smithy/types": "^3.5.0", "tslib": "^2.6.2" }, "engines": { @@ -3722,9 +3763,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", - "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -3864,17 +3905,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", - "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", + "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/type-utils": "8.8.0", - "@typescript-eslint/utils": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/type-utils": "8.8.1", + "@typescript-eslint/utils": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -3898,16 +3939,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz", - "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.1.tgz", + "integrity": "sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", "debug": "^4.3.4" }, "engines": { @@ -3927,14 +3968,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz", - "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", + "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0" + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3945,14 +3986,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz", - "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz", + "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.1", + "@typescript-eslint/utils": "8.8.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -3970,9 +4011,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz", - "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", + "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", "dev": true, "license": "MIT", "engines": { @@ -3984,14 +4025,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz", - "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", + "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4039,16 +4080,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz", - "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", + "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0" + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4062,13 +4103,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz", - "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", + "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/types": "8.8.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -5708,9 +5749,9 @@ } }, "node_modules/eslint": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz", - "integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==", + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", + "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", "dev": true, "license": "MIT", "dependencies": { @@ -5719,11 +5760,11 @@ "@eslint/config-array": "^0.18.0", "@eslint/core": "^0.6.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.11.1", + "@eslint/js": "9.12.0", "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", + "@humanwhocodes/retry": "^0.3.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", @@ -5731,9 +5772,9 @@ "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5743,13 +5784,11 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { @@ -5850,10 +5889,11 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -5866,10 +5906,11 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -5882,6 +5923,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -5946,14 +5988,15 @@ } }, "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" + "eslint-visitor-keys": "^4.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5963,10 +6006,11 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -6145,11 +6189,12 @@ } }, "node_modules/express-session": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", - "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz", + "integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==", + "license": "MIT", "dependencies": { - "cookie": "0.6.0", + "cookie": "0.7.2", "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "~2.0.0", @@ -6162,6 +6207,15 @@ "node": ">= 0.8.0" } }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express-session/node_modules/cookie-signature": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", @@ -6272,7 +6326,9 @@ } }, "node_modules/fastq": { - "version": "1.14.0", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "license": "ISC", "dependencies": { @@ -7206,14 +7262,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -9251,6 +9299,8 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -9472,6 +9522,8 @@ }, "node_modules/reusify": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, "license": "MIT", "engines": { @@ -9591,6 +9643,8 @@ }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -10791,9 +10845,9 @@ } }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -10805,15 +10859,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.0.tgz", - "integrity": "sha512-BjIT/VwJ8+0rVO01ZQ2ZVnjE1svFBiRczcpr1t1Yxt7sT25VSbPfrJtDsQ8uQTy2pilX5nI9gwxhUyLULNentw==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.1.tgz", + "integrity": "sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.8.0", - "@typescript-eslint/parser": "8.8.0", - "@typescript-eslint/utils": "8.8.0" + "@typescript-eslint/eslint-plugin": "8.8.1", + "@typescript-eslint/parser": "8.8.1", + "@typescript-eslint/utils": "8.8.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 09e6edc6..4f21149f 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "typeorm": "typeorm-ts-node-commonjs" }, "dependencies": { - "@aws-sdk/client-kinesis": "^3.658.1", + "@aws-sdk/client-kinesis": "^3.668.0", "@nestjs/axios": "^3.0.3", "@nestjs/common": "^10.4.4", "@nestjs/config": "^3.2.3", @@ -41,7 +41,7 @@ "connect-mongo": "^5.1.0", "deep-equal": "^2.2.3", "ejs": "^3.1.10", - "express-session": "^1.18.0", + "express-session": "^1.18.1", "file-stream-rotator": "^1.0.0", "helmet": "^8.0.0", "libsodium-wrappers": "^0.7.15", @@ -62,7 +62,7 @@ "uuid": "^10.0.0" }, "devDependencies": { - "@eslint/js": "^9.11.1", + "@eslint/js": "^9.12.0", "@golevelup/ts-jest": "^0.5.6", "@nestjs/cli": "^10.4.5", "@nestjs/schematics": "^10.1.4", @@ -76,15 +76,15 @@ "@types/jest": "^29.5.13", "@types/libsodium-wrappers": "^0.7.14", "@types/lodash.merge": "^4.6.9", - "@types/node": "^22.7.4", + "@types/node": "^22.7.5", "@types/passport": "^1.0.16", "@types/passport-http": "^0.3.11", "@types/passport-jwt": "^4.0.1", "@types/supertest": "^6.0.2", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "^8.8.0", - "@typescript-eslint/parser": "^8.8.0", - "eslint": "^9.11.1", + "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/parser": "^8.8.1", + "eslint": "^9.12.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "jest": "^29.7.0", @@ -95,8 +95,8 @@ "ts-loader": "^9.5.1", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "^5.6.2", - "typescript-eslint": "^8.8.0" + "typescript": "^5.6.3", + "typescript-eslint": "^8.8.1" }, "jest": { "moduleFileExtensions": [ diff --git a/scripts/db/mongo-setup.js b/scripts/db/mongo-setup.js index b6c3c527..3af8cda9 100644 --- a/scripts/db/mongo-setup.js +++ b/scripts/db/mongo-setup.js @@ -126,6 +126,7 @@ result = db.collectionConfig.insertOne({ }, browseFields: ['title', 'name', 'short', 'position'], name: 'Environment', + hint: 'An environment refers to the context in which software is deployed and run, encompassing the tools, configurations, and infrastructure that support its operation.', permissions: { browse: true, create: false, @@ -198,6 +199,7 @@ result = db.collectionConfig.insertOne({ }, browseFields: ['name', 'title', 'website', 'email'], name: 'Project', + hint: 'A project groups services together.', permissions: { browse: true, create: true, @@ -279,6 +281,7 @@ result = db.collectionConfig.insertOne({ }, browseFields: ['name', 'title', 'scmUrl'], name: 'Service', + hint: 'A service is a software component that runs in an environment.', permissions: { browse: true, create: true, @@ -345,8 +348,8 @@ result = db.collectionConfig.insertOne({ }, }, browseFields: ['name', 'url'], - graphVertexOmit: true, name: 'Instance', + hint: 'A service instance is a provisioned service.', parent: { edgeName: 'instance', }, @@ -428,6 +431,9 @@ result = db.collectionConfig.insertOne({ dir: 1, }, fields: { + alias: { + type: 'embeddedDoc', + }, domain: { name: 'Domain', required: true, @@ -456,6 +462,7 @@ result = db.collectionConfig.insertOne({ }, browseFields: ['domain', 'username', 'name', 'email'], name: 'User', + hint: 'A user is a real or virtual person that can be granted access to Broker.', permissions: { browse: true, create: false, @@ -562,6 +569,7 @@ result = db.collectionConfig.insertOne({ }, browseFields: ['name', 'email', 'clientId', 'website', 'requireRoleId'], name: 'Broker Account', + hint: 'A Broker Account grants programmatic access to the API to teams and allows them to provision associated services.', permissions: { browse: true, create: true, @@ -631,6 +639,7 @@ result = db.collectionConfig.insertOne({ }, browseFields: ['name', 'email', 'website'], name: 'Team', + hint: 'A team is a collection of users with roles that can be setup with service and granted control of accounts.', permissions: { browse: true, create: true, @@ -731,6 +740,7 @@ result = db.collectionConfig.insertOne({ 'acquired', ], name: 'Server', + hint: 'A server is a real or virtual machine that hosts installs of services.', permissions: { browse: true, create: true, diff --git a/scripts/setenv-backend-dev.sh b/scripts/setenv-backend-dev.sh index fbfa6c98..d32e330b 100755 --- a/scripts/setenv-backend-dev.sh +++ b/scripts/setenv-backend-dev.sh @@ -19,8 +19,10 @@ if [ $? != 0 ]; then [ $PS1 ] && return || exit; fi export AUDIT_URL_TEMPLATE="https://audit.example/dashboard?from=<%= intention.transaction.start %>&to=<%= intention.transaction.end %>&hash=<%= intention.transaction.hash %>" export VAULT_TOKEN=$(eval $VAULT_TOKEN_CMD) if [ -z "$1" ]; then - export GITHUB_CLIENT_ID=$(vault kv get -field=GITHUB_CLIENT_ID apps/prod/vault/vsync) - export GITHUB_PRIVATE_KEY=$(vault kv get -field=GITHUB_PRIVATE_KEY apps/prod/vault/vsync) + export GITHUB_OAUTH_CLIENT_ID=$(vault kv get -field=GITHUB_OAUTH_CLIENT_ID apps/prod/vault/vsync) + export GITHUB_OAUTH_CLIENT_SECRET=$(vault kv get -field=GITHUB_OAUTH_CLIENT_SECRET apps/prod/vault/vsync) + export GITHUB_SYNC_CLIENT_ID=$(vault kv get -field=GITHUB_SYNC_CLIENT_ID apps/prod/vault/vsync) + export GITHUB_SYNC_PRIVATE_KEY=$(vault kv get -field=GITHUB_SYNC_PRIVATE_KEY apps/prod/vault/vsync) fi BROKER_ROLE_ID=$(vault read -format json auth/$VAULT_APPROLE_PATH/role/$VAULT_BROKER_ROLE/role-id | jq -r '.data.role_id') BROKER_SECRET_ID=$(vault write -format json -f auth/$VAULT_APPROLE_PATH/role/$VAULT_BROKER_ROLE/secret-id | jq -r '.data.secret_id') diff --git a/src/auth/auth.controller.spec.ts b/src/auth/auth.controller.spec.ts index 27a31e61..47ee0cce 100644 --- a/src/auth/auth.controller.spec.ts +++ b/src/auth/auth.controller.spec.ts @@ -1,3 +1,4 @@ +import { createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { AuthController } from './auth.controller'; @@ -7,7 +8,9 @@ describe('AuthController', () => { beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [AuthController], - }).compile(); + }) + .useMocker(createMock) + .compile(); controller = module.get(AuthController); }); diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 08436010..a4d8670d 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -1,8 +1,11 @@ -import { Controller, Get, Request, Res, UseGuards } from '@nestjs/common'; -import { Response, Request as ExpressRequest } from 'express'; +import { Controller, Get, Request, Response, UseGuards } from '@nestjs/common'; +import { + Response as ExpressResponse, + Request as ExpressRequest, +} from 'express'; +import { Issuer } from 'openid-client'; import { BrokerOidcRedirectGuard } from './broker-oidc-redirect.guard'; -import { Issuer } from 'openid-client'; @Controller('auth') export class AuthController { @@ -19,7 +22,7 @@ export class AuthController { @UseGuards(BrokerOidcRedirectGuard) @Get('/callback') - loginCallback(@Res() res: Response) { + loginCallback(@Response() res: ExpressResponse) { res.redirect('/'); } @@ -29,7 +32,10 @@ export class AuthController { * @param res */ @Get('/logout') - async logout(@Request() req: ExpressRequest, @Res() res: Response) { + async logout( + @Request() req: ExpressRequest, + @Response() res: ExpressResponse, + ) { const id_token = req.user ? (req.user as any).id_token : undefined; req.logout(() => { req.session.destroy(async () => { diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 68d2d98d..434ec051 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; + import { AuditModule } from '../audit/audit.module'; import { JwtStrategy } from './jwt.strategy'; import { PersistenceModule } from '../persistence/persistence.module'; @@ -44,6 +45,6 @@ const OidcStrategyFactory = { AuthService, ], controllers: [AuthController], - exports: [BrokerOidcAuthGuard, BrokerJwtAuthGuard], + exports: [AuthService, BrokerOidcAuthGuard, BrokerJwtAuthGuard], }) export class AuthModule {} diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts index 800ab662..6addcd32 100644 --- a/src/auth/auth.service.spec.ts +++ b/src/auth/auth.service.spec.ts @@ -1,3 +1,4 @@ +import { createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { AuthService } from './auth.service'; @@ -7,7 +8,9 @@ describe('AuthService', () => { beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [AuthService], - }).compile(); + }) + .useMocker(createMock) + .compile(); service = module.get(AuthService); }); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index a41c649f..3848967b 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -1,4 +1,23 @@ import { Injectable } from '@nestjs/common'; +import { get } from 'radash'; +import { Request } from 'express'; + +import { OAUTH2_CLIENT_MAP_GUID } from '../constants'; +import { CollectionRepository } from '../persistence/interfaces/collection.repository'; @Injectable() -export class AuthService {} +export class AuthService { + constructor(private readonly collectionRepository: CollectionRepository) {} + + public getUserDto(request: Request) { + const userGuid: string = get( + (request as any).user.userinfo, + OAUTH2_CLIENT_MAP_GUID, + ); + return this.collectionRepository.getCollectionByKeyValue( + 'user', + 'guid', + userGuid, + ); + } +} diff --git a/src/collection/account.service.ts b/src/collection/account.service.ts index d37bca68..2dcb7912 100644 --- a/src/collection/account.service.ts +++ b/src/collection/account.service.ts @@ -10,6 +10,7 @@ import { Request } from 'express'; import { Cron, CronExpression } from '@nestjs/schedule'; import { plainToInstance } from 'class-transformer'; import { catchError, lastValueFrom, of, switchMap } from 'rxjs'; +import ejs from 'ejs'; import { CollectionRepository } from '../persistence/interfaces/collection.repository'; import { SystemRepository } from '../persistence/interfaces/system.repository'; import { JwtRegistryDto } from '../persistence/dto/jwt-registry.dto'; @@ -21,6 +22,7 @@ import { MILLISECONDS_IN_SECOND, VAULT_KV_APPS_MOUNT, REDIS_PUBSUB, + VAULT_KV_APPS_TOOLS_PATH_TPL, } from '../constants'; import { ActionError } from '../intention/action.error'; import { AuditService } from '../audit/audit.service'; @@ -33,7 +35,7 @@ import { CollectionNameEnum } from '../persistence/dto/collection-dto-union.type import { ProjectDto } from '../persistence/dto/project.dto'; import { RedisService } from '../redis/redis.service'; import { VaultService } from '../vault/vault.service'; -import { GithubService } from '../github/github.service'; +import { GithubSyncService } from '../github/github-sync.service'; export class TokenCreateDTO { token: string; @@ -44,7 +46,7 @@ export class AccountService { constructor( private readonly auditService: AuditService, private readonly opensearchService: OpensearchService, - private readonly githubService: GithubService, + private readonly githubSyncService: GithubSyncService, private readonly vaultService: VaultService, private readonly redisService: RedisService, private readonly graphRepository: GraphRepository, @@ -195,7 +197,7 @@ export class AccountService { if (patchVault) { await this.addTokenToAccountServices(token, account); } - if (this.githubService.isEnabled()) { + if (this.githubSyncService.isEnabled()) { try { await this.refresh(account.id.toString()); } catch (error) { @@ -292,7 +294,10 @@ export class AccountService { serviceName: string, data: any, ) { - const path = `tools/${projectName}/${serviceName}`; + const path = ejs.render(VAULT_KV_APPS_TOOLS_PATH_TPL, { + projectName, + serviceName, + }); return lastValueFrom( this.vaultService.getKvSubkeys(VAULT_KV_APPS_MOUNT, path).pipe( catchError((err) => { @@ -329,7 +334,7 @@ export class AccountService { this.auditService.recordToolsSync('info', 'failure', message); throw new NotFoundException(`Account with ID ${id} not found`); } - if (!this.githubService.isEnabled()) { + if (!this.githubSyncService.isEnabled()) { this.auditService.recordToolsSync( 'info', 'failure', @@ -357,7 +362,9 @@ export class AccountService { // Determine if this is a valid service to sync for if ( - !this.githubService.isBrokerManagedScmUrl(service.collection.scmUrl) + !this.githubSyncService.isBrokerManagedScmUrl( + service.collection.scmUrl, + ) ) { this.auditService.recordToolsSync( 'info', @@ -378,7 +385,7 @@ export class AccountService { ); try { - await this.githubService.refresh( + await this.githubSyncService.refresh( projectName, serviceName, service.collection.scmUrl, diff --git a/src/collection/collection.controller.ts b/src/collection/collection.controller.ts index 88be2d40..bed146a2 100644 --- a/src/collection/collection.controller.ts +++ b/src/collection/collection.controller.ts @@ -10,13 +10,17 @@ import { Put, Query, Request, + Response, Sse, UseGuards, UseInterceptors, UsePipes, ValidationPipe, } from '@nestjs/common'; -import { Request as ExpressRequest } from 'express'; +import { + Response as ExpressResponse, + Request as ExpressRequest, +} from 'express'; import { ApiBearerAuth, ApiOAuth2, ApiQuery } from '@nestjs/swagger'; import { Observable } from 'rxjs'; import { @@ -69,6 +73,19 @@ export class CollectionController { return await this.userCollectionService.extractUserFromRequest(req); } + @Get('/user/link-github') + @UseGuards(BrokerOidcAuthGuard) + @ApiBearerAuth() + async linkGithub( + @Query('code') code: string, + @Query('state') state: string, + @Request() req: ExpressRequest, + @Response() res: ExpressResponse, + ) { + const user = await this.userCollectionService.linkGithub(req, state, code); + res.redirect(`/browse/user/${user.id}`); + } + @Post('user/import') @UseGuards(BrokerCombinedAuthGuard) @Roles('admin') diff --git a/src/collection/collection.service.ts b/src/collection/collection.service.ts index 1145c3ea..0c92489f 100644 --- a/src/collection/collection.service.ts +++ b/src/collection/collection.service.ts @@ -14,13 +14,11 @@ import { IntentionService } from '../intention/intention.service'; import { PERSISTENCE_TYPEAHEAD_SUBQUERY_LIMIT } from '../persistence/persistence.constants'; import { RedisService } from '../redis/redis.service'; import { IntentionActionPointerDto } from '../persistence/dto/intention-action-pointer.dto'; -import { BuildRepository } from '../persistence/interfaces/build.repository'; import { CollectionComboRestDto } from '../persistence/dto/collection-combo-rest.dto'; @Injectable() export class CollectionService { constructor( - private readonly buildRepository: BuildRepository, private readonly collectionRepository: CollectionRepository, private readonly graphRepository: GraphRepository, private readonly intentionService: IntentionService, diff --git a/src/collection/user-collection.service.ts b/src/collection/user-collection.service.ts index f8cf8e79..1b51791b 100644 --- a/src/collection/user-collection.service.ts +++ b/src/collection/user-collection.service.ts @@ -1,12 +1,15 @@ import { Injectable } from '@nestjs/common'; import { Request } from 'express'; +import { USER_ALIAS_DOMAIN_GITHUB } from '../constants'; import { CollectionRepository } from '../persistence/interfaces/collection.repository'; import { GraphService } from '../graph/graph.service'; import { UserDto } from '../persistence/dto/user.dto'; import { UserImportDto } from './dto/user-import.dto'; import { UserRolesDto } from './dto/user-roles.dto'; import { VertexInsertDto } from '../persistence/dto/vertex-rest.dto'; +import { GithubService } from '../github/github.service'; +import { AuthService } from '../auth/auth.service'; /** * Assists with user collection activities @@ -15,6 +18,8 @@ import { VertexInsertDto } from '../persistence/dto/vertex-rest.dto'; export class UserCollectionService { constructor( private readonly collectionRepository: CollectionRepository, + private readonly authService: AuthService, + private readonly githubService: GithubService, private readonly graphService: GraphService, ) {} @@ -73,4 +78,49 @@ export class UserCollectionService { } return existingUser.vertex; } + + public async linkGithub(req: Request, state: string, code: string) { + const existingUser = await this.authService.getUserDto(req); + if ( + !(await this.githubService.isRequestStateMatching( + existingUser.id.toString(), + state, + )) + ) { + console.log('hi'); + } + // console.log(state); + const token = await this.githubService.getUserAccessToken(code); + const userData = await this.githubService.getUserInfo(token); + + // console.log(userData); + + const vertex: VertexInsertDto = { + collection: 'user', + data: { + ...existingUser, + alias: [ + { + domain: USER_ALIAS_DOMAIN_GITHUB, + guid: userData.id, + name: userData.name, + username: userData.login, + raw: userData, + }, + ], + }, + }; + delete vertex.data.id; + delete vertex.data.vertex; + + // console.log(vertex); + + await this.graphService.editVertex( + req, + existingUser.vertex.toString(), + vertex, + true, + ); + return this.authService.getUserDto(req); + } } diff --git a/src/constants.ts b/src/constants.ts index d8efc50e..d3f9ecd9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,3 +1,5 @@ +export const BROKER_URL = process.env.BROKER_URL ?? ''; + export const AWS_REGION = 'ca-central-1'; export const AWS_KINESIS_BUFFER_TIME = 100; export const AWS_KINESIS_MAX_RECORDS = 10; @@ -68,6 +70,9 @@ export const VAULT_ENVIRONMENTS_SHORT = Object.freeze([ 'tools', ]); export const VAULT_KV_APPS_MOUNT = 'apps'; +export const VAULT_KV_APPS_TOOLS_PATH_TPL = + process.env.VAULT_KV_APPS_TOOLS_PATH_TPL ?? + 'tools/<%= projectName %>/<%= serviceName %>'; export const VAULT_SYNC_APP_AUTH_MOUNT = process.env.VAULT_APPROLE_PATH ?? 'vs_apps_approle'; @@ -97,8 +102,16 @@ export const REDIS_PUBSUB = { BROKER_ACCOUNT_TOKEN: 'broker-account-token', } as const; -export const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID ?? ''; -export const GITHUB_PRIVATE_KEY = process.env.GITHUB_PRIVATE_KEY ?? ''; +export const GITHUB_OAUTH_CLIENT_ID = process.env.GITHUB_OAUTH_CLIENT_ID ?? ''; +export const GITHUB_OAUTH_CLIENT_SECRET = + process.env.GITHUB_OAUTH_CLIENT_SECRET ?? ''; + +export const GITHUB_SYNC_CLIENT_ID = process.env.GITHUB_SYNC_CLIENT_ID ?? ''; +export const GITHUB_SYNC_PRIVATE_KEY = + process.env.GITHUB_SYNC_PRIVATE_KEY ?? ''; + export const GITHUB_MANAGED_URL_REGEX = process.env.GITHUB_MANAGED_URL_REGEX ?? '^https://github.com/([a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+)$'; + +export const USER_ALIAS_DOMAIN_GITHUB = 'GitHub'; diff --git a/src/github/github.service.spec.ts b/src/github/github-sync.service.spec.ts similarity index 79% rename from src/github/github.service.spec.ts rename to src/github/github-sync.service.spec.ts index a8126924..e4d4c154 100644 --- a/src/github/github.service.spec.ts +++ b/src/github/github-sync.service.spec.ts @@ -1,18 +1,18 @@ import { createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { GithubService } from './github.service'; +import { GithubSyncService } from './github-sync.service'; -describe('GithubService', () => { - let service: GithubService; +describe('GithubSyncService', () => { + let service: GithubSyncService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [GithubService], + providers: [GithubSyncService], }) .useMocker(createMock) .compile(); - service = module.get(GithubService); + service = module.get(GithubSyncService); }); it('should be defined', () => { diff --git a/src/github/github-sync.service.ts b/src/github/github-sync.service.ts new file mode 100644 index 00000000..055c1f38 --- /dev/null +++ b/src/github/github-sync.service.ts @@ -0,0 +1,214 @@ +import { Injectable } from '@nestjs/common'; +import axios, { AxiosInstance } from 'axios'; +import { lastValueFrom } from 'rxjs'; +import sodium from 'libsodium-wrappers'; +import * as jwt from 'jsonwebtoken'; +import { + GITHUB_SYNC_CLIENT_ID, + GITHUB_SYNC_PRIVATE_KEY, + GITHUB_MANAGED_URL_REGEX, + VAULT_KV_APPS_MOUNT, +} from '../constants'; +import { VaultService } from '../vault/vault.service'; + +@Injectable() +export class GithubSyncService { + private readonly axiosInstance: AxiosInstance; + private brokerManagedRegex = new RegExp(GITHUB_MANAGED_URL_REGEX); + + constructor(private readonly vaultService: VaultService) { + this.axiosInstance = axios.create({ + baseURL: 'https://api.github.com', + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); + } + + public isEnabled() { + return GITHUB_SYNC_CLIENT_ID !== '' && GITHUB_SYNC_PRIVATE_KEY !== ''; + } + + public isBrokerManagedScmUrl(scmUrl: string) { + if (!scmUrl) { + return false; + } + return this.brokerManagedRegex.test(scmUrl); + } + + public async refresh(project: string, service: string, scmUrl: string) { + if (!this.isEnabled()) { + throw new Error('Not enabled'); + } + if (!this.isBrokerManagedScmUrl(scmUrl)) { + throw new Error('Service does not have Github repo URL to update'); + } + const path = `tools/${project}/${service}`; + const kvData = await lastValueFrom( + this.vaultService.getKv(VAULT_KV_APPS_MOUNT, path), + ); + if (kvData) { + for (const [secretName, secretValue] of Object.entries(kvData)) { + await this.updateSecret(scmUrl, secretName, secretValue.toString()); + } + } + } + + public async updateSecret( + repoUrl: string, + secretName: string, + secretValue: string, + ): Promise { + const { owner, repo } = this.getOwnerAndRepoFromUrl(repoUrl); + const token = await this.getInstallationAccessToken(owner, repo); + const filteredSecretName = secretName.replace(/[^a-zA-Z0-9_]/g, '_'); + + if (!token) { + throw new Error('Github access token is null!'); + } + const { key: base64PublicKey, key_id: keyId } = await this.getPublicKey( + owner, + repo, + token, + ); + // Encrypt secret + const encryptedSecret = await this.encryptSecret( + base64PublicKey.toString('utf-8'), + secretValue, + ); + // Update secret + await this.axiosInstance.put( + `/repos/${owner}/${repo}/actions/secrets/${filteredSecretName}`, + { + encrypted_value: encryptedSecret, + key_id: keyId, + }, + { + headers: { + Authorization: `token ${token}`, + }, + }, + ); + } + + // Generate JWT + private generateJWT(): string { + const payload = { + iat: Math.floor(Date.now() / 1000) - 60, + exp: Math.floor(Date.now() / 1000) + 2 * 60, // JWT expires in 2 minutes + iss: GITHUB_SYNC_CLIENT_ID, + }; + return jwt.sign(payload, GITHUB_SYNC_PRIVATE_KEY, { algorithm: 'RS256' }); + } + + private async getInstallationId( + owner: string, + repo: string, + token: string, + ): Promise { + try { + const response = await this.axiosInstance.get( + `/repos/${owner}/${repo}/installation`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ); + if (response.data.id) return response.data.id; + } catch (error) { + console.error( + `Catch error on make API call on get Installation ID for ${owner}/${repo}`, + ); + //throw new Error('Failed to get installation id.'); + } + } + + private async getInstallationAccessToken( + owner: string, + repo: string, + ): Promise { + const token = this.generateJWT(); + try { + const installationId = await this.getInstallationId(owner, repo, token); + if (installationId) { + const response = await this.axiosInstance.post( + `/app/installations/${installationId}/access_tokens`, + {}, + { + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ); + if (response.data.token) return response.data.token; + } + } catch (error) { + console.error( + `Github App has not been authorized to access ${owner}/${repo}`, + ); + //throw new Error('Failed to get access token.'); + } + } + + private getOwnerAndRepoFromUrl(repoUrl: string): { + owner: string; + repo: string; + } { + const regex = /github\.com[:/](.+?)\/(.+?)(\.git)?$/; + const match = repoUrl.match(regex); + if (match && match.length >= 3) { + return { owner: match[1], repo: match[2] }; + } + throw new Error('Invalid GitHub URL'); + } + + private async getPublicKey( + owner: string, + repo: string, + accessToken: string, + ): Promise { + const url = `https://api.github.com/repos/${owner}/${repo}/actions/secrets/public-key`; + const response = await axios.get(url, { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: 'application/vnd.github.v3+json', + }, + }); + + return response.data; + } + + private async encryptSecret( + publicKey: string, + secretValue: string, + ): Promise { + try { + await sodium.ready; + // Convert the base64 public key to a Uint8Array + const publicKeyUint8Array = sodium.from_base64( + publicKey, + sodium.base64_variants.ORIGINAL, + ); + + // Convert the secret value to a Uint8Array + const secretUint8Array = sodium.from_string(secretValue); + + // Encrypt the secret using the public key + const encryptedUint8Array = sodium.crypto_box_seal( + secretUint8Array, + publicKeyUint8Array, + ); + + // Convert the encrypted Uint8Array to a base64 string + const encryptedBase64 = sodium.to_base64( + encryptedUint8Array, + sodium.base64_variants.ORIGINAL, + ); + return encryptedBase64; + } catch (error) { + console.error('Error encrypting the secret:', error); + //throw new Error('Failed to encrypt the secret.'); + } + } +} diff --git a/src/github/github.health.ts b/src/github/github.health.ts index 6da6907e..301f8448 100644 --- a/src/github/github.health.ts +++ b/src/github/github.health.ts @@ -1,15 +1,20 @@ import { Injectable } from '@nestjs/common'; import { HealthIndicator, HealthIndicatorResult } from '@nestjs/terminus'; import { GithubService } from './github.service'; +import { GithubSyncService } from './github-sync.service'; @Injectable() export class GithubHealthIndicator extends HealthIndicator { - constructor(private readonly githubService: GithubService) { + constructor( + private readonly githubService: GithubService, + private readonly githubSyncService: GithubSyncService, + ) { super(); } async isHealthy(key: string): Promise { - const result = this.getStatus(key, this.githubService.isEnabled(), { - enabled: this.githubService.isEnabled(), + const result = this.getStatus(key, this.githubSyncService.isEnabled(), { + alias: this.githubService.isUserAliasEnabled(), + sync: this.githubSyncService.isEnabled(), }); return result; diff --git a/src/github/github.module.ts b/src/github/github.module.ts index 46b8cda5..b661acb1 100644 --- a/src/github/github.module.ts +++ b/src/github/github.module.ts @@ -1,12 +1,14 @@ import { Module } from '@nestjs/common'; import { GithubService } from './github.service'; +import { GithubSyncService } from './github-sync.service'; import { VaultModule } from '../vault/vault.module'; import { RedisModule } from '../redis/redis.module'; import { GithubHealthIndicator } from './github.health'; +import { PersistenceModule } from '../persistence/persistence.module'; @Module({ - imports: [VaultModule, RedisModule], - providers: [GithubService, GithubHealthIndicator], - exports: [GithubService, GithubHealthIndicator], + imports: [VaultModule, RedisModule, PersistenceModule], + providers: [GithubService, GithubSyncService, GithubHealthIndicator], + exports: [GithubService, GithubSyncService, GithubHealthIndicator], }) export class GithubModule {} diff --git a/src/github/github.service.ts b/src/github/github.service.ts index 4453f9b6..2332b6cb 100644 --- a/src/github/github.service.ts +++ b/src/github/github.service.ts @@ -1,214 +1,68 @@ import { Injectable } from '@nestjs/common'; -import axios, { AxiosInstance } from 'axios'; -import { lastValueFrom } from 'rxjs'; -import sodium from 'libsodium-wrappers'; -import * as jwt from 'jsonwebtoken'; +import axios from 'axios'; import { - GITHUB_CLIENT_ID, - GITHUB_MANAGED_URL_REGEX, - GITHUB_PRIVATE_KEY, - VAULT_KV_APPS_MOUNT, + BROKER_URL, + GITHUB_OAUTH_CLIENT_ID, + GITHUB_OAUTH_CLIENT_SECRET, + USER_ALIAS_DOMAIN_GITHUB, } from '../constants'; -import { VaultService } from '../vault/vault.service'; +import { SystemRepository } from '../persistence/interfaces/system.repository'; @Injectable() export class GithubService { - private readonly axiosInstance: AxiosInstance; - private brokerManagedRegex = new RegExp(GITHUB_MANAGED_URL_REGEX); + constructor(private readonly systemRepository: SystemRepository) {} - constructor(private readonly vaultService: VaultService) { - this.axiosInstance = axios.create({ - baseURL: 'https://api.github.com', - headers: { - Accept: 'application/vnd.github.v3+json', - }, - }); + public isUserAliasEnabled() { + return GITHUB_OAUTH_CLIENT_ID !== '' && GITHUB_OAUTH_CLIENT_SECRET !== ''; } - public isEnabled() { - return GITHUB_CLIENT_ID !== '' && GITHUB_PRIVATE_KEY !== ''; - } - - public isBrokerManagedScmUrl(scmUrl: string) { - if (!scmUrl) { - return false; - } - return this.brokerManagedRegex.test(scmUrl); + public async generateAuthorizeUrl(accountId: string) { + const state = await this.systemRepository.generateUserAliasRequestState( + accountId, + USER_ALIAS_DOMAIN_GITHUB, + ); + return `https://github.com/login/oauth/authorize?client_id=${GITHUB_OAUTH_CLIENT_ID}&redirect_uri=${encodeURIComponent(this.getUserLinkRedirectUrl())}&scope=read:user&state=${state}`; } - public async refresh(project: string, service: string, scmUrl: string) { - if (!this.isEnabled()) { - throw new Error('Not enabled'); - } - if (!this.isBrokerManagedScmUrl(scmUrl)) { - throw new Error('Service does not have Github repo URL to update'); - } - const path = `tools/${project}/${service}`; - const kvData = await lastValueFrom( - this.vaultService.getKv(VAULT_KV_APPS_MOUNT, path), + public async isRequestStateMatching(accountId: string, requestState: string) { + const storedState = await this.systemRepository.getUserAliasRequestState( + accountId, + USER_ALIAS_DOMAIN_GITHUB, ); - if (kvData) { - for (const [secretName, secretValue] of Object.entries(kvData)) { - await this.updateSecret(scmUrl, secretName, secretValue.toString()); - } - } + return requestState === storedState; } - public async updateSecret( - repoUrl: string, - secretName: string, - secretValue: string, - ): Promise { - const { owner, repo } = this.getOwnerAndRepoFromUrl(repoUrl); - const token = await this.getInstallationAccessToken(owner, repo); - const filteredSecretName = secretName.replace(/[^a-zA-Z0-9_]/g, '_'); + private getUserLinkRedirectUrl() { + return BROKER_URL + '/v1/collection/user/link-github'; + } - if (!token) { - throw new Error('Github access token is null!'); - } - const { key: base64PublicKey, key_id: keyId } = await this.getPublicKey( - owner, - repo, - token, - ); - // Encrypt secret - const encryptedSecret = await this.encryptSecret( - base64PublicKey.toString('utf-8'), - secretValue, - ); - // Update secret - await this.axiosInstance.put( - `/repos/${owner}/${repo}/actions/secrets/${filteredSecretName}`, + public async getUserAccessToken(code: string) { + // console.log(code); + const req = await axios.post( + 'https://github.com/login/oauth/access_token', { - encrypted_value: encryptedSecret, - key_id: keyId, + client_id: GITHUB_OAUTH_CLIENT_ID, + client_secret: GITHUB_OAUTH_CLIENT_SECRET, + code, + redirect_uri: this.getUserLinkRedirectUrl(), }, { headers: { - Authorization: `token ${token}`, + Accept: 'application/json', // Request a JSON response }, }, ); + return req.data.access_token; } - // Generate JWT - private generateJWT(): string { - const payload = { - iat: Math.floor(Date.now() / 1000) - 60, - exp: Math.floor(Date.now() / 1000) + 2 * 60, // JWT expires in 2 minutes - iss: GITHUB_CLIENT_ID, - }; - return jwt.sign(payload, GITHUB_PRIVATE_KEY, { algorithm: 'RS256' }); - } - - private async getInstallationId( - owner: string, - repo: string, - token: string, - ): Promise { - try { - const response = await this.axiosInstance.get( - `/repos/${owner}/${repo}/installation`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - }, - ); - if (response.data.id) return response.data.id; - } catch (error) { - console.error( - `Catch error on make API call on get Installation ID for ${owner}/${repo}`, - ); - //throw new Error('Failed to get installation id.'); - } - } - - private async getInstallationAccessToken( - owner: string, - repo: string, - ): Promise { - const token = this.generateJWT(); - try { - const installationId = await this.getInstallationId(owner, repo, token); - if (installationId) { - const response = await this.axiosInstance.post( - `/app/installations/${installationId}/access_tokens`, - {}, - { - headers: { - Authorization: `Bearer ${token}`, - }, - }, - ); - if (response.data.token) return response.data.token; - } - } catch (error) { - console.error( - `Github App has not been authorized to access ${owner}/${repo}`, - ); - //throw new Error('Failed to get access token.'); - } - } - - private getOwnerAndRepoFromUrl(repoUrl: string): { - owner: string; - repo: string; - } { - const regex = /github\.com[:/](.+?)\/(.+?)(\.git)?$/; - const match = repoUrl.match(regex); - if (match && match.length >= 3) { - return { owner: match[1], repo: match[2] }; - } - throw new Error('Invalid GitHub URL'); - } - - private async getPublicKey( - owner: string, - repo: string, - accessToken: string, - ): Promise { - const url = `https://api.github.com/repos/${owner}/${repo}/actions/secrets/public-key`; - const response = await axios.get(url, { + public async getUserInfo(token: string) { + const req = await axios.get('https://api.github.com/user', { headers: { - Authorization: `Bearer ${accessToken}`, - Accept: 'application/vnd.github.v3+json', + Accept: 'application/json', // Request a JSON response + Authorization: `token ${token}`, }, }); - return response.data; - } - - private async encryptSecret( - publicKey: string, - secretValue: string, - ): Promise { - try { - await sodium.ready; - // Convert the base64 public key to a Uint8Array - const publicKeyUint8Array = sodium.from_base64( - publicKey, - sodium.base64_variants.ORIGINAL, - ); - - // Convert the secret value to a Uint8Array - const secretUint8Array = sodium.from_string(secretValue); - - // Encrypt the secret using the public key - const encryptedUint8Array = sodium.crypto_box_seal( - secretUint8Array, - publicKeyUint8Array, - ); - - // Convert the encrypted Uint8Array to a base64 string - const encryptedBase64 = sodium.to_base64( - encryptedUint8Array, - sodium.base64_variants.ORIGINAL, - ); - return encryptedBase64; - } catch (error) { - console.error('Error encrypting the secret:', error); - //throw new Error('Failed to encrypt the secret.'); - } + return req.data; } } diff --git a/src/graph/graph.service.ts b/src/graph/graph.service.ts index 78bede2a..df879aed 100644 --- a/src/graph/graph.service.ts +++ b/src/graph/graph.service.ts @@ -30,14 +30,16 @@ import { GraphTypeaheadResult } from './dto/graph-typeahead-result.dto'; import { CollectionConfigInstanceRestDto } from '../persistence/dto/collection-config-rest.dto'; import { ServiceInstanceDto } from '../persistence/dto/service-instance.dto'; import { EnvironmentDto } from '../persistence/dto/environment.dto'; -import { OAUTH2_CLIENT_MAP_GUID, REDIS_PUBSUB } from '../constants'; +import { REDIS_PUBSUB } from '../constants'; import { RedisService } from '../redis/redis.service'; import { UserPermissionNames } from '../persistence/dto/user-permission-rest.dto'; +import { AuthService } from '../auth/auth.service'; @Injectable() export class GraphService { constructor( private readonly auditService: AuditService, + private readonly authSerivice: AuthService, private readonly collectionRepository: CollectionRepository, private readonly graphRepository: GraphRepository, private readonly validatorUtil: ValidatorUtil, @@ -65,15 +67,7 @@ export class GraphService { } public async getUserPermissions(request: Request) { - const userGuid: string = get( - (request as any).user.userinfo, - OAUTH2_CLIENT_MAP_GUID, - ); - const user = await this.collectionRepository.getCollectionByKeyValue( - 'user', - 'guid', - userGuid, - ); + const user = await this.authSerivice.getUserDto(request); return this.graphRepository.getUserPermissions(user.vertex.toString()); } @@ -673,15 +667,7 @@ export class GraphService { } public async connectedVertex(request: Request) { - const userGuid: string = get( - (request as any).user.userinfo, - OAUTH2_CLIENT_MAP_GUID, - ); - const user = await this.collectionRepository.getCollectionByKeyValue( - 'user', - 'guid', - userGuid, - ); + const user = await this.authSerivice.getUserDto(request); return this.graphRepository.getUserConnectedVertex(user.vertex.toString()); } diff --git a/src/health/health-check-rest.dto.ts b/src/health/health-check-rest.dto.ts new file mode 100644 index 00000000..8e421fee --- /dev/null +++ b/src/health/health-check-rest.dto.ts @@ -0,0 +1,28 @@ +// Shared DTO: Copy in back-end and front-end should be identical + +export type HealthCheckStatus = 'error' | 'ok' | 'shutting_down'; +export type HealthIndicatorStatus = 'up' | 'down'; + +export class HealthCheckStatusInfo { + status!: HealthCheckStatus; +} + +export class HealthIndicatorResult { + [key: string]: { + /** + * The status if the given health indicator was successful or not + */ + status: HealthIndicatorStatus; + /** + * Optional settings of the health indicator result + */ + [optionalKeys: string]: any; + }; +} + +export class HealthCheckRestDto { + status!: HealthCheckStatus; + info!: HealthIndicatorResult; + error!: HealthIndicatorResult; + details!: HealthIndicatorResult; +} diff --git a/src/package/package.controller.ts b/src/package/package.controller.ts index b1c40a50..e825612f 100644 --- a/src/package/package.controller.ts +++ b/src/package/package.controller.ts @@ -47,7 +47,6 @@ export class PackageController { async search( @Query() query: PackageBuildSearchQuery, ): Promise { - console.log(query); return this.service.search( query.serviceId, query.sort, diff --git a/src/persistence/dto/user-alias-request.dto.ts b/src/persistence/dto/user-alias-request.dto.ts new file mode 100644 index 00000000..936cf80a --- /dev/null +++ b/src/persistence/dto/user-alias-request.dto.ts @@ -0,0 +1,34 @@ +import { ApiHideProperty, ApiProperty } from '@nestjs/swagger'; +import { Entity, Column, Index, ObjectIdColumn } from 'typeorm'; +import { IsDate, IsDefined, IsString } from 'class-validator'; +import { Transform } from 'class-transformer'; +import { ObjectId } from 'mongodb'; + +@Entity({ name: 'userAliasRequest' }) +export class UserAliasRequestDto { + @ObjectIdColumn() + @ApiHideProperty() + id: ObjectId; + + @Column() + @ApiProperty({ type: () => String }) + @Transform((value) => + value.obj.accountId ? new ObjectId(value.obj.accountId.toString()) : null, + ) + @Index() + accountId: ObjectId; + + @Column() + @IsDate() + createdAt: Date; + + @IsDefined() + @IsString() + @Column() + domain: string; + + @IsDefined() + @IsString() + @Column() + state: string; +} diff --git a/src/persistence/dto/user.dto.ts b/src/persistence/dto/user.dto.ts index 9d9b8dde..bf8c5dba 100644 --- a/src/persistence/dto/user.dto.ts +++ b/src/persistence/dto/user.dto.ts @@ -1,10 +1,36 @@ import { ApiHideProperty, ApiProperty } from '@nestjs/swagger'; import { Entity, ObjectIdColumn, Column } from 'typeorm'; import { IsDefined, IsOptional, IsString } from 'class-validator'; -import { Transform } from 'class-transformer'; +import { Transform, Type } from 'class-transformer'; import { ObjectId } from 'mongodb'; import { VertexPointerDto } from './vertex-pointer.dto'; +export class UserAliasDto { + @IsDefined() + @IsString() + @Column() + domain: string; + + @IsDefined() + @IsString() + @Column() + guid: string; + + @IsDefined() + @IsString() + @Column() + name: string; + + @IsDefined() + @IsString() + @Column() + username: string; + + @IsOptional() + @Column() + raw?: any; +} + export class UserGroupDto { @Column() domain?: string; @@ -29,6 +55,11 @@ export class UserDto extends VertexPointerDto { ) id: ObjectId; + @IsOptional() + @Column(() => UserAliasDto, { array: true }) + @Type(() => UserAliasDto) + alias?: UserAliasDto[]; + @IsDefined() @IsString() @Column() diff --git a/src/persistence/interfaces/system.repository.ts b/src/persistence/interfaces/system.repository.ts index d4927a85..ec93774b 100644 --- a/src/persistence/interfaces/system.repository.ts +++ b/src/persistence/interfaces/system.repository.ts @@ -33,4 +33,12 @@ export abstract class SystemRepository { ): Promise; public abstract getConnectionConfigs(): Promise; + public abstract generateUserAliasRequestState( + accountId: string, + domain: string, + ): Promise; + public abstract getUserAliasRequestState( + accountId: string, + domain: string, + ): Promise; } diff --git a/src/persistence/mongo/system-mongo.repository.ts b/src/persistence/mongo/system-mongo.repository.ts index 463a647d..915c01cc 100644 --- a/src/persistence/mongo/system-mongo.repository.ts +++ b/src/persistence/mongo/system-mongo.repository.ts @@ -1,6 +1,7 @@ +import { randomUUID } from 'node:crypto'; import { InjectRepository } from '@nestjs/typeorm'; import { MongoRepository } from 'typeorm'; -// import { ObjectId } from 'mongodb'; +import { ObjectId } from 'mongodb'; import { ConnectionConfigDto } from '../dto/connection-config.dto'; import { JwtAllowDto } from '../dto/jwt-allow.dto'; @@ -10,8 +11,8 @@ import { JwtDto } from '../dto/jwt.dto'; import { SystemRepository } from '../interfaces/system.repository'; import { PreferenceDto } from '../dto/preference.dto'; import { PreferenceRestDto } from '../dto/preference-rest.dto'; -import { ObjectId } from 'mongodb'; import { GroupRegistryByAccountDto } from '../dto/group-registry-by-account.dto'; +import { UserAliasRequestDto } from '../dto/user-alias-request.dto'; export class SystemMongoRepository implements SystemRepository { constructor( @@ -23,6 +24,8 @@ export class SystemMongoRepository implements SystemRepository { private readonly jwtBlockRepository: MongoRepository, @InjectRepository(JwtRegistryDto) private readonly jwtRegistryRepository: MongoRepository, + @InjectRepository(UserAliasRequestDto) + private readonly userAliasRequestRepository: MongoRepository, @InjectRepository(PreferenceDto) private readonly preferenceRepository: MongoRepository, ) {} @@ -195,4 +198,38 @@ export class SystemMongoRepository implements SystemRepository { public getConnectionConfigs(): Promise { return this.connectionConfigRepository.find(); } + + public async generateUserAliasRequestState( + accountId: string, + domain: string, + ): Promise { + const state = randomUUID(); + await this.userAliasRequestRepository.deleteMany({ + accountId: new ObjectId(accountId), + domain, + }); + + await this.userAliasRequestRepository.insertOne({ + accountId: new ObjectId(accountId), + createdAt: new Date(), + domain, + state, + }); + + return state; + } + + public async getUserAliasRequestState( + accountId: string, + domain: string, + ): Promise { + const request = await this.userAliasRequestRepository.findOne({ + where: { + accountId: new ObjectId(accountId), + domain, + }, + }); + + return request?.state; + } } diff --git a/src/persistence/persistence-cache.interceptor.ts b/src/persistence/persistence-cache.interceptor.ts index 59b34e1d..2f18f60c 100644 --- a/src/persistence/persistence-cache.interceptor.ts +++ b/src/persistence/persistence-cache.interceptor.ts @@ -64,8 +64,8 @@ export class PersistenceCacheInterceptor } const request = context.switchToHttp().getRequest(); - console.log(request.params); - console.log(suffixValue); + // console.log(request.params); + // console.log(suffixValue); if ( suffixValue && request.params[suffixValue] && @@ -77,7 +77,7 @@ export class PersistenceCacheInterceptor .update(suffixArr.join('|')) .digest('hex'); keyValue = `${keyValue}-${hash}`; - console.log(keyValue); + // console.log(keyValue); } const response = context.switchToHttp().getResponse(); diff --git a/src/persistence/persistence.module.ts b/src/persistence/persistence.module.ts index 9829aa75..1d6e299b 100644 --- a/src/persistence/persistence.module.ts +++ b/src/persistence/persistence.module.ts @@ -19,6 +19,7 @@ import { ServerDto } from './dto/server.dto'; import { ServiceDto } from './dto/service.dto'; import { ServiceInstanceDto } from './dto/service-instance.dto'; import { TeamDto } from './dto/team.dto'; +import { UserAliasRequestDto } from './dto/user-alias-request.dto'; import { UserDto } from './dto/user.dto'; import { VertexDto } from './dto/vertex.dto'; @@ -92,6 +93,7 @@ const redisFactory = { ProjectDto, ServerDto, TeamDto, + UserAliasRequestDto, UserDto, VertexDto, ]), diff --git a/src/system/system.controller.ts b/src/system/system.controller.ts index cccdd39a..e70ee42a 100644 --- a/src/system/system.controller.ts +++ b/src/system/system.controller.ts @@ -1,4 +1,5 @@ -import { Controller, Get, UseGuards } from '@nestjs/common'; +import { Controller, Get, Post, Req, UseGuards } from '@nestjs/common'; +import { Request } from 'express'; import { SystemService } from './system.service'; import { BrokerOidcAuthGuard } from '../auth/broker-oidc-auth.guard'; @@ -14,4 +15,10 @@ export class SystemController { getConnections() { return this.systemService.getConnections(); } + + @Post('user-link/github') + @UseGuards(BrokerOidcAuthGuard) + async getGitHubLink(@Req() request: Request) { + return this.systemService.generateGitHubAuthorizeUrl(request); + } } diff --git a/src/system/system.module.ts b/src/system/system.module.ts index 05fe2e64..e38e2343 100644 --- a/src/system/system.module.ts +++ b/src/system/system.module.ts @@ -1,10 +1,12 @@ import { Module } from '@nestjs/common'; +import { AuthModule } from '../auth/auth.module'; +import { GithubModule } from '../github/github.module'; import { PersistenceModule } from '../persistence/persistence.module'; import { SystemController } from './system.controller'; import { SystemService } from './system.service'; @Module({ - imports: [PersistenceModule], + imports: [AuthModule, PersistenceModule, GithubModule], controllers: [SystemController], providers: [SystemService], }) diff --git a/src/system/system.service.ts b/src/system/system.service.ts index b2c6bce5..dee72a74 100644 --- a/src/system/system.service.ts +++ b/src/system/system.service.ts @@ -1,14 +1,29 @@ import { Injectable } from '@nestjs/common'; +import { Request } from 'express'; import { SystemRepository } from '../persistence/interfaces/system.repository'; import { ConnectionConfigRestDto } from '../persistence/dto/connection-config-rest.dto'; +import { GithubService } from '../github/github.service'; +import { AuthService } from '../auth/auth.service'; @Injectable() export class SystemService { - constructor(private readonly systemRepository: SystemRepository) {} + constructor( + private readonly authService: AuthService, + private readonly systemRepository: SystemRepository, + private readonly github: GithubService, + ) {} async getConnections(): Promise { return (await this.systemRepository.getConnectionConfigs()).sort( (a, b) => a.order - b.order, ) as unknown as ConnectionConfigRestDto[]; } + + async generateGitHubAuthorizeUrl(request: Request) { + const user = await this.authService.getUserDto(request); + + return { + url: await this.github.generateAuthorizeUrl(user.id.toString()), + }; + } } diff --git a/ui/package-lock.json b/ui/package-lock.json index 910b472f..f73e415e 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -9,16 +9,16 @@ "version": "0.0.0", "license": "Apache-2.0", "dependencies": { - "@angular/animations": "^18.2.6", - "@angular/cdk": "^18.2.6", - "@angular/common": "^18.2.6", - "@angular/compiler": "^18.2.6", - "@angular/core": "^18.2.6", - "@angular/forms": "^18.2.6", - "@angular/material": "^18.2.6", - "@angular/platform-browser": "^18.2.6", - "@angular/platform-browser-dynamic": "^18.2.6", - "@angular/router": "^18.2.6", + "@angular/animations": "^18.2.8", + "@angular/cdk": "^18.2.8", + "@angular/common": "^18.2.8", + "@angular/compiler": "^18.2.8", + "@angular/core": "^18.2.8", + "@angular/forms": "^18.2.8", + "@angular/material": "^18.2.8", + "@angular/platform-browser": "^18.2.8", + "@angular/platform-browser-dynamic": "^18.2.8", + "@angular/router": "^18.2.8", "@bcgov/bc-sans": "^2.1.0", "class-validator": "^0.14.1", "echarts": "^5.5.1", @@ -34,9 +34,9 @@ "zone.js": "^0.14.10" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.2.6", - "@angular/cli": "^18.2.6", - "@angular/compiler-cli": "^18.2.6", + "@angular-devkit/build-angular": "^18.2.8", + "@angular/cli": "^18.2.8", + "@angular/compiler-cli": "^18.2.8", "@types/jasmine": "^5.1.4", "@types/url-regex-safe": "^1.0.2", "@types/uuid": "^10.0.0", @@ -63,13 +63,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1802.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.6.tgz", - "integrity": "sha512-oF7cPFdTLxeuvXkK/opSdIxZ1E4LrBbmuytQ/nCoAGOaKBWdqvwagRZ6jVhaI0Gwu48rkcV7Zhesg/ESNnROdw==", + "version": "0.1802.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.8.tgz", + "integrity": "sha512-/rtFQEKgS7LlB9oHr4NCBSdKnvP5kr8L5Hbd3Vl8hZOYK9QWjxKPEXnryA2d5+PCE98bBzZswCNXqELZCPTgIQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.6", + "@angular-devkit/core": "18.2.8", "rxjs": "7.8.1" }, "engines": { @@ -79,17 +79,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.6.tgz", - "integrity": "sha512-u12cJZttgs5j7gICHWSmcaTCu0EFXEzKqI8nkYCwq2MtuJlAXiMQSXYuEP9OU3Go4vMAPtQh2kShyOWCX5b4EQ==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.8.tgz", + "integrity": "sha512-qK/iLk7A8vQp1CyiJV4DpwfLjPKoiOlTtFqoO5vD8Tyxmc+R06FQp6GJTsZ7JtrTLYSiH+QAWiY6NgF/Rj/hHg==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.6", - "@angular-devkit/build-webpack": "0.1802.6", - "@angular-devkit/core": "18.2.6", - "@angular/build": "18.2.6", + "@angular-devkit/architect": "0.1802.8", + "@angular-devkit/build-webpack": "0.1802.8", + "@angular-devkit/core": "18.2.8", + "@angular/build": "18.2.8", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -100,7 +100,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.6", + "@ngtools/webpack": "18.2.8", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -231,13 +231,13 @@ "dev": true }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.6.tgz", - "integrity": "sha512-JMLcXFaitJplwZMKkqhbYirINCRD6eOPZuIGaIOVynXYGWgvJkLT9t5C2wm9HqSLtp1K7NcYG2Y7PtTVR4krnQ==", + "version": "0.1802.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.8.tgz", + "integrity": "sha512-uPpopkXkO66SSdjtVr7xCyQCPs/x6KUC76xkDc4j0b8EEHifTbi/fNpbkcZ6wBmoAfjKLWXfKvtkh0TqKK5Hkw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.6", + "@angular-devkit/architect": "0.1802.8", "rxjs": "7.8.1" }, "engines": { @@ -251,9 +251,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.6.tgz", - "integrity": "sha512-la4CFvs5PcRWSkQ/H7TB5cPZirFVA9GoWk5LzIk8si6VjWBJRm8b3keKJoC9LlNeABRUIR5z0ocYkyQQUhdMfg==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.8.tgz", + "integrity": "sha512-4o2T6wsmXGE/v53+F8L7kGoN2+qzt03C9rtjLVQpOljzpJVttQ8bhvfWxyYLWwcl04RWqRa+82fpIZtBkOlZJw==", "dev": true, "license": "MIT", "dependencies": { @@ -279,13 +279,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.6.tgz", - "integrity": "sha512-uIttrQ2cQ2PWAFFVPeCoNR8xvs7tPJ2i8gzqsIwYdge107xDC6u9CqfgmBqPDSFpWj+IiC2Jwcm8Z4HYKU4+7A==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.8.tgz", + "integrity": "sha512-i/h2Oji5FhJMC7wDSnIl5XUe/qym+C1ZwScaATJwDyRLCUIynZkj5rLgdG/uK6l+H0PgvxigkF+akWpokkwW6w==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.6", + "@angular-devkit/core": "18.2.8", "jsonc-parser": "3.3.1", "magic-string": "0.30.11", "ora": "5.4.1", @@ -298,9 +298,9 @@ } }, "node_modules/@angular/animations": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.6.tgz", - "integrity": "sha512-vy9wy+Q9beiRxkEO8wNxFQ63AqAujGvk8AUHepxxIT7QNNc512TNKz8uH+feWDPO38Dm2obwYQHMGzs3WO7pUA==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.8.tgz", + "integrity": "sha512-dMSn2hg70siv3lhP+vqhMbgc923xw6XBUvnpCPEzhZqFHvPXfh/LubmsD5RtqHmjWebXtgVcgS+zg3Gq3jB2lg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -309,18 +309,18 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.6" + "@angular/core": "18.2.8" } }, "node_modules/@angular/build": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.6.tgz", - "integrity": "sha512-TQzX6Mi7uXFvmz7+OVl4Za7WawYPcx+B5Ewm6IY/DdMyB9P/Z4tbKb1LO+ynWUXYwm7avXo6XQQ4m5ArDY5F/A==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.8.tgz", + "integrity": "sha512-ufuA4vHJSrL9SQW7bKV61DOoN1mm0t0ILTHaxSoCG3YF70cZJOX7+HNp3cK2uoldRMwbTOKSvCWBw54KKDRd5Q==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.6", + "@angular-devkit/architect": "0.1802.8", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -400,9 +400,9 @@ } }, "node_modules/@angular/cdk": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.6.tgz", - "integrity": "sha512-Gfq/iv4zhlKYpdQkDaBRwxI71NHNUHM1Cs1XhnZ0/oFct5HXvSv1RHRGTKqBJLLACaAPzZKXJ/UglLoyO5CNiQ==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.8.tgz", + "integrity": "sha512-J8A2FkwTBzLleAEWz6EgW73dEoeq87GREBPjTv8+2JV09LX+V3hnbgNk6zWq5k4OXtQNg9WrWP9QyRbUyA597g==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -417,18 +417,18 @@ } }, "node_modules/@angular/cli": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.6.tgz", - "integrity": "sha512-tdXsnV/w+Rgu8q0zFsLU5L9ImTVqrTol1vppHaQkJ/vuoHy+s8ZEbBqhVrO/ffosNb2xseUybGYvqMS4zkNQjg==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.8.tgz", + "integrity": "sha512-GKXG7F7z5rxwZ8/bnW/Bp8/zsfE/BpHmIP/icLfUIOwv2kaY5OD2tfQssWXPEuqZzYq2AYz+wjVSbWjxGoja8A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.6", - "@angular-devkit/core": "18.2.6", - "@angular-devkit/schematics": "18.2.6", + "@angular-devkit/architect": "0.1802.8", + "@angular-devkit/core": "18.2.8", + "@angular-devkit/schematics": "18.2.8", "@inquirer/prompts": "5.3.8", "@listr2/prompt-adapter-inquirer": "2.0.15", - "@schematics/angular": "18.2.6", + "@schematics/angular": "18.2.8", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", @@ -451,9 +451,9 @@ } }, "node_modules/@angular/common": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.6.tgz", - "integrity": "sha512-89793ow+wrI1c7C6kyMbnweLNIZHzXthosxAEjipRZGBrqBYjvTtkE45Fl+5yBa3JO7bAhyGkUnEoyvWtZIAEA==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.8.tgz", + "integrity": "sha512-TYsKtE5nVaIScWSLGSO34Skc+s3hB/BujSddnfQHoNFvPT/WR0dfmdlpVCTeLj+f50htFoMhW11tW99PbK+whQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -462,14 +462,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.6", + "@angular/core": "18.2.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.6.tgz", - "integrity": "sha512-3tX2/Qw+bZ8XzKitviH8jzNGyY0uohhehhBB57OJOCc+yr4ojy/7SYFnun1lSsRnDztdCE461641X4iQLCQ94w==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.8.tgz", + "integrity": "sha512-JRedHNfK1CCPVyeGQB5w3WBYqMA6X8Q240CkvjlGfn0pVXihf9DWk3nkSQJVgYxpvpHfxdgjaYZ5IpMzlkmkhw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -478,7 +478,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.6" + "@angular/core": "18.2.8" }, "peerDependenciesMeta": { "@angular/core": { @@ -487,15 +487,15 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.6.tgz", - "integrity": "sha512-b5x9STfjNiNM/S0D+CnqRP9UOxPtSz1+RlCH5WdOMiW/p8j5p6dBix8YYgTe6Wg3OD7eItD2pnFQKgF/dWiopA==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.8.tgz", + "integrity": "sha512-OksDE4LWQUCcIvMjtZF7eiDCdIMrcMMpC1+Q0PIYi7KmnqXFGs4/Y0NdJvtn/LrQznzz5WaKM3ZDVNZTRX4wmw==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^3.0.0", + "chokidar": "^4.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", @@ -511,14 +511,44 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.2.6", + "@angular/compiler": "18.2.8", "typescript": ">=5.4 <5.6" } }, + "node_modules/@angular/compiler-cli/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular/compiler-cli/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/core": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.6.tgz", - "integrity": "sha512-PjFad2j4YBwLVTw+0Te8CJCa/tV0W8caTHG8aOjj3ObdL6ihGI+FKnwerLc9RVzDFd14BOO4C6/+LbOQAh3Ltw==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.8.tgz", + "integrity": "sha512-NwIuX/Iby1jT6Iv1/s6S3wOFf8xfuQR3MPGvKhGgNtjXLbHG+TXceK9+QPZC0s9/Z8JR/hz+li34B79GrIKgUg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -532,9 +562,9 @@ } }, "node_modules/@angular/forms": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.6.tgz", - "integrity": "sha512-quGkUqTxlBaLB8C/RnpfFG57fdmNF5RQ+368N89Ma++2lpIsVAHaGZZn4yOyo3wNYaM2jBxNqaYxOzZNUl5Tig==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.8.tgz", + "integrity": "sha512-JCLki7KC6D5vF6dE6yGlBmW33khIgpHs8N9SzuiJtkQqNDTIQA8cPsGV6qpLpxflxASynQOX5lDkWYdQyfm77Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -543,23 +573,23 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.6", - "@angular/core": "18.2.6", - "@angular/platform-browser": "18.2.6", + "@angular/common": "18.2.8", + "@angular/core": "18.2.8", + "@angular/platform-browser": "18.2.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/material": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.6.tgz", - "integrity": "sha512-ObxC/vomSb9QF3vIztuiInQzws+D6u09Dhfx6uNFjtyICqxEFpF7+Qx7QVDWrsuXOgxZTKgacK8f46iV8hWUfg==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.8.tgz", + "integrity": "sha512-wQGMVsfQ9lQfih2VsWAvV4z3S3uBxrxc61owlE+K0T1BxH9u/jo3A/rnRitIdvR/L4NnYlfhCnmrW9K+Pl+WCg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^18.0.0 || ^19.0.0", - "@angular/cdk": "18.2.6", + "@angular/cdk": "18.2.8", "@angular/common": "^18.0.0 || ^19.0.0", "@angular/core": "^18.0.0 || ^19.0.0", "@angular/forms": "^18.0.0 || ^19.0.0", @@ -568,9 +598,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.6.tgz", - "integrity": "sha512-RA8UMiYNLga+QMwpKcDw1357gYPfPyY/rmLeezMak//BbsENFYQOJ4Z6DBOBNiPlHxmBsUJMGaKdlpQhfCROyQ==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.8.tgz", + "integrity": "sha512-EPai4ZPqSq3ilLJUC85kPi9wo5j5suQovwtgRyjM/75D9Qy4TV19g8hkVM5Co/zrltO8a2G6vDscCNI5BeGw2A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -579,9 +609,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.2.6", - "@angular/common": "18.2.6", - "@angular/core": "18.2.6" + "@angular/animations": "18.2.8", + "@angular/common": "18.2.8", + "@angular/core": "18.2.8" }, "peerDependenciesMeta": { "@angular/animations": { @@ -590,9 +620,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.6.tgz", - "integrity": "sha512-kGBU3FNc+DF9r33hwHZqiWoZgQbCDdEIucU0NCLCIg0Hw6/Q9Hr2ndjxQI+WynCPg0JeBn34jpouvpeJer3YDQ==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.8.tgz", + "integrity": "sha512-poZoapDqyN/rxGKQ3C6esdPiPLMkSpP2v12hoEa12KHgfPk7T1e+a+NMyJjV8HeOY3WyvL7tGRhW0NPTajTkhw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -601,16 +631,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.6", - "@angular/compiler": "18.2.6", - "@angular/core": "18.2.6", - "@angular/platform-browser": "18.2.6" + "@angular/common": "18.2.8", + "@angular/compiler": "18.2.8", + "@angular/core": "18.2.8", + "@angular/platform-browser": "18.2.8" } }, "node_modules/@angular/router": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.6.tgz", - "integrity": "sha512-t57Sqja8unHhZlPr+4CWnQacuox2M4p2pMHps+31wt337qH6mKf4jqDmK0dE/MFdRyKjT2a2E/2NwtxXxcWNuw==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.8.tgz", + "integrity": "sha512-L+olYgxIiBq+tbfayVI0cv1yOuymsw33msnGC2l/vpc9sSVfqGzESFnB4yMVU3vHtE9v6v2Y6O+iV44/b79W/g==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -619,9 +649,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.6", - "@angular/core": "18.2.6", - "@angular/platform-browser": "18.2.6", + "@angular/common": "18.2.8", + "@angular/core": "18.2.8", + "@angular/platform-browser": "18.2.8", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -3230,9 +3260,9 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", - "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3437,9 +3467,9 @@ ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.6.tgz", - "integrity": "sha512-7HwOPE1EOgcHnpt4brSiT8G2CcXB50G0+CbCBaKGy4LYCG3Y3mrlzF5Fup9HvMJ6Tzqd62RqzpKKYBiGUT7hxg==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.8.tgz", + "integrity": "sha512-sq0kI8gEen4QlM6X8XqOYy7j4B8iLCYNo+iKxatV36ts4AXH0MuVkP56+oMaoH5oZNoSqd0RlfnotEHfvJAr8A==", "dev": true, "license": "MIT", "engines": { @@ -3988,14 +4018,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.6.tgz", - "integrity": "sha512-Y988EoOEQDLEyHu3414T6AeVUyx21AexBHQNbUNQkK8cxlxyB6m1eH1cx6vFgLRFUTsLVv+C6Ln/ICNTfLcG4A==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.8.tgz", + "integrity": "sha512-62Sr7/j/dlhZorxH4GzQgpJy0s162BVts0Q7knZuEacP4VL+IWOUE1NS9OFkh/cbomoyXBdoewkZ5Zd1dVX78w==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.6", - "@angular-devkit/schematics": "18.2.6", + "@angular-devkit/core": "18.2.8", + "@angular-devkit/schematics": "18.2.8", "jsonc-parser": "3.3.1" }, "engines": { @@ -6698,9 +6728,9 @@ "dev": true }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6709,7 +6739,7 @@ "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -6741,9 +6771,9 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "license": "MIT", "engines": { @@ -9194,9 +9224,9 @@ } }, "node_modules/memfs": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.12.0.tgz", - "integrity": "sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.13.0.tgz", + "integrity": "sha512-dIs5KGy24fbdDhIAg0RxXpFqQp3RwL6wgSMRF9OSuphL/Uc9a4u2/SDJKPLj/zUgtOGKuHrRMrj563+IErj4Cg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -13472,9 +13502,9 @@ } }, "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/ui/package.json b/ui/package.json index 3abac5e6..a4c78e64 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,16 +12,16 @@ "private": true, "license": "Apache-2.0", "dependencies": { - "@angular/animations": "^18.2.6", - "@angular/cdk": "^18.2.6", - "@angular/common": "^18.2.6", - "@angular/compiler": "^18.2.6", - "@angular/core": "^18.2.6", - "@angular/forms": "^18.2.6", - "@angular/material": "^18.2.6", - "@angular/platform-browser": "^18.2.6", - "@angular/platform-browser-dynamic": "^18.2.6", - "@angular/router": "^18.2.6", + "@angular/animations": "^18.2.8", + "@angular/cdk": "^18.2.8", + "@angular/common": "^18.2.8", + "@angular/compiler": "^18.2.8", + "@angular/core": "^18.2.8", + "@angular/forms": "^18.2.8", + "@angular/material": "^18.2.8", + "@angular/platform-browser": "^18.2.8", + "@angular/platform-browser-dynamic": "^18.2.8", + "@angular/router": "^18.2.8", "@bcgov/bc-sans": "^2.1.0", "class-validator": "^0.14.1", "echarts": "^5.5.1", @@ -37,9 +37,9 @@ "zone.js": "^0.14.10" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.2.6", - "@angular/cli": "^18.2.6", - "@angular/compiler-cli": "^18.2.6", + "@angular-devkit/build-angular": "^18.2.8", + "@angular/cli": "^18.2.8", + "@angular/compiler-cli": "^18.2.8", "@types/jasmine": "^5.1.4", "@types/url-regex-safe": "^1.0.2", "@types/uuid": "^10.0.0", diff --git a/ui/src/app/browse/collection-inspector/collection-inspector.component.html b/ui/src/app/browse/collection-inspector/collection-inspector.component.html index 943e7c88..75e964ed 100644 --- a/ui/src/app/browse/collection-inspector/collection-inspector.component.html +++ b/ui/src/app/browse/collection-inspector/collection-inspector.component.html @@ -189,6 +189,18 @@ + @if (collection === 'user') { + + +
+ Alias +
+ +
+
+ } + @if (collection === 'service' || collection === 'project' || collection === 'brokerAccount') { diff --git a/ui/src/app/browse/collection-inspector/collection-inspector.component.ts b/ui/src/app/browse/collection-inspector/collection-inspector.component.ts index e9251846..6cec02df 100644 --- a/ui/src/app/browse/collection-inspector/collection-inspector.component.ts +++ b/ui/src/app/browse/collection-inspector/collection-inspector.component.ts @@ -65,6 +65,7 @@ import { DeleteConfirmDialogComponent } from '../../graph/delete-confirm-dialog/ import { TagDialogComponent } from '../../graph/tag-dialog/tag-dialog.component'; import { VertexDialogComponent } from '../../graph/vertex-dialog/vertex-dialog.component'; import { ServiceInstanceDetailsComponent } from '../service-instance-details/service-instance-details.component'; +import { UserAliasComponent } from '../user-alias/user-alias.component'; @Component({ selector: 'app-collection-inspector', @@ -102,6 +103,7 @@ import { ServiceInstanceDetailsComponent } from '../service-instance-details/ser TeamMembersComponent, TeamServicesComponent, TeamSummaryComponent, + UserAliasComponent, VertexTagsComponent, ], templateUrl: './collection-inspector.component.html', diff --git a/ui/src/app/browse/user-alias/user-alias.component.html b/ui/src/app/browse/user-alias/user-alias.component.html new file mode 100644 index 00000000..c2277a1e --- /dev/null +++ b/ui/src/app/browse/user-alias/user-alias.component.html @@ -0,0 +1,30 @@ +
+
+

GitHub

+ + @if(healthStatus.health$ | async; as health) { + @if(isSelf && health.details['github']['alias']) { + + } + } +
+
+ +@if(!collection?.alias) { +
Account is not linked
+} + +@if(collection?.alias) { +
+
+
Username
+
{{ collection.alias[0].username }}
+
+
+} \ No newline at end of file diff --git a/ui/src/app/browse/user-alias/user-alias.component.scss b/ui/src/app/browse/user-alias/user-alias.component.scss new file mode 100644 index 00000000..40330a6e --- /dev/null +++ b/ui/src/app/browse/user-alias/user-alias.component.scss @@ -0,0 +1,57 @@ + + +.edge-container-margin-left { + margin-left: 16px; + margin-bottom: 16px; +} + +.edge-container-buttons a { + margin-right: 12px; +} + +.heading { + margin-left: 16px; +} + +.heading { + display: flex; + align-items: center; +} + +.heading h3 { + flex-grow: 1; + margin: 0; +} + +.heading :last-child { + flex-grow: 0; +} + +.details-container { + flex: 0 0 auto; + margin-bottom: 16px; +} + +.details-item { + margin-left: -4px; + padding: 4px; + margin-bottom: 12px; +} + +.details-item-clickable:hover { + background: whitesmoke; + cursor: pointer; + border-radius: 8px; +} + +.details-header { + min-width: 100px; + font-weight: 500; + color: #333; +} + +.details-line { + color: var(--mat-card-subtitle-text-color); + min-width: 100px; + font-weight: 300; +} diff --git a/ui/src/app/browse/user-alias/user-alias.component.spec.ts b/ui/src/app/browse/user-alias/user-alias.component.spec.ts new file mode 100644 index 00000000..2b8f93fc --- /dev/null +++ b/ui/src/app/browse/user-alias/user-alias.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserAliasComponent } from './user-alias.component'; + +describe('UserAliasComponent', () => { + let component: UserAliasComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UserAliasComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UserAliasComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ui/src/app/browse/user-alias/user-alias.component.ts b/ui/src/app/browse/user-alias/user-alias.component.ts new file mode 100644 index 00000000..f6cef888 --- /dev/null +++ b/ui/src/app/browse/user-alias/user-alias.component.ts @@ -0,0 +1,44 @@ +import { Component, Inject, Input, OnChanges } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { SystemApiService } from '../../service/system-api.service'; +import { CURRENT_USER } from '../../app-initialize.factory'; +import { UserDto } from '../../service/graph.types'; +import { HealthStatusService } from '../../service/health-status.service'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-user-alias', + standalone: true, + imports: [CommonModule, MatButtonModule], + templateUrl: './user-alias.component.html', + styleUrl: './user-alias.component.scss', +}) +export class UserAliasComponent implements OnChanges { + @Input() collection: any; + + isSelf = false; + + constructor( + private readonly systemApi: SystemApiService, + public readonly healthStatus: HealthStatusService, + @Inject(CURRENT_USER) public readonly user: UserDto, + ) {} + + ngOnChanges(): void { + this.isSelf = this.user.vertex === this.collection?.vertex; + } + + public async linkGitHubAccount() { + this.systemApi.userLinkGithub().subscribe({ + next: (data) => { + window.location.href = data.url; + }, + error: (err: any) => { + console.log(err); + // this.openSnackBar( + // 'Syncing token failed: ' + (err?.statusText ?? 'unknown'), + // ); + }, + }); + } +} diff --git a/ui/src/app/graph/inspector-account/inspector-account.component.html b/ui/src/app/graph/inspector-account/inspector-account.component.html index 3c36b63c..f73eb048 100644 --- a/ui/src/app/graph/inspector-account/inspector-account.component.html +++ b/ui/src/app/graph/inspector-account/inspector-account.component.html @@ -15,9 +15,11 @@

Token

- + } @if (lastJwtTokenData) { - diff --git a/ui/src/app/toolbar/toolbar.component.ts b/ui/src/app/toolbar/toolbar.component.ts index 41afb6e5..308a4222 100644 --- a/ui/src/app/toolbar/toolbar.component.ts +++ b/ui/src/app/toolbar/toolbar.component.ts @@ -22,6 +22,7 @@ import { HealthStatusService } from '../service/health-status.service'; import { interval, Subject } from 'rxjs'; import { takeUntil, catchError } from 'rxjs/operators'; import { SearchInputComponent } from './search-input/search-input.component'; +import { CollectionUtilService } from '../service/collection-util.service'; @Component({ selector: 'app-toolbar', @@ -45,6 +46,7 @@ export class ToolbarComponent implements OnInit, OnDestroy { constructor( private readonly dialog: MatDialog, private readonly healthService: HealthStatusService, + private readonly collectionUtil: CollectionUtilService, @Inject(CURRENT_USER) public readonly user: UserDto, ) {} @@ -75,8 +77,7 @@ export class ToolbarComponent implements OnInit, OnDestroy { getHealthCheck(): any { try { - this.healthService - .healthCheck() + this.healthService.health$ .pipe( catchError((error: any) => { this.healthStatus = false; @@ -100,6 +101,10 @@ export class ToolbarComponent implements OnInit, OnDestroy { this.statusText = this.healthStatus ? 'Online' : 'Offline'; } + showUser() { + this.collectionUtil.openInBrowserByVertexId('user', this.user.vertex); + } + showRolesDialog() { this.dialog.open(RolesDialogComponent, { width: '400px',