diff --git a/.changeset/clever-steaks-hope.md b/.changeset/clever-steaks-hope.md new file mode 100644 index 0000000000..94c6e8ee29 --- /dev/null +++ b/.changeset/clever-steaks-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-unprocessed': patch +--- + +Explicitly only depend on the `use` method from the `HttpRouterService`. diff --git a/.changeset/famous-zoos-remain.md b/.changeset/famous-zoos-remain.md new file mode 100644 index 0000000000..be4147c21e --- /dev/null +++ b/.changeset/famous-zoos-remain.md @@ -0,0 +1,12 @@ +--- +'@backstage/plugin-entity-feedback-backend': patch +'@backstage/plugin-azure-devops-backend': patch +'@backstage/plugin-lighthouse-backend': patch +'@backstage/plugin-devtools-backend': patch +'@backstage/plugin-linguist-backend': patch +'@backstage/plugin-badges-backend': patch +'@backstage/plugin-adr-backend': patch +'@backstage/plugin-airbrake': patch +--- + +Updated New Backend System instructions to use default import diff --git a/.changeset/funny-meals-tease.md b/.changeset/funny-meals-tease.md new file mode 100644 index 0000000000..3dce739952 --- /dev/null +++ b/.changeset/funny-meals-tease.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': minor +--- + +support oidc customization diff --git a/.changeset/honest-pets-judge.md b/.changeset/honest-pets-judge.md new file mode 100644 index 0000000000..468fc1b6d5 --- /dev/null +++ b/.changeset/honest-pets-judge.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-notifications-backend': patch +'@backstage/plugin-notifications-common': patch +'@backstage/plugin-notifications': patch +--- + +Add support for signal type in notifications diff --git a/.changeset/metal-clocks-suffer.md b/.changeset/metal-clocks-suffer.md new file mode 100644 index 0000000000..c459be9fa5 --- /dev/null +++ b/.changeset/metal-clocks-suffer.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitea': minor +'@backstage/plugin-scaffolder-backend': minor +--- + +Created a gitea module for the scaffolder. This module provides a new action "publish:gitea" able to create a gitea repository owned by an organization. See: https://gitea.com/api/swagger#/organization/createOrgRepo diff --git a/.changeset/nasty-suns-speak.md b/.changeset/nasty-suns-speak.md new file mode 100644 index 0000000000..2c5fff25a1 --- /dev/null +++ b/.changeset/nasty-suns-speak.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Add an internal limiter on concurrency when launching processes diff --git a/.changeset/renovate-4b0ba1e.md b/.changeset/renovate-4b0ba1e.md new file mode 100644 index 0000000000..54dcd58187 --- /dev/null +++ b/.changeset/renovate-4b0ba1e.md @@ -0,0 +1,5 @@ +--- +'@backstage/config-loader': patch +--- + +Updated dependency `typescript-json-schema` to `^0.63.0`. diff --git a/.changeset/shiny-jeans-begin.md b/.changeset/shiny-jeans-begin.md new file mode 100644 index 0000000000..d542747b34 --- /dev/null +++ b/.changeset/shiny-jeans-begin.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Validate if the `baseUrl` is a valid URL diff --git a/.changeset/thick-pillows-punch.md b/.changeset/thick-pillows-punch.md new file mode 100644 index 0000000000..def589d3f8 --- /dev/null +++ b/.changeset/thick-pillows-punch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-node': patch +--- + +Add gitea as new type to be used from integrations configuration diff --git a/.changeset/tidy-cycles-obey.md b/.changeset/tidy-cycles-obey.md new file mode 100644 index 0000000000..4a002269e1 --- /dev/null +++ b/.changeset/tidy-cycles-obey.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Remove unused deps diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 828e5f5481..5d979d5f22 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -3,17 +3,24 @@ labels: ['dependencies'], - extends: ['config:best-practices', ':gitSignOff'], + extends: [ + 'config:best-practices', + ':gitSignOff', + 'default:pinDigestsDisabled', + ], // do not pin dev dependencies, which are part of the best-practices preset - ignorePresets: [':pinDevDependencies'], + ignorePresets: [':pinDevDependencies', ':pinDigest'], // the default limit are 10 PRs prConcurrentLimit: 20, postUpdateOptions: ['yarnDedupeHighest'], rangeStrategy: 'update-lockfile', - // @elastic/elasticsearch is ignored due to licensing issues. See #10992 - ignoreDeps: ['@elastic/elasticsearch', 'event-source-polyfill'], + ignoreDeps: [ + // ignored due to licensing issues. See #10992 + '@elastic/elasticsearch', + 'event-source-polyfill', + ], packageRules: [ { matchSourceUrlPrefixes: ['https://github.com/spotify/web-scripts'], diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c8d009f8e..5df2a2509d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,7 +155,7 @@ jobs: name: Test ${{ matrix.node-version }} services: postgres16: - image: postgres:16@sha256:39d764950f22cfe878661247bb15cb344169dc3d55c9d4676303a2ef8675c057 + image: postgres:16 env: POSTGRES_PASSWORD: postgres options: >- @@ -166,7 +166,7 @@ jobs: ports: - 5432/tcp postgres12: - image: postgres:12@sha256:7a4c3f690fa767db8aaa4a9da3870037535307cc7f8f1880f1d7275a1be29b4d + image: postgres:12 env: POSTGRES_PASSWORD: postgres options: >- @@ -177,7 +177,7 @@ jobs: ports: - 5432/tcp mysql8: - image: mysql:8@sha256:343b82684a6b05812c58ca20ccd3af8bcf8a5f48b1842f251c54379bfce848f9 + image: mysql:8 env: MYSQL_ROOT_PASSWORD: root options: >- diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index 707e70ed56..c91fec948e 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -23,7 +23,7 @@ jobs: services: postgres16: - image: postgres:16@sha256:39d764950f22cfe878661247bb15cb344169dc3d55c9d4676303a2ef8675c057 + image: postgres:16 env: POSTGRES_PASSWORD: postgres options: >- @@ -34,7 +34,7 @@ jobs: ports: - 5432/tcp postgres12: - image: postgres:12@sha256:7a4c3f690fa767db8aaa4a9da3870037535307cc7f8f1880f1d7275a1be29b4d + image: postgres:12 env: POSTGRES_PASSWORD: postgres options: >- @@ -45,7 +45,7 @@ jobs: ports: - 5432/tcp mysql8: - image: mysql:8@sha256:343b82684a6b05812c58ca20ccd3af8bcf8a5f48b1842f251c54379bfce848f9 + image: mysql:8 env: MYSQL_ROOT_PASSWORD: root options: >- diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 4155f08e03..621776d69b 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@e675ced7a7522a761fc9c8eb26682c8b27c42b2b # v3.24.1 + uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3 with: sarif_file: results.sarif diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index 080bd3cc73..7ee4e72d38 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -58,6 +58,6 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} NODE_OPTIONS: --max-old-space-size=7168 - name: Upload Snyk report - uses: github/codeql-action/upload-sarif@e675ced7a7522a761fc9c8eb26682c8b27c42b2b # v3.24.1 + uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3 with: sarif_file: snyk.sarif diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index 48195726e1..7c7ef286db 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e675ced7a7522a761fc9c8eb26682c8b27c42b2b # v3.24.1 + uses: github/codeql-action/init@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@e675ced7a7522a761fc9c8eb26682c8b27c42b2b # v3.24.1 + uses: github/codeql-action/autobuild@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -80,4 +80,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e675ced7a7522a761fc9c8eb26682c8b27c42b2b # v3.24.1 + uses: github/codeql-action/analyze@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3 diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 2da0739e64..dc62ce5725 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -19,7 +19,7 @@ jobs: services: postgres: - image: postgres:12@sha256:7a4c3f690fa767db8aaa4a9da3870037535307cc7f8f1880f1d7275a1be29b4d + image: postgres:12 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 537499016c..70fb16ac48 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -51,7 +51,7 @@ jobs: - run: yarn build-storybook - - uses: chromaui/action@a7938ff070f700b48e271857366b0564d65e3e5b # v10 + - uses: chromaui/action@c9067691aca4a28d6fbb40d9eea6e144369fbcae # v10 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks diff --git a/beps/0003-auth-architecture-evolution/README.md b/beps/0003-auth-architecture-evolution/README.md index 713184be8c..dc475fa14d 100644 --- a/beps/0003-auth-architecture-evolution/README.md +++ b/beps/0003-auth-architecture-evolution/README.md @@ -1,6 +1,6 @@ --- title: Auth Architecture Evolution -status: provisional +status: implementable authors: - '@Rugvip' owners: @@ -60,6 +60,7 @@ The following goals are the primary focus of this BEP: - No advanced rate limiting or other protection against DDoS attacks. If this is a concern then adopters should still use other external technologies to protect access to their Backstage instance. - As part of the immediate work we will only add as much support for service-to-service auth as is needed for a stable API, and not necessarily make it very capable from the start. +- We will not aim to provide an abstraction that makes it possible to switch out the `Authorization` header for service-to-service communication. ## Proposal @@ -126,11 +127,13 @@ export interface AuthService { type: TType, ): credentials is BackstageCredentials; - getOwnCredentials(): Promise>; + getOwnServiceCredentials(): Promise< + BackstageCredentials + >; - // TODO: should the caller provide the target plugin ID? if not - probably skip the object form - issueServiceToken(options: { - forward: BackstageCredentials; + getPluginRequestToken(options: { + onBehalfOf: BackstageCredentials; + targetPluginId: string; }): Promise<{ token: string }>; } ``` @@ -257,7 +260,6 @@ The new `HttpAuthService` interface is defined as follows: ```ts type BackstageHttpAccessToPrincipalTypesMapping = { user: BackstageUserPrincipal; - 'user-cookie': BackstageUserPrincipal; service: BackstageServicePrincipal; unauthenticated: BackstageNonePrincipal; unknown: unknown; @@ -270,17 +272,16 @@ export interface HttpAuthService { | keyof BackstageHttpAccessToPrincipalTypesMapping = 'unknown', >( req: Request, - options?: { allow: Array }, + options?: { + allow?: Array; + allowedAuthMethods?: Array<'token' | 'cookie'>; + }, ): Promise< BackstageCredentials >; - requestHeaders(options: { - forward: BackstageCredentials; - }): Promise>; - // The cookie issued by this method must be consumable by the `credentials` method, which in turn - // should create a credentials object that can be passed to the `issueServiceToken` method. + // should create a credentials object that can be passed to the `getPluginRequestToken` method. // The issued token must then in turn be a valid token for a user principal with full access. issueUserCookie(res: Response): Promise; } @@ -304,6 +305,25 @@ router.get('/read-data', (req, res) => { }); ``` +#### Issue a service token for a backend-to-backend request + +NOTE: This is not what we want this kind of request to look like in practice. The goal is to forward credential objects as far as possible, keeping the `auth.getPluginRequestToken(...)` in API client code rather than plugin app code. + +```ts +const { token } = await auth.getPluginRequestToken({ + onBehalfOf: await auth.getOwnServiceCredentials(), + targetPluginId: 'example', +}); + +const baseUrl = await discovery.getBaseUrl('example'); +const res = await fetch(`${baseUrl}/some-resource`, { + headers: { + // A utility may be provided for this in the future if needed, this is currently fairly rare + Authorization: `Bearer ${token}`, + }, +}); +``` + #### Forward the user credentials from an incoming requests to upstream plugin backend ```ts @@ -315,8 +335,9 @@ class CatalogIntegration { }, ) { return catalogClient.getEntityByRef(req.params.entityRef, { - token: await auth.issueServiceToken({ - forward: options.credentials, + token: await auth.getPluginRequestToken({ + onBehalfOf: options.credentials, + targetPluginId: 'catalog', }), }); } @@ -402,27 +423,30 @@ backend: dangerouslyDisableServiceAuth: true ``` -The exact impact that this has is that it disables the check in the `HttpRouterService` implementation, effectively applying the `unauthenticated` access level to all routes. Furthermore, it will also change `AuthService` so that the `issueServiceToken()` method will now issue an empty token for a `'none'` principal, rather than throwing. +The exact impact that this has is that it disables the check in the `HttpRouterService` implementation, effectively applying the `unauthenticated` access level to all routes. Furthermore, it will also change `AuthService` so that the `getPluginRequestToken()` method will now issue an empty token for a `'none'` principal, rather than throwing. ## Release Plan The existing `IdentityService` and `TokenManagerService` will be deprecated and instead implemented in terms of the new `AuthService`. -The release plan for the `HttpAuthService` is TBD, but is likely to be shipped as a no-op for plugins using the old backend system. The goal is for all plugins using the new backend system to have endpoint security be opt-out, which will be a breaking change. +The new `AuthService` and `HttpAuthService` will need backwards compatible implementations for the old backend system. The plan is to not apply any access restrictions for the old Backend system, only implementing that in the new system. The backwards compatibility helpers will use the provided `identity` and `tokenManager` services if available, and plugins should provide fallbacks in the same way as they currently do. If these are not provided, the `identity` client will fall back to `DefaultIdentityClient`, and `tokenManager` will fall back to `ServicerTokenManager.noop()`. -### Implementation Tasks +The backwards compatibility helpers will have the following behavior for each individual service call: -- [ ] Implement `AuthService` -- [ ] Implement `HttpAuthService` - leave cookie auth as unimplemented for now -- [ ] Add `addAuthPolicy()` for `HttpRouterService`, using `HttpAuthService` -- [ ] Implement a compatibility wrapper in `backend-common` that accepts `AuthService`, `HttpAuthService`, `IdentityService`, and `TokenManagerService` (all optional), and returns implementations for `AuthService` and `HttpAuthService`, such hat existing plugins can use a single `createRouter` implementation for both the old and new backend systems. -- [ ] Implement `UserInfoService` in `@backstage/auth-node` - for now it will just extract the ownership entity refs from the token stored in the credentials -- [ ] Implement cookie auth in `HttpAuthService` - just put the user token in the cookie for now -- [ ] Deprecate `IdentityService` and `TokenManagerService`, switch to using default factories that depend on the `AuthService` and `HttpAuthService`. Stop supplying implementations for these in `backend-defaults` and `backend-test-utils` -- [ ] Migrate plugins: - - [ ] Permission backend - - [ ] TechDocs backend - - [ ] App backend +- `auth.authenticate(token)`: If the decoded token has the `backstage` audience, authenticate the token for a user principal using `identity.getIdentity(...)`, otherwise authenticate it using `tokenManager.authenticate(...)` and return a service principal with the subject `external:backstage-plugin`. If a no-op token manager is used then anything but a user token will be treated as a valid service token, which is consistent with existing behavior. +- `auth.getOwnServiceCredentials()`: Use original implementation. +- `auth.isPrincipal()`: Use original implementation. +- `auth.getPluginRequestToken(options)`: Same behavior as the original implementation, using the `tokenManager` to issue service tokens, with the exception that a `none` principal will translate to an empty token rather than an error in order to properly forward calls with a no-op token manager. +- `httpAuth.credentials(...)`: Use original implementation. +- `httpAuth.issueUserCookie(...)`: This is a no-op as we do not need to support cookie auth in the legacy adapter. + +With this compatibility layer in place all plugins will be refactored to always use the new `AuthService` and `HttpAuthService` internally. The old deprecated services are only accepted at the public API boundaries, i.e. `createRouter` and similar. All plugin code beyond that point uses the new services. + +We do not roll out support for the new auth services for the old backend system, the full implementation is only supported in the new backend system. In particular this means that the new default protection in the `HttpRouterService` only apply to the new backend system. + +Users of the old backend system may already have their own protection set up, which we need to take into account, ensuring that we do not break these existing implementations. + +Several API clients will be updated to support passing `BackstageCredentials` instead of a token, although it is not a requirement to update all clients. In particular we will hold off on migrating isomorphic clients, leaving them to keep consuming tokens where possible. Adding support for credentials to be passed to these clients is a separate future improvement. ## Dependencies diff --git a/contrib/.devcontainer/Dockerfile b/contrib/.devcontainer/Dockerfile index 5c21c73acc..6407aa26dd 100644 --- a/contrib/.devcontainer/Dockerfile +++ b/contrib/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/typescript-node:20@sha256:381a1fde32704f229b439ade94816d5619f710e35698982ec35afcd9384ae6cf +FROM mcr.microsoft.com/devcontainers/typescript-node:20 RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install chromium \ diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index cc2b3d1c7b..054b727e78 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -1119,7 +1119,7 @@ Some common values for this field could be: - `database` - `s3-bucket` -- `cluster` +- `kubernetes-cluster` ### `spec.system` [optional] diff --git a/docs/plugins/new-backend-system.md b/docs/plugins/new-backend-system.md index 0fc44f283f..08ed7e73c7 100644 --- a/docs/plugins/new-backend-system.md +++ b/docs/plugins/new-backend-system.md @@ -26,7 +26,7 @@ const backend = createBackend(); backend.add(import('@backstage/plugin-catalog-backend')); // Start up the backend -await backend.start(); +backend.start(); ``` One notable change that helped achieve this much slimmer backend setup is the introduction of a system for dependency injection, which is very similar to the one in the Backstage frontend. diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 14292c36bf..6b522f9cf8 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -10392,15 +10392,15 @@ __metadata: linkType: hard "sass@npm:^1.57.1": - version: 1.70.0 - resolution: "sass@npm:1.70.0" + version: 1.71.0 + resolution: "sass@npm:1.71.0" dependencies: chokidar: ">=3.0.0 <4.0.0" immutable: ^4.0.0 source-map-js: ">=0.6.2 <2.0.0" bin: sass: sass.js - checksum: fd1b622cf9b7fa699a03ec634611997552ece45eb98ac365fef22f42bdcb8ed63b326b64173379c966830c8551ae801e44e4a00d2de16fdadda2dc8f35400bbb + checksum: 5ba6b4b994c7ae94286919d8be8a3692038c27175b4ad3a3ac43f51a91188590d3ddd3a0ef1022135503b9d70d0732efdbedfd56f3ee1a4651549f5b13f8942f languageName: node linkType: hard diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index a9e80a4672..f5ed8e4d85 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -47,7 +47,7 @@ "lodash": "^4.17.21", "minimist": "^1.2.5", "node-fetch": "^2.6.7", - "typescript-json-schema": "^0.62.0", + "typescript-json-schema": "^0.63.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/packages/integration/src/gitea/config.ts b/packages/integration/src/gitea/config.ts index 28070d570d..ae1fe5ee87 100644 --- a/packages/integration/src/gitea/config.ts +++ b/packages/integration/src/gitea/config.ts @@ -16,7 +16,7 @@ import { Config } from '@backstage/config'; import { trimEnd } from 'lodash'; -import { isValidHost } from '../helpers'; +import { isValidHost, isValidUrl } from '../helpers'; /** * The configuration for a single Gitea integration. @@ -62,6 +62,10 @@ export function readGiteaConfig(config: Config): GiteaIntegrationConfig { throw new Error( `Invalid Gitea integration config, '${host}' is not a valid host`, ); + } else if (baseUrl && !isValidUrl(baseUrl)) { + throw new Error( + `Invalid Gitea integration config, '${baseUrl}' is not a valid baseUrl`, + ); } if (baseUrl) { diff --git a/packages/integration/src/gitea/core.test.ts b/packages/integration/src/gitea/core.test.ts index fe6381d52e..ac29c469b6 100644 --- a/packages/integration/src/gitea/core.test.ts +++ b/packages/integration/src/gitea/core.test.ts @@ -30,6 +30,22 @@ describe('gitea core', () => { const worker = setupServer(); setupRequestMockHandlers(worker); + describe('getGiteaFileCatalogInfoCntentsUrl', () => { + it('can create an url from arguments', () => { + const config: GiteaIntegrationConfig = { + host: 'gitea.com', + }; + expect( + getGiteaFileContentsUrl( + config, + 'https://gitea.com/org1/repo1/src/branch/main/catalog-info.yaml', + ), + ).toEqual( + 'https://gitea.com/api/v1/repos/org1/repo1/contents/catalog-info.yaml?ref=main', + ); + }); + }); + describe('getGiteaFileContentsUrl', () => { it('can create an url from arguments', () => { const config: GiteaIntegrationConfig = { @@ -94,24 +110,10 @@ describe('gitea core', () => { }); }); - describe('getGerritRequestOptions', () => { - it('adds token header when only a password is specified', () => { - const authRequest: GiteaIntegrationConfig = { - host: 'gerrit.com', - password: 'P', - }; - const anonymousRequest: GiteaIntegrationConfig = { - host: 'gerrit.com', - }; - expect( - (getGiteaRequestOptions(authRequest).headers as any).Authorization, - ).toEqual('token P'); - expect(getGiteaRequestOptions(anonymousRequest).headers).toBeUndefined(); - }); - + describe('getGiteaRequestOptions', () => { it('adds basic auth when username and password are specified', () => { const authRequest: GiteaIntegrationConfig = { - host: 'gerrit.com', + host: 'gitea.com', username: 'username', password: 'P', }; diff --git a/packages/repo-tools/src/commands/util.ts b/packages/repo-tools/src/commands/util.ts index 933945bc5c..e28aae6267 100644 --- a/packages/repo-tools/src/commands/util.ts +++ b/packages/repo-tools/src/commands/util.ts @@ -13,29 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { execFile } from 'child_process'; +import os from 'os'; +import pLimit from 'p-limit'; + +// Some commands launch full node processes doing heavy work, which at high +// concurrency levels risk exhausting system resources. Placing the limiter here +// at the root level ensures that the concurrency boundary applies globally, not +// just per-runner. +const limiter = pLimit(os.cpus().length); export function createBinRunner(cwd: string, path: string) { return async (...command: string[]) => - new Promise((resolve, reject) => { - execFile( - 'node', - [path, ...command], - { - cwd, - shell: true, - timeout: 60000, - maxBuffer: 1024 * 1024, - }, - (err, stdout, stderr) => { - if (err) { - reject(new Error(`${err.message}\n${stderr}`)); - } else if (stderr) { - reject(new Error(`Command printed error output: ${stderr}`)); - } else { - resolve(stdout); - } - }, - ); - }); + limiter( + () => + new Promise((resolve, reject) => { + execFile( + 'node', + [path, ...command], + { + cwd, + shell: true, + timeout: 60000, + maxBuffer: 1024 * 1024, + }, + (err, stdout, stderr) => { + if (err) { + reject(new Error(`${err.message}\n${stderr}`)); + } else if (stderr) { + reject(new Error(`Command printed error output: ${stderr}`)); + } else { + resolve(stdout); + } + }, + ); + }), + ); } diff --git a/plugins/adr-backend/README.md b/plugins/adr-backend/README.md index ebf99b4ee1..73af5137ba 100644 --- a/plugins/adr-backend/README.md +++ b/plugins/adr-backend/README.md @@ -65,11 +65,9 @@ The ADR backend plugin has support for the [new backend system](https://backstag In your `packages/backend/src/index.ts` make the following changes: ```diff - -+ import { adrPlugin } from '@backstage/plugin-adr-backend'; const backend = createBackend(); -+ backend.add(adrPlugin()); ++ backend.add(import('@backstage/plugin-adr-backend')); // ... other feature additions diff --git a/plugins/airbrake/README.md b/plugins/airbrake/README.md index 603311f92c..2426a6eb8a 100644 --- a/plugins/airbrake/README.md +++ b/plugins/airbrake/README.md @@ -124,10 +124,13 @@ In your `packages/backend/src/index.ts` make the following changes: ```diff import { createBackend } from '@backstage/backend-defaults'; -+ import { airbrakePlugin } from '@backstage/plugin-airbrake-backend'; + const backend = createBackend(); + // ... other feature additions -+ backend.add(airbrakePlugin()); + ++ backend.add(import('@backstage/plugin-airbrake-backend')); + backend.start(); ``` diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md index f69951f70d..7c722dbe26 100644 --- a/plugins/azure-devops-backend/README.md +++ b/plugins/azure-devops-backend/README.md @@ -84,13 +84,12 @@ In your `packages/backend/src/index.ts` make the following changes: ```diff import { createBackend } from '@backstage/backend-defaults'; -+ import { azureDevOpsPlugin } from '@backstage/plugin-azure-devops-backend'; const backend = createBackend(); // ... other feature additions -+ backend.add(azureDevOpsPlugin()); ++ backend.add(import('@backstage/plugin-azure-devops-backend')); backend.start(); ``` diff --git a/plugins/badges-backend/README.md b/plugins/badges-backend/README.md index 1737482080..4e35b30c13 100644 --- a/plugins/badges-backend/README.md +++ b/plugins/badges-backend/README.md @@ -84,12 +84,12 @@ In your `packages/backend/src/index.ts` make the following changes: ```diff import { createBackend } from '@backstage/backend-defaults'; -+ import { badgesPlugin } from '@backstage/plugin-badges-backend'; + const backend = createBackend(); // ... other feature additions -+ backend.add(badgesPlugin()); ++ backend.add(import('@backstage/plugin-badges-backend')); backend.start(); ``` diff --git a/plugins/catalog-backend-module-unprocessed/api-report.md b/plugins/catalog-backend-module-unprocessed/api-report.md index 6e5e4f843b..569bd572da 100644 --- a/plugins/catalog-backend-module-unprocessed/api-report.md +++ b/plugins/catalog-backend-module-unprocessed/api-report.md @@ -13,7 +13,7 @@ export default catalogModuleUnprocessedEntities; // @public export class UnprocessedEntitiesModule { - constructor(database: Knex, router: HttpRouterService); + constructor(database: Knex, router: Pick); // (undocumented) registerRoutes(): void; } diff --git a/plugins/catalog-backend-module-unprocessed/src/UnprocessedEntitiesModule.ts b/plugins/catalog-backend-module-unprocessed/src/UnprocessedEntitiesModule.ts index bdd3f64488..a01f717e12 100644 --- a/plugins/catalog-backend-module-unprocessed/src/UnprocessedEntitiesModule.ts +++ b/plugins/catalog-backend-module-unprocessed/src/UnprocessedEntitiesModule.ts @@ -23,7 +23,6 @@ import { import { Knex } from 'knex'; import { HttpRouterService } from '@backstage/backend-plugin-api'; import Router from 'express-promise-router'; -import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; /** * Module providing Unprocessed Entities API endpoints @@ -35,7 +34,7 @@ export class UnprocessedEntitiesModule { constructor( private readonly database: Knex, - private readonly router: HttpRouterService, + private readonly router: Pick, ) { this.moduleRouter = Router(); this.router.use(this.moduleRouter); @@ -111,9 +110,6 @@ export class UnprocessedEntitiesModule { await this.unprocessed({ reason: 'failed', owner: req.query.owner as string, - authorizationToken: getBearerTokenFromAuthorizationHeader( - req.header('authorization'), - ), }), ); }) @@ -122,9 +118,6 @@ export class UnprocessedEntitiesModule { await this.unprocessed({ reason: 'pending', owner: req.query.owner as string, - authorizationToken: getBearerTokenFromAuthorizationHeader( - req.header('authorization'), - ), }), ); }); diff --git a/plugins/catalog-backend-module-unprocessed/src/types.ts b/plugins/catalog-backend-module-unprocessed/src/types.ts index 8d70345682..099412444b 100644 --- a/plugins/catalog-backend-module-unprocessed/src/types.ts +++ b/plugins/catalog-backend-module-unprocessed/src/types.ts @@ -60,7 +60,6 @@ export type RefreshStateError = { export interface UnprocessedEntitiesRequest { reason: 'failed' | 'pending'; owner?: string; - authorizationToken?: string; } export interface UnprocessedEntitiesResponse { diff --git a/plugins/devtools-backend/README.md b/plugins/devtools-backend/README.md index c9226a92ab..4439c8cd9f 100644 --- a/plugins/devtools-backend/README.md +++ b/plugins/devtools-backend/README.md @@ -57,13 +57,12 @@ In your `packages/backend/src/index.ts` make the following changes: ```diff import { createBackend } from '@backstage/backend-defaults'; -+ import { devtoolsPlugin } from '@backstage/plugin-devtools-backend'; const backend = createBackend(); // ... other feature additions -+ backend.add(devtoolsPlugin()); ++ backend.add(import('@backstage/plugin-devtools-backend')); backend.start(); ``` diff --git a/plugins/entity-feedback-backend/README.md b/plugins/entity-feedback-backend/README.md index a3aae695e2..cef580a580 100644 --- a/plugins/entity-feedback-backend/README.md +++ b/plugins/entity-feedback-backend/README.md @@ -59,11 +59,13 @@ The Entity Feedback backend plugin has support for the [new backend system](http In your `packages/backend/src/index.ts` make the following changes: ```diff -+ import { entityFeedbackPlugin } from '@backstage/plugin-entity-feedback-backend'; + import { createBackend } from '@backstage/backend-defaults'; -const backend = createBackend(); -+ backend.add(entityFeedbackPlugin()); -// ... other feature additions + const backend = createBackend(); + + // ... other feature additions + ++ backend.add(import(@backstage/plugin-entity-feedback-backend)); backend.start(); ``` diff --git a/plugins/lighthouse-backend/README.md b/plugins/lighthouse-backend/README.md index 06455d90b4..df6c2415d9 100644 --- a/plugins/lighthouse-backend/README.md +++ b/plugins/lighthouse-backend/README.md @@ -72,10 +72,13 @@ In your `packages/backend/src/index.ts` make the following changes: ```diff import { createBackend } from '@backstage/backend-defaults'; -+ import { lighthousePlugin } from '@backstage/plugin-lighthouse-backend'; + const backend = createBackend(); + // ... other feature additions -+ backend.add(lighthousePlugin()); + ++ backend.add(import('@backstage/plugin-lighthouse-backend')); + backend.start(); ``` diff --git a/plugins/linguist-backend/README.md b/plugins/linguist-backend/README.md index 3bc441c238..8939bbe303 100644 --- a/plugins/linguist-backend/README.md +++ b/plugins/linguist-backend/README.md @@ -64,13 +64,12 @@ In your `packages/backend/src/index.ts` make the following changes: ```diff import { createBackend } from '@backstage/backend-defaults'; -+ import { linguistPlugin } from '@backstage/plugin-linguist-backend'; const backend = createBackend(); // ... other feature additions -+ backend.add(linguistPlugin()); ++ backend.add(import('@backstage/plugin-linguist-backend')); backend.start(); ``` diff --git a/plugins/notifications-backend/src/service/router.ts b/plugins/notifications-backend/src/service/router.ts index b293ea4a1f..6c745e158e 100644 --- a/plugins/notifications-backend/src/service/router.ts +++ b/plugins/notifications-backend/src/service/router.ts @@ -42,7 +42,9 @@ import { AuthenticationError, InputError } from '@backstage/errors'; import { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api'; import { SignalService } from '@backstage/plugin-signals-node'; import { + NewNotificationSignal, Notification, + NotificationReadSignal, NotificationType, } from '@backstage/plugin-notifications-common'; @@ -206,6 +208,21 @@ export async function createRouter( res.send(notifications); }); + router.get('/:id', async (req, res) => { + const user = await getUser(req); + const opts: NotificationGetOptions = { + user: user, + limit: 1, + ids: [req.params.id], + }; + const notifications = await store.getNotifications(opts); + if (notifications.length !== 1) { + res.status(404).send({ error: 'Not found' }); + return; + } + res.send(notifications[0]); + }); + router.get('/status', async (req, res) => { const user = await getUser(req); const status = await store.getStatus({ user, type: 'undone' }); @@ -214,38 +231,18 @@ export async function createRouter( router.post('/update', async (req, res) => { const user = await getUser(req); - const { ids, done, read, saved } = req.body; + const { ids, read, saved } = req.body; if (!ids || !Array.isArray(ids)) { throw new InputError(); } - if (done === true) { - await store.markDone({ user, ids }); - if (signalService) { - await signalService.publish({ - recipients: [user], - message: { action: 'done', notification_ids: ids }, - channel: 'notifications', - }); - } - } else if (done === false) { - await store.markUndone({ user, ids }); - if (signalService) { - await signalService.publish({ - recipients: [user], - message: { action: 'undone', notification_ids: ids }, - channel: 'notifications', - }); - } - } - if (read === true) { await store.markRead({ user, ids }); if (signalService) { - await signalService.publish({ + await signalService.publish({ recipients: [user], - message: { action: 'mark_read', notification_ids: ids }, + message: { action: 'notification_read', notification_ids: ids }, channel: 'notifications', }); } @@ -253,9 +250,9 @@ export async function createRouter( await store.markUnread({ user: user, ids }); if (signalService) { - await signalService.publish({ + await signalService.publish({ recipients: [user], - message: { action: 'mark_unread', notification_ids: ids }, + message: { action: 'notification_unread', notification_ids: ids }, channel: 'notifications', }); } @@ -285,7 +282,7 @@ export async function createRouter( throw new AuthenticationError(); } - const { title, link, description, scope } = payload; + const { title, link, scope } = payload; if (!recipients || !title || !origin || !link) { logger.error(`Invalid notification request received`); @@ -344,17 +341,17 @@ export async function createRouter( processorSendNotification(ret); notifications.push(ret); - } - if (signalService) { - await signalService.publish({ - recipients: entityRef === null ? null : uniqueUsers, - message: { - action: 'new_notification', - notification: { title, description, link }, - }, - channel: 'notifications', - }); + if (signalService) { + await signalService.publish({ + recipients: user, + message: { + action: 'new_notification', + notification_id: ret.id, + }, + channel: 'notifications', + }); + } } res.json(notifications); diff --git a/plugins/notifications-common/api-report.md b/plugins/notifications-common/api-report.md index d2dc1afb9d..6f40c76e58 100644 --- a/plugins/notifications-common/api-report.md +++ b/plugins/notifications-common/api-report.md @@ -3,6 +3,12 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +// @public (undocumented) +export type NewNotificationSignal = { + action: 'new_notification'; + notification_id: string; +}; + // @public (undocumented) type Notification_2 = { id: string; @@ -28,9 +34,18 @@ export type NotificationPayload = { icon?: string; }; +// @public (undocumented) +export type NotificationReadSignal = { + action: 'notification_read' | 'notification_unread'; + notification_ids: string[]; +}; + // @public (undocumented) export type NotificationSeverity = 'critical' | 'high' | 'normal' | 'low'; +// @public (undocumented) +export type NotificationSignal = NewNotificationSignal | NotificationReadSignal; + // @public (undocumented) export type NotificationStatus = { unread: number; diff --git a/plugins/notifications-common/src/types.ts b/plugins/notifications-common/src/types.ts index 1e7469244f..4d71004265 100644 --- a/plugins/notifications-common/src/types.ts +++ b/plugins/notifications-common/src/types.ts @@ -51,3 +51,18 @@ export type NotificationStatus = { unread: number; read: number; }; + +/** @public */ +export type NewNotificationSignal = { + action: 'new_notification'; + notification_id: string; +}; + +/** @public */ +export type NotificationReadSignal = { + action: 'notification_read' | 'notification_unread'; + notification_ids: string[]; +}; + +/** @public */ +export type NotificationSignal = NewNotificationSignal | NotificationReadSignal; diff --git a/plugins/notifications/api-report.md b/plugins/notifications/api-report.md index e2071dad14..0f5d7a0049 100644 --- a/plugins/notifications/api-report.md +++ b/plugins/notifications/api-report.md @@ -26,6 +26,8 @@ export type GetNotificationsOptions = { // @public (undocumented) export interface NotificationsApi { + // (undocumented) + getNotification(id: string): Promise; // (undocumented) getNotifications( options?: GetNotificationsOptions, @@ -45,6 +47,8 @@ export const notificationsApiRef: ApiRef; export class NotificationsClient implements NotificationsApi { constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }); // (undocumented) + getNotification(id: string): Promise; + // (undocumented) getNotifications( options?: GetNotificationsOptions, ): Promise; @@ -128,6 +132,7 @@ export function useWebNotifications(): { sendWebNotification: (options: { title: string; description: string; + link?: string; }) => Notification | null; }; diff --git a/plugins/notifications/src/api/NotificationsApi.ts b/plugins/notifications/src/api/NotificationsApi.ts index 775dc6b244..266c8a1ee5 100644 --- a/plugins/notifications/src/api/NotificationsApi.ts +++ b/plugins/notifications/src/api/NotificationsApi.ts @@ -45,6 +45,8 @@ export type UpdateNotificationsOptions = { export interface NotificationsApi { getNotifications(options?: GetNotificationsOptions): Promise; + getNotification(id: string): Promise; + getStatus(): Promise; updateNotifications( diff --git a/plugins/notifications/src/api/NotificationsClient.test.ts b/plugins/notifications/src/api/NotificationsClient.test.ts index a7a2d1e5a7..1312b99cf4 100644 --- a/plugins/notifications/src/api/NotificationsClient.test.ts +++ b/plugins/notifications/src/api/NotificationsClient.test.ts @@ -74,6 +74,20 @@ describe('NotificationsClient', () => { expect(response).toEqual(expectedResp); }); + it('should fetch single notification', async () => { + server.use( + rest.get(`${mockBaseUrl}/:id`, (req, res, ctx) => { + expect(req.params.id).toBe('acdaa8ca-262b-43c1-b74b-de06e5f3b3c7'); + return res(ctx.json(testNotification)); + }), + ); + + const response = await client.getNotification( + 'acdaa8ca-262b-43c1-b74b-de06e5f3b3c7', + ); + expect(response).toEqual(testNotification); + }); + it('should fetch status from correct endpoint', async () => { server.use( rest.get(`${mockBaseUrl}/status`, (_, res, ctx) => diff --git a/plugins/notifications/src/api/NotificationsClient.ts b/plugins/notifications/src/api/NotificationsClient.ts index fe7a90d3e8..9ef7b287ab 100644 --- a/plugins/notifications/src/api/NotificationsClient.ts +++ b/plugins/notifications/src/api/NotificationsClient.ts @@ -60,6 +60,10 @@ export class NotificationsClient implements NotificationsApi { return await this.request(urlSegment); } + async getNotification(id: string): Promise { + return await this.request(`${id}`); + } + async getStatus(): Promise { return await this.request('status'); } diff --git a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx index 90fba009a3..2163c6660f 100644 --- a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx +++ b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx @@ -17,12 +17,13 @@ import React, { useEffect } from 'react'; import { useNotificationsApi } from '../../hooks'; import { SidebarItem } from '@backstage/core-components'; import NotificationsIcon from '@material-ui/icons/Notifications'; -import { useRouteRef } from '@backstage/core-plugin-api'; +import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { rootRouteRef } from '../../routes'; import { useSignal } from '@backstage/plugin-signals-react'; +import { NotificationSignal } from '@backstage/plugin-notifications-common'; import { useWebNotifications } from '../../hooks/useWebNotifications'; import { useTitleCounter } from '../../hooks/useTitleCounter'; -import { JsonObject } from '@backstage/types'; +import { notificationsApiRef } from '../../api'; /** @public */ export const NotificationsSidebarItem = (props?: { @@ -35,11 +36,11 @@ export const NotificationsSidebarItem = (props?: { const { loading, error, value, retry } = useNotificationsApi(api => api.getStatus(), ); + const notificationsApi = useApi(notificationsApiRef); const [unreadCount, setUnreadCount] = React.useState(0); const notificationsRoute = useRouteRef(rootRouteRef); - // TODO: Add signal type support to `useSignal` to make it a bit easier to use // TODO: Do we want to add long polling in case signals are not available - const { lastSignal } = useSignal('notifications'); + const { lastSignal } = useSignal('notifications'); const { sendWebNotification } = useWebNotifications(); const [refresh, setRefresh] = React.useState(false); const { setNotificationCount } = useTitleCounter(); @@ -52,39 +53,35 @@ export const NotificationsSidebarItem = (props?: { }, [refresh, retry]); useEffect(() => { - const handleWebNotification = (signal: JsonObject) => { - if (!webNotificationsEnabled || !('notification' in signal)) { + const handleWebNotification = (signal: NotificationSignal) => { + if (!webNotificationsEnabled || signal.action !== 'new_notification') { return; } - const notificationData = signal.notification as JsonObject; - - if ( - !notificationData || - !('title' in notificationData) || - !('description' in notificationData) || - !('title' in notificationData) - ) { - return; - } - const notification = sendWebNotification({ - title: notificationData.title as string, - description: notificationData.description as string, - }); - if (notification) { - notification.onclick = event => { - event.preventDefault(); - notification.close(); - window.open(notificationData.link as string, '_blank'); - }; - } + notificationsApi + .getNotification(signal.notification_id) + .then(notification => { + if (!notification) { + return; + } + sendWebNotification({ + title: notification.payload.title, + description: notification.payload.description ?? '', + link: notification.payload.link, + }); + }); }; if (lastSignal && lastSignal.action) { handleWebNotification(lastSignal); setRefresh(true); } - }, [lastSignal, sendWebNotification, webNotificationsEnabled]); + }, [ + lastSignal, + sendWebNotification, + webNotificationsEnabled, + notificationsApi, + ]); useEffect(() => { if (!loading && !error && value) { diff --git a/plugins/notifications/src/hooks/useWebNotifications.ts b/plugins/notifications/src/hooks/useWebNotifications.ts index 7e34172a97..bf3b5269f5 100644 --- a/plugins/notifications/src/hooks/useWebNotifications.ts +++ b/plugins/notifications/src/hooks/useWebNotifications.ts @@ -37,7 +37,7 @@ export function useWebNotifications() { }); const sendWebNotification = useCallback( - (options: { title: string; description: string }) => { + (options: { title: string; description: string; link?: string }) => { if (webNotificationPermission !== 'granted') { return null; } @@ -45,6 +45,15 @@ export function useWebNotifications() { const notification = new Notification(options.title, { body: options.description, }); + + notification.onclick = event => { + event.preventDefault(); + notification.close(); + if (options.link) { + window.open(options.link, '_blank'); + } + }; + return notification; }, [webNotificationPermission], diff --git a/plugins/scaffolder-backend-module-gitea/.eslintrc.js b/plugins/scaffolder-backend-module-gitea/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-gitea/README.md b/plugins/scaffolder-backend-module-gitea/README.md new file mode 100644 index 0000000000..f13602f2d8 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/README.md @@ -0,0 +1,110 @@ +# scaffolder-backend-module-gitea + +Welcome to the `publish:gitea` action of the `scaffolder-gitea-backend`. + +## Getting started + +To use this action, you will have to add the package using the following command to be executed at the root of your backstage project: + +```bash +yarn add --cwd packages/backend +@backstage/plugin-scaffolder-backend-module-gitea +``` + +Configure the action (if not yet done): +(you can check the [docs](https://backstage.io/docs/features/software-templates/writing-custom-actions#registering-custom-actions) to see all options): + +Before to create a template, include to your `app-config.yaml` file the +gitea host and credentials under the `integrations:` section + +```yaml +integrations: + gitea: + - host: gitea.com + username: '' + password: '' + - host: localhost:3333 + username: '' + password: '' +``` + +**NOTE**: As backstage will issue HTTPS/TLS requests to the gitea instance, it is needed to configure `gitea` with a valid certificate or at least with a +self-signed certificate `gitea cert --host localhost -ca`. Don't forget to set the env var `NODE_EXTRA_CA_CERTS` to point to the CA file before launching backstage ! + +When done, you can create a template which: + +- Declare the `RepoUrlPicker` within the `spec/parameters` section to select the gitea hosts +- Include a step able to publish by example the newly generated project using the action `action: publish:gitea` + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: quarkus-web-template + title: Quarkus Hello world + description: Create a simple microservice using Quarkus + tags: + - java + - quarkus +spec: + owner: quarkus + type: service + parameters: + - title: Git repository Information + required: + - repoUrl + properties: + repoUrl: + title: Repository Location + type: string + ui:field: RepoUrlPicker + ui:options: + allowedHosts: + - gitea.: + - localhost: + + steps: + - id: template + name: Generating component + action: fetch:template + input: + url: ./skeleton + copyWithoutTemplating: + - .github/workflows/* + values: + component_id: ${{ parameters.component_id }} + namespace: ${{ parameters.component_id }}-dev + description: ${{ parameters.description }} + group_id: ${{ parameters.group_id }} + artifact_id: ${{ parameters.artifact_id }} + java_package_name: ${{ parameters.java_package_name }} + owner: ${{ parameters.owner }} + destination: ${{ (parameters.repoUrl | parseRepoUrl).owner }}/${{ (parameters.repoUrl | parseRepoUrl).repo } + port: 8080 + + - id: publish + name: Publishing to a gitea git repository + action: publish:gitea + input: + description: This is ${{ parameters.component_id }} + repoUrl: ${{ parameters.repoUrl }} + defaultBranch: main + + - id: register + if: ${{ parameters.dryRun !== true }} + name: Register + action: catalog:register + input: + repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }} + catalogInfoPath: 'main/catalog-info.yaml' + + output: + links: + - title: Source Code Repository + url: ${{ steps.publish.output.remoteUrl }} + - title: Open Component in catalog + icon: catalog + entityRef: ${{ steps.register.output.entityRef }} +``` + +Access the newly gitea repository created using the `repoContentsUrl` ;-) diff --git a/plugins/scaffolder-backend-module-gitea/api-report.md b/plugins/scaffolder-backend-module-gitea/api-report.md new file mode 100644 index 0000000000..373cc6258c --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/api-report.md @@ -0,0 +1,32 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-gitea" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; + +// @public +export function createPublishGiteaAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + description: string; + defaultBranch?: string | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + sourcePath?: string | undefined; + }, + JsonObject +>; + +// @public +const giteaModule: () => BackendFeature; +export default giteaModule; +``` diff --git a/plugins/scaffolder-backend-module-gitea/catalog-info.yaml b/plugins/scaffolder-backend-module-gitea/catalog-info.yaml new file mode 100644 index 0000000000..adfcc754fb --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-scaffolder-backend-module-gitea + title: '@backstage/plugin-scaffolder-backend-module-gitea' +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json new file mode 100644 index 0000000000..17f30b226b --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -0,0 +1,57 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-gitea", + "description": "The gitea module for @backstage/plugin-scaffolder-backend", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/scaffolder-backend-module-gitea" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "exports": { + ".": "./src/index.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "package.json": [ + "package.json" + ] + } + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", + "node-fetch": "^2.6.7", + "yaml": "^2.0.0" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts new file mode 100644 index 0000000000..748a869205 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts @@ -0,0 +1,158 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: + 'Initializes a Gitea repository using the content of the workspace and publish it to Gitea with default configuration.', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + }, + }, + ], + }), + }, + { + description: 'Initializes a Gitea repository with a description.', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + description: 'Initialize a gitea repository', + }, + }, + ], + }), + }, + { + description: + 'Initializes a Gitea repository with a default Branch, if not set defaults to main', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + defaultBranch: 'main', + }, + }, + ], + }), + }, + { + description: + 'Initializes a Gitea repository with an initial commit message, if not set defaults to initial commit', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + gitCommitMessage: 'Initial Commit Message', + }, + }, + ], + }), + }, + { + description: + 'Initializes a Gitea repository with a repo Author Name, if not set defaults to Scaffolder', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + gitAuthorName: 'John Doe', + }, + }, + ], + }), + }, + { + description: 'Initializes a Gitea repository with a repo Author Email', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + gitAuthorEmail: 'johndoe@email.com', + }, + }, + ], + }), + }, + { + description: + 'Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + sourcePath: 'repository/', + }, + }, + ], + }), + }, + { + description: 'Initializes a Gitea repository with all properties being set', + example: yaml.stringify({ + steps: [ + { + id: 'publish', + action: 'publish:gitea', + name: 'Publish to Gitea', + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + description: 'Initialize a gitea repository', + defaultBranch: 'staging', + gitCommitMessage: 'Initial Commit Message', + gitAuthorName: 'John Doe', + gitAuthorEmail: 'johndoe@email.com', + sourcePath: 'repository/', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts new file mode 100644 index 0000000000..5e1e94b1b4 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts @@ -0,0 +1,160 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { PassThrough } from 'stream'; +import { ScmIntegrations } from '@backstage/integration'; +import { ConfigReader } from '@backstage/config'; +import { getVoidLogger } from '@backstage/backend-common'; +import { createPublishGiteaAction } from './gitea'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; +import { rest } from 'msw'; +import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { setupServer } from 'msw/node'; + +jest.mock('@backstage/plugin-scaffolder-node', () => { + return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + initRepoAndPush: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + }; +}); + +describe('publish:gitea', () => { + const config = new ConfigReader({ + integrations: { + gitea: [ + { + host: 'gitea.com', + username: 'gitea_user', + password: 'gitea_password', + }, + ], + }, + }); + + const description = 'for the lols'; + const integrations = ScmIntegrations.fromConfig(config); + const action = createPublishGiteaAction({ integrations, config }); + const mockContext = { + input: { + repoUrl: 'gitea.com?repo=repo&owner=owner', + description, + }, + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + const server = setupServer(); + setupRequestMockHandlers(server); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should throw an error when the repoUrl is not well formed', async () => { + await expect( + action.handler({ + ...mockContext, + input: { repoUrl: 'gitea.com?owner=o', description }, + }), + ).rejects.toThrow(/missing repo/); + }); + + it('should throw if there is no integration config provided for missing.com host', async () => { + await expect( + action.handler({ + ...mockContext, + input: { repoUrl: 'missing.com?repo=repo', description }, + }), + ).rejects.toThrow(/No matching integration configuration/); + }); + + it('should throw if there is no repositoryId returned', async () => { + server.use( + rest.get('https://gitea.com/api/v1/orgs/org1', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + id: 1, + name: 'org1', + visibility: 'public', + repo_admin_change_team_access: false, + username: 'org1', + }), + ); + }), + rest.get( + 'https://gitea.com/org1/repo/src/branch/main', + (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }, + ), + rest.post('https://gitea.com/api/v1/orgs/org1/repos', (req, res, ctx) => { + // Basic auth must match the user and password defined part of the config + expect(req.headers.get('Authorization')).toBe( + 'basic Z2l0ZWFfdXNlcjpnaXRlYV9wYXNzd29yZA==', + ); + expect(req.body).toEqual({ + name: 'repo', + description, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json({}), + ); + }), + ); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + repoUrl: 'gitea.com?repo=repo&owner=org1', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://gitea.com/org1/repo.git', + defaultBranch: 'main', + auth: { username: 'gitea_user', password: 'gitea_password' }, + logger: mockContext.logger, + commitMessage: expect.stringContaining('initial commit\n\nChange-Id:'), + gitAuthorInfo: { + email: undefined, + name: undefined, + }, + }); + + expect(mockContext.output).toHaveBeenCalledWith( + 'repoContentsUrl', + 'https://gitea.com/org1/repo/src/branch/main/', + ); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts new file mode 100644 index 0000000000..e7f62f51da --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts @@ -0,0 +1,346 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import { Config } from '@backstage/config'; +import { + getGiteaRequestOptions, + GiteaIntegrationConfig, + ScmIntegrationRegistry, +} from '@backstage/integration'; +import { + ActionContext, + createTemplateAction, + getRepoSourceDirectory, + initRepoAndPush, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; +import { examples } from './gitea.examples'; +import crypto from 'crypto'; + +const checkGiteaContentUrl = async ( + config: GiteaIntegrationConfig, + options: { + owner?: string; + repo: string; + defaultBranch?: string; + }, +): Promise => { + const { owner, repo, defaultBranch } = options; + let response: Response; + const getOptions: RequestInit = { + method: 'GET', + }; + + try { + response = await fetch( + `${config.baseUrl}/${owner}/${repo}/src/branch/${defaultBranch}`, + getOptions, + ); + } catch (e) { + throw new Error( + `Unable to get the repository: ${owner}/${repo} metadata , ${e}`, + ); + } + return response; +}; + +const checkGiteaOrg = async ( + config: GiteaIntegrationConfig, + options: { + owner: string; + }, +): Promise => { + const { owner } = options; + let response: Response; + // check first if the org = owner exists + const getOptions: RequestInit = { + method: 'GET', + headers: { + ...getGiteaRequestOptions(config).headers, + 'Content-Type': 'application/json', + }, + }; + try { + response = await fetch( + `${config.baseUrl}/api/v1/orgs/${owner}`, + getOptions, + ); + } catch (e) { + throw new Error(`Unable to get the Organization: ${owner}, ${e}`); + } + if (response.status !== 200) { + throw new Error( + `Organization ${owner} do not exist. Please create it first !`, + ); + } +}; + +const createGiteaProject = async ( + config: GiteaIntegrationConfig, + options: { + projectName: string; + owner?: string; + description: string; + }, +): Promise => { + const { projectName, description, owner } = options; + + /* + Several options exist to create a repository using either the user or organisation + User: https://gitea.com/api/swagger#/user/createCurrentUserRepo + Api: URL/api/v1/user/repos + Remark: The user is the username defined part of the backstage integration config for the gitea URL ! + + Org: https://gitea.com/api/swagger#/organization/createOrgRepo + Api: URL/api/v1/orgs/${org_owner}/repos + This is the default scenario that we support currently + */ + let response: Response; + + const postOptions: RequestInit = { + method: 'POST', + body: JSON.stringify({ + name: projectName, + description, + }), + headers: { + ...getGiteaRequestOptions(config).headers, + 'Content-Type': 'application/json', + }, + }; + try { + response = await fetch( + `${config.baseUrl}/api/v1/orgs/${owner}/repos`, + postOptions, + ); + } catch (e) { + throw new Error(`Unable to create repository, ${e}`); + } + if (response.status !== 201) { + throw new Error( + `Unable to create repository, ${response.status} ${ + response.statusText + }, ${await response.text()}`, + ); + } +}; + +const generateCommitMessage = ( + config: Config, + commitSubject?: string, +): string => { + const changeId = crypto.randomBytes(20).toString('hex'); + const msg = `${ + config.getOptionalString('scaffolder.defaultCommitMessage') || commitSubject + }\n\nChange-Id: I${changeId}`; + return msg; +}; + +async function checkAvailabilityGiteaRepository( + maxDuration: number, + integrationConfig: GiteaIntegrationConfig, + options: { + owner?: string; + repo: string; + defaultBranch: string; + ctx: ActionContext; + }, +) { + const startTimestamp = Date.now(); + + const { owner, repo, defaultBranch, ctx } = options; + const sleep = (ms: number | undefined) => new Promise(r => setTimeout(r, ms)); + let response: Response; + + while (Date.now() - startTimestamp < maxDuration) { + if (ctx.signal?.aborted) return; + + response = await checkGiteaContentUrl(integrationConfig, { + owner, + repo, + defaultBranch, + }); + + if (response.status !== 200) { + // Repository is not yet available/accessible ... + await sleep(1000); + } + } +} + +/** + * Creates a new action that initializes a git repository using the content of the workspace. + * and publishes it to a Gitea instance. + * @public + */ +export function createPublishGiteaAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}) { + const { integrations, config } = options; + + return createTemplateAction<{ + repoUrl: string; + description: string; + defaultBranch?: string; + gitCommitMessage?: string; + gitAuthorName?: string; + gitAuthorEmail?: string; + sourcePath?: string; + }>({ + id: 'publish:gitea', + description: + 'Initializes a git repository using the content of the workspace, and publishes it to Gitea.', + examples, + schema: { + input: { + type: 'object', + required: ['repoUrl'], + properties: { + repoUrl: { + title: 'Repository Location', + type: 'string', + }, + description: { + title: 'Repository Description', + type: 'string', + }, + defaultBranch: { + title: 'Default Branch', + type: 'string', + description: `Sets the default branch on the repository. The default value is 'main'`, + }, + gitCommitMessage: { + title: 'Git Commit Message', + type: 'string', + description: `Sets the commit message on the repository. The default value is 'initial commit'`, + }, + gitAuthorName: { + title: 'Default Author Name', + type: 'string', + description: `Sets the default author name for the commit. The default value is 'Scaffolder'`, + }, + gitAuthorEmail: { + title: 'Default Author Email', + type: 'string', + description: `Sets the default author email for the commit.`, + }, + sourcePath: { + title: 'Source Path', + type: 'string', + description: `Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.`, + }, + }, + }, + output: { + type: 'object', + properties: { + remoteUrl: { + title: 'A URL to the repository with the provider', + type: 'string', + }, + repoContentsUrl: { + title: 'A URL to the root of the repository', + type: 'string', + }, + commitHash: { + title: 'The git commit hash of the initial commit', + type: 'string', + }, + }, + }, + }, + async handler(ctx) { + const { + repoUrl, + description, + defaultBranch = 'main', + gitAuthorName, + gitAuthorEmail, + gitCommitMessage = 'initial commit', + sourcePath, + } = ctx.input; + + const { repo, host, owner } = parseRepoUrl(repoUrl, integrations); + + const integrationConfig = integrations.gitea.byHost(host); + if (!integrationConfig) { + throw new InputError( + `No matching integration configuration for host ${host}, please check your integrations config`, + ); + } + const { username, password } = integrationConfig.config; + + if (!username || !password) { + throw new Error('Credentials for the gitea ${host} required.'); + } + + // check if the org exists within the gitea server + if (owner) { + await checkGiteaOrg(integrationConfig.config, { owner }); + } + + await createGiteaProject(integrationConfig.config, { + description, + owner: owner, + projectName: repo, + }); + + const auth = { + username: username, + password: password, + }; + const gitAuthorInfo = { + name: gitAuthorName + ? gitAuthorName + : config.getOptionalString('scaffolder.defaultAuthor.name'), + email: gitAuthorEmail + ? gitAuthorEmail + : config.getOptionalString('scaffolder.defaultAuthor.email'), + }; + // The owner to be used should be either the org name or user authenticated with the gitea server + const remoteUrl = `${integrationConfig.config.baseUrl}/${owner}/${repo}.git`; + const commitResult = await initRepoAndPush({ + dir: getRepoSourceDirectory(ctx.workspacePath, sourcePath), + remoteUrl, + auth, + defaultBranch, + logger: ctx.logger, + commitMessage: generateCommitMessage(config, gitCommitMessage), + gitAuthorInfo, + }); + + // Check if the gitea repo URL is available before to exit + const maxDuration = 20000; // 20 seconds + await checkAvailabilityGiteaRepository( + maxDuration, + integrationConfig.config, + { + owner, + repo, + defaultBranch, + ctx, + }, + ); + + const repoContentsUrl = `${integrationConfig.config.baseUrl}/${owner}/${repo}/src/branch/${defaultBranch}/`; + ctx.output('remoteUrl', remoteUrl); + ctx.output('commitHash', commitResult?.commitHash); + ctx.output('repoContentsUrl', repoContentsUrl); + }, + }); +} diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/index.ts b/plugins/scaffolder-backend-module-gitea/src/actions/index.ts new file mode 100644 index 0000000000..ccf7f23fab --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/src/actions/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './gitea'; diff --git a/plugins/scaffolder-backend-module-gitea/src/index.ts b/plugins/scaffolder-backend-module-gitea/src/index.ts new file mode 100644 index 0000000000..0b68069178 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/src/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A module for the scaffolder backend that lets you interact with gitea + * + * @packageDocumentation + */ + +export * from './actions'; +export { giteaModule as default } from './module'; diff --git a/plugins/scaffolder-backend-module-gitea/src/module.ts b/plugins/scaffolder-backend-module-gitea/src/module.ts new file mode 100644 index 0000000000..658f240471 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitea/src/module.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + createBackendModule, + coreServices, +} from '@backstage/backend-plugin-api'; +import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; +import { createPublishGiteaAction } from './actions'; +import { ScmIntegrations } from '@backstage/integration'; + +/** + * @public + * The Gitea Module for the Scaffolder Backend + */ +export const giteaModule = createBackendModule({ + pluginId: 'scaffolder', + moduleId: 'gitea', + register({ registerInit }) { + registerInit({ + deps: { + scaffolder: scaffolderActionsExtensionPoint, + config: coreServices.rootConfig, + }, + async init({ scaffolder, config }) { + const integrations = ScmIntegrations.fromConfig(config); + scaffolder.addActions( + createPublishGiteaAction({ + integrations, + config, + }), + ); + }, + }); + }, +}); diff --git a/plugins/scaffolder-backend-module-github/api-report.md b/plugins/scaffolder-backend-module-github/api-report.md index a588840585..de03894a5a 100644 --- a/plugins/scaffolder-backend-module-github/api-report.md +++ b/plugins/scaffolder-backend-module-github/api-report.md @@ -205,6 +205,12 @@ export function createGithubRepoCreateAction(options: { [key: string]: string; } | undefined; + oidcCustomization?: + | { + useDefault: boolean; + includeClaimKeys?: string[] | undefined; + } + | undefined; requireCommitSigning?: boolean | undefined; }, JsonObject @@ -352,6 +358,12 @@ export function createPublishGithubAction(options: { [key: string]: string; } | undefined; + oidcCustomization?: + | { + useDefault: boolean; + includeClaimKeys?: string[] | undefined; + } + | undefined; requiredCommitSigning?: boolean | undefined; }, JsonObject diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts index a2a8e11e15..75d9b74a8b 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts @@ -77,6 +77,7 @@ const mockOctokit = { getRepoPublicKey: jest.fn(), }, }, + request: jest.fn(), }; jest.mock('octokit', () => ({ Octokit: class { @@ -930,6 +931,40 @@ describe('publish:github', () => { }); }); + it('should configure oidc customizations when provided', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + oidcCustomization: { + useDefault: false, + includeClaimKeys: ['foo', 'bar'], + }, + }, + }); + + expect(mockOctokit.request).toHaveBeenCalledWith( + 'PUT /repos/{owner}/{repo}/actions/oidc/customization/sub', + { + include_claim_keys: ['foo', 'bar'], + owner: 'owner', + repo: 'repo', + use_default: false, + }, + ); + }); + it('should call output with the remoteUrl and the repoContentsUrl', async () => { mockOctokit.rest.users.getByUsername.mockResolvedValue({ data: { type: 'User' }, diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.ts b/plugins/scaffolder-backend-module-github/src/actions/github.ts index 91d7a34aea..f32b65bc9a 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.ts @@ -109,6 +109,10 @@ export function createPublishGithubAction(options: { topics?: string[]; repoVariables?: { [key: string]: string }; secrets?: { [key: string]: string }; + oidcCustomization?: { + useDefault: boolean; + includeClaimKeys?: string[]; + }; requiredCommitSigning?: boolean; }>({ id: 'publish:github', @@ -156,6 +160,7 @@ export function createPublishGithubAction(options: { topics: inputProps.topics, repoVariables: inputProps.repoVariables, secrets: inputProps.secrets, + oidcCustomization: inputProps.oidcCustomization, requiredCommitSigning: inputProps.requiredCommitSigning, }, }, @@ -203,6 +208,7 @@ export function createPublishGithubAction(options: { topics, repoVariables, secrets, + oidcCustomization, token: providedToken, requiredCommitSigning = false, } = ctx.input; @@ -243,6 +249,7 @@ export function createPublishGithubAction(options: { topics, repoVariables, secrets, + oidcCustomization, ctx.logger, ); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts index 4cb007275e..c72a969e96 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts @@ -58,6 +58,7 @@ const mockOctokit = { getRepoPublicKey: jest.fn(), }, }, + request: jest.fn(), }; jest.mock('octokit', () => ({ Octokit: class { @@ -652,6 +653,40 @@ describe('github:repo:create', () => { }); }); + it('should configure oidc customizations when provided', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + oidcCustomization: { + useDefault: false, + includeClaimKeys: ['foo', 'bar'], + }, + }, + }); + + expect(mockOctokit.request).toHaveBeenCalledWith( + 'PUT /repos/{owner}/{repo}/actions/oidc/customization/sub', + { + include_claim_keys: ['foo', 'bar'], + owner: 'owner', + repo: 'repo', + use_default: false, + }, + ); + }); + it('should call output with the remoteUrl', async () => { mockOctokit.rest.users.getByUsername.mockResolvedValue({ data: { type: 'User' }, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts index 735919794f..52bf9be9c0 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts @@ -95,6 +95,10 @@ export function createGithubRepoCreateAction(options: { topics?: string[]; repoVariables?: { [key: string]: string }; secrets?: { [key: string]: string }; + oidcCustomization?: { + useDefault: boolean; + includeClaimKeys?: string[]; + }; requireCommitSigning?: boolean; }>({ id: 'github:repo:create', @@ -133,6 +137,7 @@ export function createGithubRepoCreateAction(options: { topics: inputProps.topics, repoVariables: inputProps.repoVariables, secrets: inputProps.secrets, + oidcCustomization: inputProps.oidcCustomization, requiredCommitSigning: inputProps.requiredCommitSigning, }, }, @@ -165,6 +170,7 @@ export function createGithubRepoCreateAction(options: { topics, repoVariables, secrets, + oidcCustomization, token: providedToken, } = ctx.input; @@ -204,6 +210,7 @@ export function createGithubRepoCreateAction(options: { topics, repoVariables, secrets, + oidcCustomization, ctx.logger, ); diff --git a/plugins/scaffolder-backend-module-github/src/actions/helpers.ts b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts index 4d95a6494f..ec282c74d9 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/helpers.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts @@ -137,6 +137,12 @@ export async function createGithubRepoWithCollaboratorsAndTopics( topics: string[] | undefined, repoVariables: { [key: string]: string } | undefined, secrets: { [key: string]: string } | undefined, + oidcCustomization: + | { + useDefault: boolean; + includeClaimKeys?: string[]; + } + | undefined, logger: Logger, ) { // eslint-disable-next-line testing-library/no-await-sync-queries @@ -304,6 +310,18 @@ export async function createGithubRepoWithCollaboratorsAndTopics( } } + if (oidcCustomization) { + await client.request( + 'PUT /repos/{owner}/{repo}/actions/oidc/customization/sub', + { + owner, + repo, + use_default: oidcCustomization.useDefault, + include_claim_keys: oidcCustomization.includeClaimKeys, + }, + ); + } + return newRepo; } diff --git a/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts b/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts index 96e1f3b6e1..585526fe94 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts @@ -277,6 +277,28 @@ const secrets = { type: 'object', }; +const oidcCustomization = { + title: 'Repository OIDC customization template', + description: `OIDC customization template attached to the repository.`, + type: 'object', + additionalProperties: false, + properties: { + useDefault: { + title: 'Use Default', + type: 'boolean', + description: `Whether to use the default OIDC template or not.`, + }, + includeClaimKeys: { + title: 'Include claim keys', + type: 'array', + items: { + type: 'string', + }, + description: `Array of unique strings. Each claim key can only contain alphanumeric characters and underscores.`, + }, + }, +}; + export { access }; export { allowMergeCommit }; export { allowRebaseMerge }; @@ -313,3 +335,4 @@ export { topics }; export { requiredCommitSigning }; export { repoVariables }; export { secrets }; +export { oidcCustomization }; diff --git a/plugins/scaffolder-backend-module-rails/Rails.dockerfile b/plugins/scaffolder-backend-module-rails/Rails.dockerfile index aa9ccf19f3..8ea3fc370a 100644 --- a/plugins/scaffolder-backend-module-rails/Rails.dockerfile +++ b/plugins/scaffolder-backend-module-rails/Rails.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3@sha256:24af4f0bf0af61d04a5ead4f43e7ad468a1b2ff05844d7780555a13a78615ced +FROM ruby:3.3 RUN apt-get update -qq && \ apt-get install -y nodejs postgresql-client git && \ diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 9026761a7c..858591749c 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -64,6 +64,7 @@ "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "workspace:^", "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "workspace:^", "@backstage/plugin-scaffolder-backend-module-gerrit": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-gitea": "workspace:^", "@backstage/plugin-scaffolder-backend-module-github": "workspace:^", "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", diff --git a/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile b/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile index 33c6ad3788..6aa3c0dfa0 100644 --- a/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile +++ b/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.18@sha256:11e21d7b981a59554b3f822c49f6e9f57b6068bb74f49c4cd5cc4c663c7e5160 +FROM alpine:3.18 RUN apk add --update \ git \ @@ -8,4 +8,4 @@ RUN apk add --update \ g++ && \ pip install cookiecutter && \ apk del g++ py-pip python-dev && \ - rm -rf /var/cache/apk/* + rm -rf /var/cache/apk/* diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index f9c15597a8..2ee0a7644f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -81,6 +81,8 @@ import { createPublishGitlabMergeRequestAction, } from '@backstage/plugin-scaffolder-backend-module-gitlab'; +import { createPublishGiteaAction } from '@backstage/plugin-scaffolder-backend-module-gitea'; + /** * The options passed to {@link createBuiltinActions} * @public @@ -158,6 +160,10 @@ export const createBuiltinActions = ( integrations, config, }), + createPublishGiteaAction({ + integrations, + config, + }), createPublishGithubAction({ integrations, config, diff --git a/plugins/scaffolder-node/src/actions/util.ts b/plugins/scaffolder-node/src/actions/util.ts index 327cfa9c2f..7f7121ef16 100644 --- a/plugins/scaffolder-node/src/actions/util.ts +++ b/plugins/scaffolder-node/src/actions/util.ts @@ -92,6 +92,10 @@ export const parseRepoUrl = ( } break; } + case 'gitea': { + checkRequiredParams(parsed, 'repo'); + break; + } case 'gerrit': { checkRequiredParams(parsed, 'repo'); break; diff --git a/plugins/scaffolder-react/knip-report.md b/plugins/scaffolder-react/knip-report.md index 3d42235f5e..3c2e8f3c3c 100644 --- a/plugins/scaffolder-react/knip-report.md +++ b/plugins/scaffolder-react/knip-report.md @@ -1,12 +1,11 @@ # Knip report -## Unused dependencies (4) +## Unused dependencies (3) | Name | Location | Severity | | :------------------------ | :----------- | :------- | | @backstage/catalog-client | package.json | error | | zod-to-json-schema | package.json | error | -| immer | package.json | error | | zod | package.json | error | ## Unused devDependencies (2) diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 0263efd4f4..94b6b044dc 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -68,7 +68,6 @@ "classnames": "^2.2.6", "flatted": "3.2.9", "humanize-duration": "^3.25.1", - "immer": "^9.0.1", "json-schema": "^0.4.0", "json-schema-library": "^7.3.9", "lodash": "^4.17.21", diff --git a/plugins/scaffolder/knip-report.md b/plugins/scaffolder/knip-report.md index d130aaeb40..6004665f89 100644 --- a/plugins/scaffolder/knip-report.md +++ b/plugins/scaffolder/knip-report.md @@ -1,13 +1,12 @@ # Knip report -## Unused dependencies (4) +## Unused dependencies (3) | Name | Location | Severity | | :------------------ | :----------- | :------- | | json-schema-library | package.json | error | | @rjsf/material-ui | package.json | error | | git-url-parse | package.json | error | -| immer | package.json | error | ## Unused devDependencies (1) diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index c93de86cc9..3acc3270aa 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -78,7 +78,6 @@ "event-source-polyfill": "^1.0.31", "git-url-parse": "^14.0.0", "humanize-duration": "^3.25.1", - "immer": "^9.0.1", "json-schema": "^0.4.0", "json-schema-library": "^7.3.9", "jszip": "^3.10.1", diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 42453e2080..e59970f4f7 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -11756,8 +11756,8 @@ __metadata: linkType: hard "webpack@npm:^5.73.0": - version: 5.90.1 - resolution: "webpack@npm:5.90.1" + version: 5.90.2 + resolution: "webpack@npm:5.90.2" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^1.0.5 @@ -11788,7 +11788,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: a7be844d5720a0c6282fec012e6fa34b1137dff953c5d48bf2ef066a6c27c1dbc92a9b9effc05ee61c9fe269499266db9782073f2d82a589d3c5c966ffc56584 + checksum: 4af55f314c3610e0b17afd01960c4cf9d8d90c87a58ef7d7dc7a0a019f48e2bba4eff63b02d9da56fc61df5b04af0d66b3fa4ec82937a780d37a64db84c643fe languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index f69b3e5851..cd5f483ddc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -363,24 +363,24 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-cognito-identity@npm:3.514.0": - version: 3.514.0 - resolution: "@aws-sdk/client-cognito-identity@npm:3.514.0" +"@aws-sdk/client-cognito-identity@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/client-cognito-identity@npm:3.515.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.513.0 + "@aws-sdk/client-sts": 3.515.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/credential-provider-node": 3.514.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/credential-provider-node": 3.515.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 "@smithy/fetch-http-handler": ^2.4.1 @@ -407,28 +407,28 @@ __metadata: "@smithy/util-retry": ^2.1.1 "@smithy/util-utf8": ^2.1.1 tslib: ^2.5.0 - checksum: 38629787a3dbbaf7edad47c7e76c3b5015b20c7e9e8cbb343f5050f3c7bd31920e22e45e1ccbf21fe9fe331dc8f307420e5da6b5c5f0d26e1ee77e6a5dddd86a + checksum: e254357719b355a7c6cdd718c3896aca9971ea9479887c221841ec2c6e91f15b880f6a5d1ebfc62af223b4d02a0d4a882aa8394b436f9b544658ee87a481e1ac languageName: node linkType: hard "@aws-sdk/client-eks@npm:^3.350.0": - version: 3.514.0 - resolution: "@aws-sdk/client-eks@npm:3.514.0" + version: 3.515.0 + resolution: "@aws-sdk/client-eks@npm:3.515.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.513.0 + "@aws-sdk/client-sts": 3.515.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/credential-provider-node": 3.514.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/credential-provider-node": 3.515.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 "@smithy/fetch-http-handler": ^2.4.1 @@ -456,29 +456,29 @@ __metadata: "@smithy/util-utf8": ^2.1.1 "@smithy/util-waiter": ^2.1.1 tslib: ^2.5.0 - uuid: ^8.3.2 - checksum: 83ba19700e9c00c2035239c9fca710177d67eb7ee568ddafe256b40ca4724d0a1de4426c3bc5b9c66ba365206351eaf931ec4988b8dd44e17a42f8afdf84b0e3 + uuid: ^9.0.1 + checksum: 38366b504f5cda083637801b8a89cb03fb05fca56e6266a18d4fa4772a5556a461efcb82c8ed9690d8ba4c49e2ec2bdd71c7d3f987d2e7a85506439de2199ff6 languageName: node linkType: hard "@aws-sdk/client-organizations@npm:^3.350.0": - version: 3.514.0 - resolution: "@aws-sdk/client-organizations@npm:3.514.0" + version: 3.515.0 + resolution: "@aws-sdk/client-organizations@npm:3.515.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.513.0 + "@aws-sdk/client-sts": 3.515.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/credential-provider-node": 3.514.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/credential-provider-node": 3.515.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 "@smithy/fetch-http-handler": ^2.4.1 @@ -505,37 +505,37 @@ __metadata: "@smithy/util-retry": ^2.1.1 "@smithy/util-utf8": ^2.1.1 tslib: ^2.5.0 - checksum: bf8e4b074eb061b76307c116b0d328de48473d0b52c338b8d179f6e710fd7c387001ef1c3dde6278c70963711e55e6b13579407e17c78222ea51dec378b8eca4 + checksum: 4b947f1fc5ca196b007855cc5d75accb82825adfe4dea370d181b9605bfe827ddc0f6cb073d7ef7f768a523be4e393a2dc1e28a999d118bda050f354997e8f60 languageName: node linkType: hard "@aws-sdk/client-s3@npm:^3.350.0": - version: 3.514.0 - resolution: "@aws-sdk/client-s3@npm:3.514.0" + version: 3.515.0 + resolution: "@aws-sdk/client-s3@npm:3.515.0" dependencies: "@aws-crypto/sha1-browser": 3.0.0 "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.513.0 + "@aws-sdk/client-sts": 3.515.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/credential-provider-node": 3.514.0 - "@aws-sdk/middleware-bucket-endpoint": 3.511.0 - "@aws-sdk/middleware-expect-continue": 3.511.0 - "@aws-sdk/middleware-flexible-checksums": 3.511.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-location-constraint": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-sdk-s3": 3.511.0 - "@aws-sdk/middleware-signing": 3.511.0 - "@aws-sdk/middleware-ssec": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/signature-v4-multi-region": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/credential-provider-node": 3.515.0 + "@aws-sdk/middleware-bucket-endpoint": 3.515.0 + "@aws-sdk/middleware-expect-continue": 3.515.0 + "@aws-sdk/middleware-flexible-checksums": 3.515.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-location-constraint": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-sdk-s3": 3.515.0 + "@aws-sdk/middleware-signing": 3.515.0 + "@aws-sdk/middleware-ssec": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/signature-v4-multi-region": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@aws-sdk/xml-builder": 3.496.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 @@ -571,29 +571,29 @@ __metadata: "@smithy/util-waiter": ^2.1.1 fast-xml-parser: 4.2.5 tslib: ^2.5.0 - checksum: 2a5b1da2343825c9e44d764d63e0be800dee5a51b26804daa6a57de12c6d9514a49a3673804a303f45d3a66d657ef8518ed186ceb205738e1794a81c224dc2be + checksum: f61f91fb45500108520357e61a018975f4e4a49df378fa16ad0fc15b59560bdfcc11c6cb7d95ad1c4b6e0607e99788662e4013d8d529af75a36dffa5c8bfe5ca languageName: node linkType: hard "@aws-sdk/client-sqs@npm:^3.350.0": - version: 3.514.0 - resolution: "@aws-sdk/client-sqs@npm:3.514.0" + version: 3.515.0 + resolution: "@aws-sdk/client-sqs@npm:3.515.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.513.0 + "@aws-sdk/client-sts": 3.515.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/credential-provider-node": 3.514.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-sdk-sqs": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/credential-provider-node": 3.515.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-sdk-sqs": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 "@smithy/fetch-http-handler": ^2.4.1 @@ -621,27 +621,27 @@ __metadata: "@smithy/util-retry": ^2.1.1 "@smithy/util-utf8": ^2.1.1 tslib: ^2.5.0 - checksum: b1ab3853441f3a2e9235e3a8594b9c2496c777331da12c82ade6ce267c7839c6fa60a7e9c1c23a7ad55fca357d7c1a47c1b3b6a1512312f65a02908537be7eb9 + checksum: e92bbea7c7453cee74898ffde1092437693eb19b3a623243913805229ab6b1ec7905735a2dd58476915d574beeca2675f00eb89b5de8c3f099becc68c9ade901 languageName: node linkType: hard -"@aws-sdk/client-sso-oidc@npm:3.513.0": - version: 3.513.0 - resolution: "@aws-sdk/client-sso-oidc@npm:3.513.0" +"@aws-sdk/client-sso-oidc@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/client-sso-oidc@npm:3.515.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.513.0 + "@aws-sdk/client-sts": 3.515.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 "@smithy/fetch-http-handler": ^2.4.1 @@ -669,27 +669,27 @@ __metadata: "@smithy/util-utf8": ^2.1.1 tslib: ^2.5.0 peerDependencies: - "@aws-sdk/credential-provider-node": ^3.513.0 - checksum: 655dbe99fde0d9413eb0c8f2c91815931ecc27eb00d470773acf968b3ceebb007bb8cffebe1261a6dc7af1ebf0a8a2d5d00060d02bf3e3be09f97bf71a4ce284 + "@aws-sdk/credential-provider-node": ^3.515.0 + checksum: f220a9ba8542460b2aa91ad060302fb9e68bdf096ecca2ec1d6e525f4df1036b330cb85d20bac3e8399276c0d8d8d388b3f2191b58804919c68369afac0be37b languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.513.0": - version: 3.513.0 - resolution: "@aws-sdk/client-sso@npm:3.513.0" +"@aws-sdk/client-sso@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/client-sso@npm:3.515.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 "@smithy/fetch-http-handler": ^2.4.1 @@ -716,26 +716,26 @@ __metadata: "@smithy/util-retry": ^2.1.1 "@smithy/util-utf8": ^2.1.1 tslib: ^2.5.0 - checksum: 1c5a0465de54cb03e6fe7b1d5543638184227c2019a0eeb4537a42b6da0a9ef698abca25bb967b9fcdd3258ac73dfe0c8e120d96d10994ab9131b28533d0fb1f + checksum: 12287dfa469fb2c6b5bedd3cbd37f7416f8234669b5ed0ff38cb1217d746ba6a5e6ff227b091a7751d1c20489a6b8bd93bcbed8f394cb4c51b6bebb9a9f79108 languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.513.0, @aws-sdk/client-sts@npm:^3.350.0": - version: 3.513.0 - resolution: "@aws-sdk/client-sts@npm:3.513.0" +"@aws-sdk/client-sts@npm:3.515.0, @aws-sdk/client-sts@npm:^3.350.0": + version: 3.515.0 + resolution: "@aws-sdk/client-sts@npm:3.515.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 "@aws-sdk/core": 3.513.0 - "@aws-sdk/middleware-host-header": 3.511.0 - "@aws-sdk/middleware-logger": 3.511.0 - "@aws-sdk/middleware-recursion-detection": 3.511.0 - "@aws-sdk/middleware-user-agent": 3.511.0 - "@aws-sdk/region-config-resolver": 3.511.0 - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 - "@aws-sdk/util-user-agent-browser": 3.511.0 - "@aws-sdk/util-user-agent-node": 3.511.0 + "@aws-sdk/middleware-host-header": 3.515.0 + "@aws-sdk/middleware-logger": 3.515.0 + "@aws-sdk/middleware-recursion-detection": 3.515.0 + "@aws-sdk/middleware-user-agent": 3.515.0 + "@aws-sdk/region-config-resolver": 3.515.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 + "@aws-sdk/util-user-agent-browser": 3.515.0 + "@aws-sdk/util-user-agent-node": 3.515.0 "@smithy/config-resolver": ^2.1.1 "@smithy/core": ^1.3.2 "@smithy/fetch-http-handler": ^2.4.1 @@ -764,8 +764,8 @@ __metadata: fast-xml-parser: 4.2.5 tslib: ^2.5.0 peerDependencies: - "@aws-sdk/credential-provider-node": ^3.513.0 - checksum: 4e89fd8f4aef57a777aff20e1afd5c502595c03ba1e21ece5940ea1b2d422c41e8bde83071ba42b96a8bfa4520197375e7f5e98a808c24c96673fc95fa4cdb3f + "@aws-sdk/credential-provider-node": ^3.515.0 + checksum: 9af6a2484909e88a83c411551d55ad149c80a8f449c2e54c499769535243602a6283cd71f6a0cf975b295a321a74e90eb95f6659bba93bae3d12e2186e7545f4 languageName: node linkType: hard @@ -783,36 +783,36 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-cognito-identity@npm:3.514.0": - version: 3.514.0 - resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.514.0" +"@aws-sdk/credential-provider-cognito-identity@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.515.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.514.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/client-cognito-identity": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/property-provider": ^2.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: 2a13f19f7f5161f388d6a63fd3b6d5e666ba5b39e40d9a3f935aded9dbec423e0d89f2da8920212e2b1e63dfab690187a45e00bdb3e5c109dc7a2a156de2d066 + checksum: cb8cb5fa19b3e10e0a816eddda0a56a412da6bc68eba4807698ed94ef6bf2f3de288d959ced099b399dfc29f08154c84f8c025816e94226e5fb21c605e710542 languageName: node linkType: hard -"@aws-sdk/credential-provider-env@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/credential-provider-env@npm:3.511.0" +"@aws-sdk/credential-provider-env@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/property-provider": ^2.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: c19f98e0a59324cb9cd59220c91ed41ee6ee507de9acdb233f1a280db14491883c24d711d6a496f03d15b9301496ab561dba8d78dfdac5477c43c9d0bb2fcced + checksum: 3573bc3f1aa89bc8eedb9eb39c8c1d501a68aec5eb059364a1091c8bf10dfda9cfbd78ee49d3ad25ec1012f765a4464363c4cd70997e94005fd21245871a4229 languageName: node linkType: hard -"@aws-sdk/credential-provider-http@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/credential-provider-http@npm:3.511.0" +"@aws-sdk/credential-provider-http@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-http@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/fetch-http-handler": ^2.4.1 "@smithy/node-http-handler": ^2.3.1 "@smithy/property-provider": ^2.1.1 @@ -821,111 +821,111 @@ __metadata: "@smithy/types": ^2.9.1 "@smithy/util-stream": ^2.1.1 tslib: ^2.5.0 - checksum: d6dc32a2e1cab7ff6b603aa087b80ec854064a9f490210d8d50db2b68f4586b7cfc78de71d6ae1e21788e8e171c6ee2c4c1fa6876ce59bab018abfd9cab13b2a + checksum: d13943dc7a83c9c129dd03a8b337b7753c791441d65a894085e00146d807738b420b9127f570a32497665be4f6e1cc8eeefd7cb1b013a04789d874c8b23b829f languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.513.0": - version: 3.513.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.513.0" +"@aws-sdk/credential-provider-ini@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.515.0" dependencies: - "@aws-sdk/client-sts": 3.513.0 - "@aws-sdk/credential-provider-env": 3.511.0 - "@aws-sdk/credential-provider-process": 3.511.0 - "@aws-sdk/credential-provider-sso": 3.513.0 - "@aws-sdk/credential-provider-web-identity": 3.513.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/client-sts": 3.515.0 + "@aws-sdk/credential-provider-env": 3.515.0 + "@aws-sdk/credential-provider-process": 3.515.0 + "@aws-sdk/credential-provider-sso": 3.515.0 + "@aws-sdk/credential-provider-web-identity": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/credential-provider-imds": ^2.2.1 "@smithy/property-provider": ^2.1.1 "@smithy/shared-ini-file-loader": ^2.3.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: d4e9f0486f44ca7271f8e245b9db483cc32a5b7600dc4de586fcbacf050a3b67c083c1bb9c86408a91ff1c46fd1b6c6428f592ca8d7537293c09f2359946039a + checksum: c136d4257460be8331d7645854b7e3c91205a1eb12efd3dcbcd84501c787085292d1ccc4578c4776308d91748bde5af2c6eaa873b56aed83ab472a878a2d8883 languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.514.0, @aws-sdk/credential-provider-node@npm:^3.350.0": - version: 3.514.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.514.0" +"@aws-sdk/credential-provider-node@npm:3.515.0, @aws-sdk/credential-provider-node@npm:^3.350.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.515.0" dependencies: - "@aws-sdk/credential-provider-env": 3.511.0 - "@aws-sdk/credential-provider-http": 3.511.0 - "@aws-sdk/credential-provider-ini": 3.513.0 - "@aws-sdk/credential-provider-process": 3.511.0 - "@aws-sdk/credential-provider-sso": 3.513.0 - "@aws-sdk/credential-provider-web-identity": 3.513.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/credential-provider-env": 3.515.0 + "@aws-sdk/credential-provider-http": 3.515.0 + "@aws-sdk/credential-provider-ini": 3.515.0 + "@aws-sdk/credential-provider-process": 3.515.0 + "@aws-sdk/credential-provider-sso": 3.515.0 + "@aws-sdk/credential-provider-web-identity": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/credential-provider-imds": ^2.2.1 "@smithy/property-provider": ^2.1.1 "@smithy/shared-ini-file-loader": ^2.3.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: ceeded87585fde1093dac1a84ffa0c0d1377f844508431b06877529de40625d2b67ad23269a7ac32e0cac3338a7051a23c51095eb22cea359b80d3ac72a34b81 + checksum: c51f267c61de0d82afe47d97cdf58971e3b8eec6e7364fe28d3867addd65e156358b96c39a335fad521e9a6925b349a967ae3eed1aa6e9cb4bcc1f0931e3ed50 languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.511.0" +"@aws-sdk/credential-provider-process@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/property-provider": ^2.1.1 "@smithy/shared-ini-file-loader": ^2.3.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: ec3be8da713542d61c40d38fb83d067115d0e54e9847ebe7291ed17aa67bbae731e9b2e54cf833bdc75b1b171e663bbbb005308e69634dc4a88926887c78881b + checksum: 11159b4c9502218ec6cba9a46ddc120e53aec7f04507c14d4e99a186073cfd363af438c623705890a2e8f6cc792475ebd14c82766dad82dabf7f20d9708f7faf languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.513.0": - version: 3.513.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.513.0" +"@aws-sdk/credential-provider-sso@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.515.0" dependencies: - "@aws-sdk/client-sso": 3.513.0 - "@aws-sdk/token-providers": 3.513.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/client-sso": 3.515.0 + "@aws-sdk/token-providers": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/property-provider": ^2.1.1 "@smithy/shared-ini-file-loader": ^2.3.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: eafa07c7502136dbed7b4308d921fec87f381fbc2c27c1d4ba8d34d902e3a4ef6b95713a6fa7be2fe82fa68fdf06e5dbcd971b4d55c66c7b2d3c4a36a58fd2cc + checksum: fbe1eebc50e9bd3715bca4e6ee1a2922cf1ea383953730a6bd3b88b12f23a95cb3ff0edaf8578c81156ef65648eb0295f5c39ed6ae2c8e16b6ce9d4c46f207e9 languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:3.513.0": - version: 3.513.0 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.513.0" +"@aws-sdk/credential-provider-web-identity@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.515.0" dependencies: - "@aws-sdk/client-sts": 3.513.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/client-sts": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/property-provider": ^2.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: 2a885d53f6a3b4a3f461095af3be0e4c7f48b93a21619f97e2ac076f43cabcf703e6cb5f57f594d7288b63dc5dec12a2096ae6c93993f82fdfee5f3227307c63 + checksum: f0a7e9855f78849143c3139c613cc1531a88272f3ec039d23ac9366b94495a3e07212ade9541e56c93560ad9f58600376e9de38706a4cd97aaf5f400911361cd languageName: node linkType: hard "@aws-sdk/credential-providers@npm:^3.350.0": - version: 3.514.0 - resolution: "@aws-sdk/credential-providers@npm:3.514.0" + version: 3.515.0 + resolution: "@aws-sdk/credential-providers@npm:3.515.0" dependencies: - "@aws-sdk/client-cognito-identity": 3.514.0 - "@aws-sdk/client-sso": 3.513.0 - "@aws-sdk/client-sts": 3.513.0 - "@aws-sdk/credential-provider-cognito-identity": 3.514.0 - "@aws-sdk/credential-provider-env": 3.511.0 - "@aws-sdk/credential-provider-http": 3.511.0 - "@aws-sdk/credential-provider-ini": 3.513.0 - "@aws-sdk/credential-provider-node": 3.514.0 - "@aws-sdk/credential-provider-process": 3.511.0 - "@aws-sdk/credential-provider-sso": 3.513.0 - "@aws-sdk/credential-provider-web-identity": 3.513.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/client-cognito-identity": 3.515.0 + "@aws-sdk/client-sso": 3.515.0 + "@aws-sdk/client-sts": 3.515.0 + "@aws-sdk/credential-provider-cognito-identity": 3.515.0 + "@aws-sdk/credential-provider-env": 3.515.0 + "@aws-sdk/credential-provider-http": 3.515.0 + "@aws-sdk/credential-provider-ini": 3.515.0 + "@aws-sdk/credential-provider-node": 3.515.0 + "@aws-sdk/credential-provider-process": 3.515.0 + "@aws-sdk/credential-provider-sso": 3.515.0 + "@aws-sdk/credential-provider-web-identity": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/credential-provider-imds": ^2.2.1 "@smithy/property-provider": ^2.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: 87468c93d84406a3cebb1df81311b5fd16ee93331c353991657423da90c960b1e3d4d033274efb81090c814dfff83064eec693abd4e6fba878961832b033b8d7 + checksum: 8890e83fc19072c51cee8d50ee7168800b9775aa00bcb7a0feb836e60fbae0fb8ba55133d256719033cd7ccda0f5881350474ba3f4769016f01ce7de4ef7b6e5 languageName: node linkType: hard @@ -951,8 +951,8 @@ __metadata: linkType: hard "@aws-sdk/lib-storage@npm:^3.350.0": - version: 3.514.0 - resolution: "@aws-sdk/lib-storage@npm:3.514.0" + version: 3.515.0 + resolution: "@aws-sdk/lib-storage@npm:3.515.0" dependencies: "@smithy/abort-controller": ^2.1.1 "@smithy/middleware-endpoint": ^2.4.1 @@ -963,22 +963,22 @@ __metadata: tslib: ^2.5.0 peerDependencies: "@aws-sdk/client-s3": ^3.0.0 - checksum: 1a122a966bd2e7c627a1a69ef6d8c441ca6f439a503d95cc58cca3f0333bc3d2f2c9fd715b4a6abb009a868240c8a1e33607002b7f6abe89e1d5c26fc3823842 + checksum: b4d7b3783508ce3ef93150b2a249490c5af803d02d91ce81aebf0ec055870aae3260d4d66e9bf1d4234fb61d11cfaa54f2916c9c2572cf4cb6ee1b15993c41b5 languageName: node linkType: hard -"@aws-sdk/middleware-bucket-endpoint@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.511.0" +"@aws-sdk/middleware-bucket-endpoint@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@aws-sdk/util-arn-parser": 3.495.0 "@smithy/node-config-provider": ^2.2.1 "@smithy/protocol-http": ^3.1.1 "@smithy/types": ^2.9.1 "@smithy/util-config-provider": ^2.2.1 tslib: ^2.5.0 - checksum: 23272bf6b5a6a7e8ae97bf2ad896487b670a1db766a2704606eb1fd852a273d99fb468bf3f7f3dddc6df7cdf5812a2195f842f949add6bc272fb90ac80241217 + checksum: 8ecec09ac50c33a24178e73be6b4238e5047984eebf54c4786392e82d2b1cdd09807ee97104f603d22890a58657335843f9587c66e544c2ffbb9a25f3e3bf065 languageName: node linkType: hard @@ -995,85 +995,85 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-expect-continue@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-expect-continue@npm:3.511.0" +"@aws-sdk/middleware-expect-continue@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-expect-continue@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/protocol-http": ^3.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: be66cd2cecff5ba6bb9cc1a3368f2f488b28d415e9122bded2d1810a57014860d63a91ef64c9edab854fe67f339d75a1ee84c6d5f6de9e534ec4ea708871ea90 + checksum: c989e0e55f51c631f914b444a0e3a6a81c79c1ad8046346c16a4ccfbb77aeaf48ba948a6b8185fc36c00abf07951cc374c3673da6d23d7de6cd3ec8d5b4d840e languageName: node linkType: hard -"@aws-sdk/middleware-flexible-checksums@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.511.0" +"@aws-sdk/middleware-flexible-checksums@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.515.0" dependencies: "@aws-crypto/crc32": 3.0.0 "@aws-crypto/crc32c": 3.0.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/is-array-buffer": ^2.1.1 "@smithy/protocol-http": ^3.1.1 "@smithy/types": ^2.9.1 "@smithy/util-utf8": ^2.1.1 tslib: ^2.5.0 - checksum: 5d95e405b5584c5fcc4c88f5ed7f49a85c95263d13a0859e167eda43ba3171233f38280430e42cc40baa923d64f02af36e442e7f374600ac8153ddfd7ba96853 + checksum: 89f2df7a3dd40c174586aec1349e4e144825cffb252df843b115390702523dc6cfb745756a69a1ab1e77e44340fd55bed04be3856fe96d937af5702bcbcf869b languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.511.0" +"@aws-sdk/middleware-host-header@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/protocol-http": ^3.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: 4cdbe0959d17c32928025e5f57b56ce35e6a94bf907be5ef00e1b564735528a585749b95f0c91d9281275275e9e77a82ad946b1daeb0a320ea767bb602cd0d61 + checksum: ff066cf47b0ba2c64bd70efdec795ac2da8bad7ba8dd44913c98f42b153ca6e753b13b6c1ef7075499590279a5cc49b5a60511dae4512dcdb11a62a0e67fa061 languageName: node linkType: hard -"@aws-sdk/middleware-location-constraint@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-location-constraint@npm:3.511.0" +"@aws-sdk/middleware-location-constraint@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-location-constraint@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: 2749c882354da4a37cf800d98f2ad14ba128d974c05875e4e6639d4eed731f36bd437bb622ab1d8c3ffc58af7c7b18035fd08e82044c9e5910765aae5cf0db09 + checksum: c3e7c7b51c276eba7ceef05c18416d2cca976c83ac9db227877090c33f676b50b0c90ceaf5d924cd9894a4c2f44c0a2d06ec93da753ac646fecb68d5facef570 languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-logger@npm:3.511.0" +"@aws-sdk/middleware-logger@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-logger@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: bcbd5486d63a7ffe0ea4131cff646be728b2f1d862231c133fdc6f67a3f39aafa9c09c059e2cb2c6720d569a3c0d9926e0acb61ccd505acdc48e3b34e706f60b + checksum: 32d251e77f43593ffdd192a4d0628f33773e29c14a3001a4c6519553e94958edbd0fb8e6954a65d1180b0caa16cafe9fc9b362d1ab663db1d1eac84b15667645 languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.511.0" +"@aws-sdk/middleware-recursion-detection@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/protocol-http": ^3.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: a9e1d7924115f07986b726c2f2bd1705227bf5660c3ff9fc356866600f2336cc0ecea5cf53cca7c48a9856216363774cecf64fa9bbe954e71cd5605fcb6d57b3 + checksum: 23c4a1e4d7de86196acfcfbc84bea84c8c3211c4831fdc7c975a6388022037bd5baa4e5809dca188631f06726b51fcf85af358f9ef526e255dc494b368d0da0c languageName: node linkType: hard -"@aws-sdk/middleware-sdk-s3@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-sdk-s3@npm:3.511.0" +"@aws-sdk/middleware-sdk-s3@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-sdk-s3@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@aws-sdk/util-arn-parser": 3.495.0 "@smithy/node-config-provider": ^2.2.1 "@smithy/protocol-http": ^3.1.1 @@ -1082,21 +1082,21 @@ __metadata: "@smithy/types": ^2.9.1 "@smithy/util-config-provider": ^2.2.1 tslib: ^2.5.0 - checksum: 1e9bad58136131aaaac326fa2d05d192ef762217a85e0bc831801b45ed15089ef763c2b5d57f28d0b2dc87d2aca02d894a3570c6e85dd2677d0a78e663fd4f15 + checksum: cb67334b30eee8fcf52637407cab2787353e463bdf5a99a33966f0e765f6f8fc687c4bba2b63ec7a4374b2ab544be807e1849bd910e6f163ff43d036f026e7e1 languageName: node linkType: hard -"@aws-sdk/middleware-sdk-sqs@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.511.0" +"@aws-sdk/middleware-sdk-sqs@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/smithy-client": ^2.3.1 "@smithy/types": ^2.9.1 "@smithy/util-hex-encoding": ^2.1.1 "@smithy/util-utf8": ^2.1.1 tslib: ^2.5.0 - checksum: 2b8593c20a40beafc88c03bd75fcf8cecd00ad68ed42f26e64c61a2006a622085764b29b6d05191ea5417a18d3503c455008482faaa4873e4e5404a0ac71e84d + checksum: 67a7d9ed3e975a3fd83266f18ce2d94e3dc457d7001af7031e732b2d96135678dd3323ecae56ffe214f3dbe23d1df295a0cd0d21df7f6b9c98699e6a9b4704ca languageName: node linkType: hard @@ -1110,42 +1110,42 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-signing@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-signing@npm:3.511.0" +"@aws-sdk/middleware-signing@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-signing@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/property-provider": ^2.1.1 "@smithy/protocol-http": ^3.1.1 "@smithy/signature-v4": ^2.1.1 "@smithy/types": ^2.9.1 "@smithy/util-middleware": ^2.1.1 tslib: ^2.5.0 - checksum: 383054601027f89065948aa19ed708f9dcc190651bbb61363c0eb2f705d75e62790d2715c4fca4cf7c7e3288f9c1c9b672556799eafa36629cc26d1d42944300 + checksum: 7ee85c70a81b85e455c4411caad79c7b41a0a0fd9696feead394a31ca360b096c74f7b2b6b5d449fcfa622659305618e24a49d15c45cab3afa54503459a9b24a languageName: node linkType: hard -"@aws-sdk/middleware-ssec@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-ssec@npm:3.511.0" +"@aws-sdk/middleware-ssec@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-ssec@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: ab21772d16006e9326bd2238ea8b6013f89b35fd3c243ec9212296fefc68ddc54b91f5cde449c1a1119089a002b4c8e2278597649d69744dc015be2964df3ad7 + checksum: 3a91ebaf128ff63665f9aa69b9b2d475ebb8e519da2e94a142bcea7f9b173be52a0476b814e90e88e0936db3371e3c1c090b4e44018f006e1cfc37d2631a36d8 languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.511.0" +"@aws-sdk/middleware-user-agent@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 - "@aws-sdk/util-endpoints": 3.511.0 + "@aws-sdk/types": 3.515.0 + "@aws-sdk/util-endpoints": 3.515.0 "@smithy/protocol-http": ^3.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: 4d09ca5497e17a748f4034f5c1374cbdf8701fedbd5b3275042dccd734a4e91d52eed5e493f1526cda965ec784502efb4f25ca55874f7996d1bb442895316ef1 + checksum: fd601cb0367d42e38b71494c773d82bde8970f9aafbdbf18d7cadc25732ecc2b787f0cfef2110755d0cef73d6aa3ce2ca77dc5353854bedaf392a69019b39ac2 languageName: node linkType: hard @@ -1193,31 +1193,31 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.511.0" +"@aws-sdk/region-config-resolver@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/node-config-provider": ^2.2.1 "@smithy/types": ^2.9.1 "@smithy/util-config-provider": ^2.2.1 "@smithy/util-middleware": ^2.1.1 tslib: ^2.5.0 - checksum: a41e119d85c690e957bc00af7a6b822f2bb4c3522c3762799a40a5e0d081cbed6028607b8528b98705af4b7e5ed1a2cbc9e9d39df415597271fba7b1da7f08f5 + checksum: 0ed7fbd6390baebdf511b30877236fa8be8716e0162e2c9e0138c9b41ebda7d99a6f3d6cf66cb4af24761631c2c29102ecfe7a5f08894e1de3c98ca6a135fa74 languageName: node linkType: hard -"@aws-sdk/signature-v4-multi-region@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/signature-v4-multi-region@npm:3.511.0" +"@aws-sdk/signature-v4-multi-region@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/signature-v4-multi-region@npm:3.515.0" dependencies: - "@aws-sdk/middleware-sdk-s3": 3.511.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/middleware-sdk-s3": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/protocol-http": ^3.1.1 "@smithy/signature-v4": ^2.1.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: f1a4d3a81310e2867ac973be8bae1a04654dbd543fb9341cd963a53e378b821e5ae189da072f5ab7c86efd00192d0b8da76f54d9f612c30ad20574485c250b0c + checksum: 1f780409af431b3ac91beee294cf4af74fff9f3dffc21ddd1c8a1782a01916da162ceec27c133a9e86452279bdf0005f9118809820d557a248613cd44f0f7ec3 languageName: node linkType: hard @@ -1237,17 +1237,17 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.513.0": - version: 3.513.0 - resolution: "@aws-sdk/token-providers@npm:3.513.0" +"@aws-sdk/token-providers@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/token-providers@npm:3.515.0" dependencies: - "@aws-sdk/client-sso-oidc": 3.513.0 - "@aws-sdk/types": 3.511.0 + "@aws-sdk/client-sso-oidc": 3.515.0 + "@aws-sdk/types": 3.515.0 "@smithy/property-provider": ^2.1.1 "@smithy/shared-ini-file-loader": ^2.3.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: 6f7765e0778814f2d94b8a2489eefecc1b314813af6462cfc4f5527257ece7c1501360664500d519da0fa48312200f040f5a7560928620ff3882c65f52fabe18 + checksum: ab51c440da9772d0ee58948241b975705c171395cf1bad81a4ffd8f11f34106af54dcba930e360fb19489beedc1106ac14432bd27abdfe4b7536dc2113841027 languageName: node linkType: hard @@ -1261,13 +1261,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/types@npm:3.511.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.347.0": - version: 3.511.0 - resolution: "@aws-sdk/types@npm:3.511.0" +"@aws-sdk/types@npm:3.515.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.347.0": + version: 3.515.0 + resolution: "@aws-sdk/types@npm:3.515.0" dependencies: "@smithy/types": ^2.9.1 tslib: ^2.5.0 - checksum: a2082c64b4aabecde26010a48f8535a90c8d3e666e63f82773f8b07dadd7c1ff05d4639c60ddfb7d3533fe4ac55259e34a23995ca868c13e6d7718a1392a6eb8 + checksum: 0874f1814b58eae6e7115c3d08c2bc56e558e73d1ff8c5f833a73b4a0f76a42743c83c36a4b2759177e41b1feff065e85450f7bc235a087b94e67db12f87d298 languageName: node linkType: hard @@ -1301,15 +1301,15 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/util-endpoints@npm:3.511.0" +"@aws-sdk/util-endpoints@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/util-endpoints@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/types": ^2.9.1 "@smithy/util-endpoints": ^1.1.1 tslib: ^2.5.0 - checksum: dfd8fa98e6abeb96edc1239d1c49aef740bc781eb772a05deeb3385d576921121e3a5050f5372cce2bd422848ece728271aadb8887dce413100a289311873b3b + checksum: 1ab8fcd3054dc0366f10813a01130d05f4ba33f1488c1a168f44881cb24f3fbc2393111b7b0fd4dc06c852e4c9a5bbe8a82717b72229b0977cdba8a631ddeee1 languageName: node linkType: hard @@ -1361,23 +1361,23 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-browser@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.511.0" +"@aws-sdk/util-user-agent-browser@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/types": ^2.9.1 bowser: ^2.11.0 tslib: ^2.5.0 - checksum: 714e5bc1faab9aee8c4a2ba02faa9c3d61621d2cc789fad460b613916adf12992c0ab7144368fdfecac10f3ec2b67f5d6da01465e827fe682e2024274c2b5721 + checksum: 40f518006cb7e76d06d83dcf05222b0b0ff47c10b63149cd5db2c0c1db79c8eff34bd582e89c748897bc11697b7b357bdca77d569f57ad0b2081c088752d601f languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.511.0": - version: 3.511.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.511.0" +"@aws-sdk/util-user-agent-node@npm:3.515.0": + version: 3.515.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.515.0" dependencies: - "@aws-sdk/types": 3.511.0 + "@aws-sdk/types": 3.515.0 "@smithy/node-config-provider": ^2.2.1 "@smithy/types": ^2.9.1 tslib: ^2.5.0 @@ -1386,7 +1386,7 @@ __metadata: peerDependenciesMeta: aws-crt: optional: true - checksum: 611a71d736d82c74f3585b0dfdd77c329047bd2815fb1782188df433015525e01247ed85ffca60d5a7c618081fd7cb935814d6854a6120071b44261b12a3e740 + checksum: 4e91d9cd5bbe4aa8321417ea1bd9caf3229416ee624b7f67b5206b284a539116692412ca41d60dcb5759b841fed7d9fb570915566d1f7e620578657f89548a23 languageName: node linkType: hard @@ -3775,7 +3775,7 @@ __metadata: minimist: ^1.2.5 msw: ^1.0.0 node-fetch: ^2.6.7 - typescript-json-schema: ^0.62.0 + typescript-json-schema: ^0.63.0 yaml: ^2.0.0 zen-observable: ^0.10.0 languageName: unknown @@ -8492,6 +8492,24 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-scaffolder-backend-module-gitea@workspace:^, @backstage/plugin-scaffolder-backend-module-gitea@workspace:plugins/scaffolder-backend-module-gitea": + version: 0.0.0-use.local + resolution: "@backstage/plugin-scaffolder-backend-module-gitea@workspace:plugins/scaffolder-backend-module-gitea" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/integration": "workspace:^" + "@backstage/plugin-scaffolder-node": "workspace:^" + msw: ^1.0.0 + node-fetch: ^2.6.7 + yaml: ^2.0.0 + languageName: unknown + linkType: soft + "@backstage/plugin-scaffolder-backend-module-github@workspace:^, @backstage/plugin-scaffolder-backend-module-github@workspace:plugins/scaffolder-backend-module-github": version: 0.0.0-use.local resolution: "@backstage/plugin-scaffolder-backend-module-github@workspace:plugins/scaffolder-backend-module-github" @@ -8618,6 +8636,7 @@ __metadata: "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "workspace:^" "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "workspace:^" "@backstage/plugin-scaffolder-backend-module-gerrit": "workspace:^" + "@backstage/plugin-scaffolder-backend-module-gitea": "workspace:^" "@backstage/plugin-scaffolder-backend-module-github": "workspace:^" "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^" "@backstage/plugin-scaffolder-common": "workspace:^" @@ -8727,7 +8746,6 @@ __metadata: classnames: ^2.2.6 flatted: 3.2.9 humanize-duration: ^3.25.1 - immer: ^9.0.1 json-schema: ^0.4.0 json-schema-library: ^7.3.9 lodash: ^4.17.21 @@ -8792,7 +8810,6 @@ __metadata: event-source-polyfill: ^1.0.31 git-url-parse: ^14.0.0 humanize-duration: ^3.25.1 - immer: ^9.0.1 json-schema: ^0.4.0 json-schema-library: ^7.3.9 jszip: ^3.10.1 @@ -30477,7 +30494,7 @@ __metadata: languageName: node linkType: hard -"immer@npm:^9.0.1, immer@npm:^9.0.6, immer@npm:^9.0.7": +"immer@npm:^9.0.6, immer@npm:^9.0.7": version: 9.0.21 resolution: "immer@npm:9.0.21" checksum: 70e3c274165995352f6936695f0ef4723c52c92c92dd0e9afdfe008175af39fa28e76aafb3a2ca9d57d1fb8f796efc4dd1e1cc36f18d33fa5b74f3dfb0375432 @@ -31573,8 +31590,8 @@ __metadata: linkType: hard "isomorphic-git@npm:^1.23.0": - version: 1.25.3 - resolution: "isomorphic-git@npm:1.25.3" + version: 1.25.4 + resolution: "isomorphic-git@npm:1.25.4" dependencies: async-lock: ^1.1.0 clean-git-ref: ^2.0.1 @@ -31589,7 +31606,7 @@ __metadata: simple-get: ^4.0.1 bin: isogit: cli.cjs - checksum: 747da1bd0435898a02f8c1ba07ce66c704ea311338b66a44830a5ce1fe9a256a3ea1ec9be5baa087f88134aa686b5d0c6dc2b9338b1fd523f2869ef2480e4d4e + checksum: 86ed42b7d15db04af5a1918b7cf50153e688a2aabd5d77a6a5f2a1798bb476aef265edd3bb3d80058929d70cd0c23247074760a48720bbba9e76b044881e6d6c languageName: node linkType: hard @@ -43239,8 +43256,8 @@ __metadata: linkType: hard "swagger-ui-react@npm:^5.0.0": - version: 5.11.4 - resolution: "swagger-ui-react@npm:5.11.4" + version: 5.11.7 + resolution: "swagger-ui-react@npm:5.11.7" dependencies: "@babel/runtime-corejs3": ^7.23.9 "@braintree/sanitize-url": =7.0.0 @@ -43279,7 +43296,7 @@ __metadata: peerDependencies: react: ">=16.8.0 <19" react-dom: ">=16.8.0 <19" - checksum: 080a367c28019e20193887a6a1dc70d42c030e2b489c9099b60f4a0cb7ebc4779d0731703060f72022bc997d6e6811661f055514e1ace1454f3bc46bb8aceaa9 + checksum: b4589abe7d4cdc97fd05f8f8f8b40daee33bb4604faa1f9c513b3ef4765fc407fef37c704dbc56c5493fa5430472e8cb30921a4d4ba544372266d06ef4d1b1e6 languageName: node linkType: hard @@ -43296,14 +43313,14 @@ __metadata: linkType: hard "swr@npm:^2.0.0": - version: 2.2.4 - resolution: "swr@npm:2.2.4" + version: 2.2.5 + resolution: "swr@npm:2.2.5" dependencies: client-only: ^0.0.1 use-sync-external-store: ^1.2.0 peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 - checksum: d1398f89fd68af0e0cb6100a5769b1e17c0dbe8a778898643ad28456acda64add43344754c7d919e3f2ca82854adf86ff7d465aba25a2d555bcb669e457138f8 + checksum: c6e6a5bd254951b22e5fd0930a95c7f79b5d0657f803c41ba1542cd6376623fb70b1895049d54ddde26da63b91951ae9d62a06772f82be28c1014d421e5b7aa9 languageName: node linkType: hard @@ -44338,9 +44355,9 @@ __metadata: languageName: node linkType: hard -"typescript-json-schema@npm:^0.62.0": - version: 0.62.0 - resolution: "typescript-json-schema@npm:0.62.0" +"typescript-json-schema@npm:^0.63.0": + version: 0.63.0 + resolution: "typescript-json-schema@npm:0.63.0" dependencies: "@types/json-schema": ^7.0.9 "@types/node": ^16.9.2 @@ -44352,7 +44369,7 @@ __metadata: yargs: ^17.1.1 bin: typescript-json-schema: bin/typescript-json-schema - checksum: 0b0ba8f86456e7bd0b2d35d3c74a6cb72b168e779352398956d4f237eff011ec2a30b0ab1b3932bd5ceab99e1ea7bc6cc7158e49d49f24daeaf11771c27c7771 + checksum: 619ab7aece08e140ba9542c6378c335751dbff3994a23343d0af67786a0c1e682d532a436c1674ddb10bca3f34972ecac7ba529b66d0e9b3e00ca81defb3aa77 languageName: node linkType: hard @@ -44492,11 +44509,11 @@ __metadata: linkType: hard "undici@npm:^5.24.0": - version: 5.26.3 - resolution: "undici@npm:5.26.3" + version: 5.28.3 + resolution: "undici@npm:5.28.3" dependencies: "@fastify/busboy": ^2.0.0 - checksum: aaa9aadb712cf80e1a9cea2377e4842670105e00abbc184a21770ea5a8b77e4e2eadc200eac62442e74a1cd3b16a840c6f73b112b9e886bd3c1a125eb22e4f21 + checksum: fa1e65aff896c5e2ee23637b632e306f9e3a2b32a3dc0b23ea71e5555ad350bcc25713aea894b3dccc0b7dc2c5e92a5a58435ebc2033b731a5524506f573dfd2 languageName: node linkType: hard @@ -45071,7 +45088,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^9.0.0": +"uuid@npm:^9.0.0, uuid@npm:^9.0.1": version: 9.0.1 resolution: "uuid@npm:9.0.1" bin: @@ -45678,8 +45695,8 @@ __metadata: linkType: hard "webpack@npm:^5, webpack@npm:^5.70.0": - version: 5.90.1 - resolution: "webpack@npm:5.90.1" + version: 5.90.2 + resolution: "webpack@npm:5.90.2" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^1.0.5 @@ -45710,7 +45727,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: a7be844d5720a0c6282fec012e6fa34b1137dff953c5d48bf2ef066a6c27c1dbc92a9b9effc05ee61c9fe269499266db9782073f2d82a589d3c5c966ffc56584 + checksum: 4af55f314c3610e0b17afd01960c4cf9d8d90c87a58ef7d7dc7a0a019f48e2bba4eff63b02d9da56fc61df5b04af0d66b3fa4ec82937a780d37a64db84c643fe languageName: node linkType: hard